2009-08-10 59 views
7

named_scope内假设我有一个名为范围:检查模型实例落在铁轨

class Foo < ActiveRecord::Base 
    named_scope :bar, :conditions => 'some_field = 1' 
end 

这个伟大的工程查询和我有一大堆的定义有用named_scopes的。我希望能够做到这一点:

f = Foo.find(:first) 
f.some_field = 1 
f.is_bar? #=> true 

'.bar?'方法将简单地返回true或false,如果模型实例在命名范围内。无论如何不写'is_bar?'就可以做到这一点方法,即使我已经写了一个很好的方法来检查是否有'is_bar?'如果我没有记错,DRY很好,所以任何帮助将不胜感激/

回答

20

您可以在命名作用域上调用exists?方法,它将查询数据库以查看给定记录是否存在这些条件。

Foo.bar.exists?(f) 

但是,如果你已经改变了f属性,它不保存到数据库中这是行不通的。这是因为命名范围条件是SQL,所以检查必须在那里进行。试图转换为Ruby if的条件很混乱,特别是在更复杂的情况下。

+0

谢谢。好吧,假装我改变了值后调用了.save。 Foo.bar.exists?(Foo.find(:first))将返回true或false,取决于它是否在bar范围内?真棒。 – user94154 2009-08-10 16:46:51

+0

正确。你不应该再次调用Find。 “f.save; Foo.bar.exists?(f)”应该工作。 – ryanb 2009-08-10 16:47:57

+4

自2009年以来,这变得更容易了吗? – 2014-12-04 18:49:21

1

如果你的范围很简单,你可能想避免代码重复。我的解决方案允许您拨打model.active?来知道某个实例是否属于该范围,并且Model.active可以查找与范围匹配的所有记录。 model.active?不涉及任何数据库查询。

考虑添加这config/initializers/scope_and_method.rb

require 'active_record/named_scope' 

module ActiveRecord::NamedScope::ClassMethods 
    def scope_and_method field, *values 
    field = field.to_sym 
    values.each do |value| 
     named_scope value.to_sym, :conditions => {field => value} 
     define_method "#{value}?" do 
     send(field.to_sym) == value 
     end 
    end 
    end 
end 

用法:

scope_and_method :state, 'active', 'inactive' 

作品,仿佛它是:

named_scope :active, :conditions => {:state => 'active'} 
named_scope :inactive, :conditions => {:state => 'inactive'} 

def active? 
    state == 'active' 
end 

def inactive? 
    state == 'inactive' 
end 

这是为Rails 2.3的溶液。这需要Rails 3和4的微调。(named_scope - >scope)我会尽快检查。