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