Проверьте, попадает ли экземпляр модели в named_scope в rails

Предположим, у меня есть именованная область:

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

Бар?' метод просто вернет true или false, если экземпляр модели попадает в указанную область. Есть ли способ сделать это без написания is_bar? метод, хотя я уже написал хороший способ проверить, является ли что-то 'is_bar?' Если я правильно помню, DRY хорош, поэтому любая помощь будет принята с благодарностью.


person user94154    schedule 10.08.2009    source источник


Ответы (2)


Вы можете вызвать метод exists? для именованной области, которая будет запрашивать базу данных, чтобы узнать, существует ли данная запись с этими условиями.

Foo.bar.exists?(f)

Однако это не сработает, если вы изменили атрибуты f и не сохранили их в базе данных. Это связано с тем, что условия именованной области являются SQL, поэтому проверка должна выполняться там. Попытка преобразовать в условия Ruby if запутана, особенно в более сложных сценариях.

person ryanb    schedule 10.08.2009
comment
благодаря. Итак, представьте, что я вызвал .save после изменения значения. Foo.bar.exists?(Foo.find(:first)) будет возвращать true или false в зависимости от того, попадает ли он в область панели? Потрясающий. - person user94154; 10.08.2009
comment
Правильный. Вам также не нужно снова вызывать Find. ф.сохранить; Foo.bar.exists?(f) должен работать. - person ryanb; 10.08.2009
comment
Стало ли это легче с 2009 года? - person Jared Beck; 04.12.2014
comment
Возможно, стало тяжелее. Теперь есть предупреждение об устаревании: ПРЕДУПРЕЖДЕНИЕ ОБ УСТАРЕНИИ: Вы передаете экземпляр ActiveRecord::Base в exists?. Пожалуйста, передайте идентификатор объекта, позвонив .id. Так что теперь это должно быть Foo.bar.exists?(f.id). - person David Runger; 18.05.2016

Если ваши области видимости просты, вы, вероятно, захотите избежать дублирования кода. Мое решение позволяет вам вызывать 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) Скоро проверю.

person Nowaker    schedule 18.12.2013