ActiveRecord.id does not work within named_scope block

Hi,

Trying to create a named_scope that would check that the record is not itself.

I have companies and contacts, where a contact can be a primary contact for a company:

class Company   has_many :contacts end

class Contact < ActiveRecord::Base   belongs_to :company

  named_scope :primary, :conditions => { :is_primary => true } do     def mark_as_non_primary!       each { |p| p.update_attribute(:is_primary, false) }     end   end

  named_scope :but_not_itself, :conditions => ['contacts.id != ?', id] end

So I would like to do something like this from Contact model:

  company.contacts.primary.but_not_itself.mark_as_non_primary!

However this does not work because id method within but_not_itself named_scope returns an Object.id (instance id) and not ActiveRecord id (database id).

How do I make it work?

Thanks!

Hi,

Trying to create a named_scope that would check that the record is not itself.

I have companies and contacts, where a contact can be a primary contact for a company:

class Company has_many :contacts end

class Contact < ActiveRecord::Base belongs_to :company

named_scope :primary, :conditions => { :is_primary => true } do def mark_as_non_primary! each { |p| p.update_attribute(:is_primary, false) } end end

named_scope :but_not_itself, :conditions => ['contacts.id != ?', id] end

So I would like to do something like this from Contact model:

    company\.contacts\.primary\.but\_not\_itself\.mark\_as\_non\_primary\!

However this does not work because id method within but_not_itself named_scope returns an Object.id (instance id) and not ActiveRecord id (database id).

The reason this does not work is because that expression "id" is evaluated when named_scope is call to create the scope, ie when the class is loaded, so self is the class Contact. It's the same reason why doing :conditions => ['created_at < ?', 1.day.ago] won't work properly: the 1.day.ago is evaluated once, at class load time and then never again.

Luckily instead of passing a hash of options you can pass a lambda that returns a hash of options. Since that proc will be called when the scope is loaded and in the right context you should be fine.

Fred

Hi Fred,

Thanks for your input.

So far I changed that named_scope into this: named_scope :but_not_itself,   lambda { |id| { :conditions => ['contacts.id != ?', id]} }

Is that what you meant?

Is there a better way to do this?

Now I have to do this: company.contacts.primary.but_not_itself(self.id).mark_as_non_primary!

seems, to me at least, kind of ugly having to pass self.id... :slight_smile:

By the way my inspiration for this came from http://ryandaigle.com/articles/2008/3/24/what-s-new-in-edge-rails-has-finder-functionality Where the author has User.inactive.activate to very neatly activate inactive users.