self.id in model

Happy holidays all!

I have a has_many line in my Members.rb model:

has_many :friends, :class_name => "Member", :finder_sql => "SELECT members.* FROM members, friends WHERE friends.member_id = #{self.id}"

when I run this line: @member.friends, the following query is ran:

select members.* from members, friends where friends.member_id = 53930410

Ignore the logic, the point is, self.id keeps translating to some crazy number like 53930410 instead of what it should be, 2.

Any ideas why?

What is happening is that you are getting the object’s object_id instead of it’s saved id. To see what I am talking about, load up irb and make an object, say: a = “A String” then type: a.id It will say this is deprecated, and that you should use object_id instead, but it will also show you the object_id. These numbers vary greatly, but the one returned to you seems to fit right in with this.

However, I am not sure why this is happening in your specific case. Hopefully this will at least help you look into the problem further.

Good luck and happy holidays, Tyler Prete

hi,

self is Members not an instance of Members thus with self.id it translates to object_id aka self.id => Members.id

might help

regards gaurav

hi,

irb(main):034:0> class A irb(main):035:1> p self irb(main):036:1> def g irb(main):037:2>
p self irb(main):038:2> end irb(main):039:1> end A => nil irb(main):043:0> a=A.new => #<A:0x2c59570> irb(main):044:0> a.g #<A:0x2c59570> => nil

this might give clear picture whats happening

regards gaurav

Makes sense.... so that begs the question, how can I access the objects id field as opposed to the object_id?

undefined method `' for Member:Class

I have a has_many line in my Members.rb model:

has_many :friends, :class_name => "Member", :finder_sql => "SELECT members.* FROM members, friends WHERE friends.member_id = #{self.id}"

when I run this line: @member.friends, the following query is ran:

select members.* from members, friends where friends.member_id = 53930410

Ignore the logic, the point is, self.id keeps translating to some crazy number like 53930410 instead of what it should be, 2.

Any ideas why?

According to documentation simple #{id} should work, but it does not. I think it is a bug. Can anyone confirm this?

Regards, Rimantas

Try self[:id] or self.send(:id).

You're probably getting Ruby's object id for the object denoted by self.

--steve

self[:id] raises the error listed above... self.send(:id) draws the same object_id as before, not the objects id field from the database

hi,

   I doubt you can do it that way.   As id you want is an instance variable and the way you want it is without instantiation.

p=Place.new

=> #<Place:0x3406dc8 @attributes={"place"=>""}, @new_record=true>

p.id

=> nil

Place.id

(irb):8: warning: Object#id will be deprecated; use Object#object_id => 28166940

you can even try p.methods.sort and see the result where you find id and id= methods similar to attr_accessors.......

regards gaurav

Now that I look at your code, I think it's a context issue. Consider this, when you call a class method, what is the definition of self? Out of curiosity, why do you need to be so specific in your finder_sql? Wouldn't it be better to do something along the lines of

has_many :friends, :class_name => 'Member', :foreign_key => 'member_id'

Then when you find a member, there is an association to that member's friends. You can simply select within them or use scope.

Am I on the right track?

app/models/member.rb class Member < ActiveRecord::Base   has_many :my_friends, :class_name => "Friend", :foreign_key => "member_id"   has_many :friends, :through => :my_friends, :source => :member end

app/models/friend.rb class Friend < ActiveRecord::Base   belongs_to :member end

db/migrate/001_create_members.rb class CreateMembers < ActiveRecord::Migration   def self.up     create_table :members do |t|       # t.column :name, :string       t.column :username, :string     end   end

  def self.down     drop_table :members   end end

db/migrate/002_create_friends.rb class CreateFriends < ActiveRecord::Migration   def self.up     create_table :friends do |t|       # t.column :name, :string       t.column :member_id, :int     end   end

  def self.down     drop_table :friends   end end

ruby script/console

Member.new(:username => "edbond").save

=> true

Member.find(:first).friends

=>

will generate (from log/development.log):   Member Load (0.000361) SELECT members.* FROM members INNER JOIN friends ON members.id = friends.member_id WHERE (friends.member_id = 1)

In through associations on edge rails you can use << method to add new friends. In rails 1.1.6 you can't. You need to create model for join table see: http://blog.hasmanythrough.com/articles/2006/08/19/magic-join-model-creation

"""s.ross писал(а): """

Yes you are on the right track... although I removed the difficult logic to simplify the explanation of my problem.

Although at this point, I think I understand the context issue and why it's not working, so I think I'll switch my strategy around and eliminate the use of finder_sql.

Thanks all, Chad

Sure, you are getting the wrong self. Try:

has_many :friends, :class_name => "Member", :finder_sql => 'SELECT members.* FROM members, friends WHERE friends.member_id = #{self.id}'

Note the change from "-quotes to '-quotes. You want the #{self.id} to be evalulated later when the SQL is needed, not while you're defining the :finder_sql. (That is, when self is an instance of Member not the class itself.)

You could also have escaped the interpolation "SELECT ... \#{self.id}"

Do you really need :finder_sql in this case? If a member can really have more than one friend, wouldn't you need another table to hold the relationship (i.e., the friendships table)?

class Member < ActiveRecord::Base    has_many :friendships, :dependent => :destroy    has_many :friends, :through => :friendships end class Friendship < ActiveRecord::Base    belongs_to :member    belongs_to :friend, :class => 'Member', :foreign_key => :friend_id end

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com

Sure, you are getting the wrong self. Try:

has_many :friends, :class_name => "Member", :finder_sql => 'SELECT members.* FROM members, friends WHERE friends.member_id = #{self.id}'

Note the change from "-quotes to '-quotes. You want the #{self.id} to be evalulated later when the SQL is needed, not while you're defining the :finder_sql. (That is, when self is an instance of Member not the class itself.)

Thank you for pointing this out! I think this is quite a gotcha and deserves a word or two in documentation...

Regards, Rimantas