1

I am maintaining a Rails 2.3.x app. Part of it deals with Users and Roles. A user can have a number of roles, each either for some period or indefinitely. I'm trying to write a has_many extension to quickly find all roles that a user currently have active. It involves writing a has_many extension due to the logic of finding active role matching for current time.

So the models look like so:

class User
  has_many :role_user_matchings
  has_many :roles, :through => :role_user_matchings do
    def active
      find(:all, :conditions => ['matchings.starts_at <= ? AND (? < matchings.ends_at OR matchings.ends_at IS NULL)', Time.now, Time.now])   
  end
end

class RoleUserMatching
  belongs_to :user
  belongs_to :role
  # has fields like starts_at and ends_at
  # ends_at can be null, meaning indefinitely
end


class Role < AR:Base
  has_many :role_user_matchings
  has_many :users, :through => :role_user_matchings
end

I need to know currently active roles for the user every time something like this is executed:

@user.roles.active

As role assignments may change frequently or based on the time, I need to ensure roles are returned based on the current time.

So this appears to be working in development mode. I'm wondering if calls to Time.now above are cached in this situation in production mode? Would appreciate if someone could also explain why or why not. Thanks.

As a side note: I know that with named_scopes, to avoid caching, you need to use a lambda expression

# call to 1.week.ago will be cached and will remain the same until restart
named_scope :recent,  { :conditions => ['created_at > ?', 1.week.ago] }
# 1.week.ago will not be cached first
named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }

Wondering if same applies to association extensions.

Swartz
  • 1,051
  • 2
  • 11
  • 23

1 Answers1

0

Without actually running your code, I'm going to go with 'no' it's not cached. The reason is that your extension is a method definition, and will not be executed when the class is loaded. The reason that named scopes are cached (w/out lambda) is because that code is executed when the class is loaded. It will evaluate any expression, so in example one, it's evaluating the hash, but in example two, it's evaluating the lambda.

Having said that, why aren't you using a named scope for the extension and move it back to the Role model? Should the User model know what it means for a Role to be active, or does it just care whether it's active or not?

class Role
  named_scope :active, lambda { { :conditions => ['matchings.starts_at <= ? AND (? < matchings.ends_at OR matchings.ends_at IS NULL)', Time.now, Time.now] }}
end
Peter Brown
  • 50,956
  • 18
  • 113
  • 146
  • Thanks for the reply. On the usage of association extensions vs. named_scopes. My thinking is as follows: named_scope here implies the the role is active. However, the actual expectation is that a matching b/w user and role is the active. Not the role itself. What if I had another marker that signified that Role record was deleted_at (inactive)? Hope that makes sense. So by making it an extension I'm explicitly saying this is the only way to use it via association. – Swartz Nov 22 '11 at 14:00