Check if model instance falls within named_scope i

2019-03-27 07:55发布

问题:

Assume I have a named scope:

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

This works great for queries and I have a bunch of useful named_scopes defined. What I would like is to be able to do this:

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

The '.bar?' method will simply return true or false if the model instance falls within the named scope. Is there anyway to do this without writing an 'is_bar?' method even though I've already written a good way to check if something 'is_bar?' If I remember correctly, DRY is good so any help would be greatly appreciated/

回答1:

You can call the exists? method on a named scope which will query the database to see if the given record exists with those conditions.

Foo.bar.exists?(f)

However this will not work if you have changed the attributes on f and not saved it to the database. This is because the named scope conditions are SQL so the check must happen there. Attempting to convert to Ruby if conditions is messy, especially in more complex scenarios.



回答2:

If your scopes are simple, you probably want to avoid code duplication. My solution allows you to call model.active? to know if an instance belongs to the scope, and Model.active to find all records matching the scope. model.active? doesn't involve any database queries.

consider adding this to 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

Usage:

scope_and_method :state, 'active', 'inactive'

Works as if it was:

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

def active?
  state == 'active'
end

def inactive?
  state == 'inactive'
end

This is a solution for Rails 2.3. This needs a very small tuning for Rails 3 and 4. (named_scope -> scope) I will check it soon.