Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check to See if A Particular Active Record Object Is In A Particular 'Scope'

Currently on save I am trying to check to see if a recorded falls into a particular 'scope'. This 'scope' really is just some saved arguments for a .where call. Also with this 'scope' I am only ever checking values of the object, not ever how it relates to other objects in the database, so querying the database will always be over kill if that makes sense.

I have only been able to come up with the below solution

begin
   result = self.class.where(scope).find(self.id)
rescue
  result = false
end

The issue with this is that I have to query the database even though I already have the record, and I have to run this not only before save but after save to check the values it was and the values it will be after save, because there is no way to query the database for the updated version if it hasn't been saved.

There can be a number of these checks so I would like to avoid having to do it twice, and also having to query the database that many times, even if ultimately I am just looking something up by id.

The only other solution I have been able to think of would be to have a method that some how translates the where call into a proc that return a boolean when passed an object. The only issue with that is translating it would some how have to work with the active record adapter being used, which seems like a whole project to its own. So does anyone know of some way to do this, or of a gem that would help?

PS I getting the 'scope' from cache so I can't save it as a proc because you can't put procs into the cache with Rails.

like image 606
rovermicrover Avatar asked Jul 29 '12 17:07

rovermicrover


2 Answers

first you can improve your first solution a bit

result = self.class.where(scope).exists?(self.id)

if you don't want to check the database, why don't you just check if your object's attributes has the values of the scope? if your scope is

class.where(:attr1 => value1, :attr2 => value2, :attr3 => value3)

then you can do

result = self.attr1 == value1 and self.attr2 == value2 and self.attr3 == value3
like image 98
arieljuod Avatar answered Nov 16 '22 21:11

arieljuod


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.

like image 4
Nowaker Avatar answered Nov 16 '22 22:11

Nowaker