HABTM deprected: using has_many :through

Hi all,

I have a question about how utilizing has_many.
I wrote the code without an editor & testing, so it could contain some
errors.

Oh, and also don't mind the weird parent/child relationships here :slight_smile:
http://pastie.caboo.se/139456

I want to be able to do something like:
Parent.find(:first).children[0].active

How can I achieve this? With has_and_belongs_to_many this was easy. But
I was fiddling with has_many and I could not get it working like this.

What am I doing wrong?

Thanks in advance!

Why do you say HABTM is deprecated? Just curious. I was always under the
impression you use HABTM if you just want a simple relationship with no
extra information and the :through option if you needed a more complex
setup.

Nathan Esquenazi wrote:

Why do you say HABTM is deprecated? Just curious. I was always under the
impression you use HABTM if you just want a simple relationship with no
extra information and the :through option if you needed a more complex
setup.

I read this in trac:
DEPRECATED: Using additional attributes on has_and_belongs_to_many
associations. Instead upgrade your association to be a real join model
[DHH]

http://dev.rubyonrails.org/changeset/4123

If you read that again and highlight the key phrase:

DEPRECATED: USING ADDITIONAL ATTRIBUTES on has_and_belongs_to_many
associations. Instead upgrade your association to be a real join model

As Nathan said, using habtm to represent a simple many-to-many
relationship is not deprecated.

Rick Denatale wrote:

Hi all,

I have a question about how utilizing has_many.
I wrote the code without an editor & testing, so it could contain some
errors.

Oh, and also don't mind the weird parent/child relationships here :slight_smile:
http://pastie.caboo.se/139456

I want to be able to do something like:
Parent.find(:first).children[0].active

How can I achieve this? With has_and_belongs_to_many this was easy.
But
I was fiddling with has_many and I could not get it working like this.

That looks plausible. what problems are you having (do you have a
ChildrenParent model ? You'll need one)

Fred

Right, he does and it need to belong_to both parent and child.

I also seems to me that it could use a better name, although I can't
think of what that should be without a bit more knowledge of his
domain.

class ChildrenParent
  belongs_to :parent
  belongs_to :child
end

class Parent < ActiveRecord::Base
  has_many :children_parents
  has_many :children, :through => :children_parents
end

class Child < ActiveRecord::Base
  has_many :children_parents
  has_many :parents, :through => :children_parents
end

That should do it. :slight_smile:

--Jeremy

How about Birth? And if the :position attribute were birth order, it
could be replaced by birthdate.

///ark

Tried the code above and got something like:

p = Parent.find(:first)
p.children.length

=> 2

p.children_parents.length

=> 2

p.children_parents[0].position

=> 0

p.children[0].position

=> NoMethodError: undefined method `position' for #<Child:0xb76b4114>
        from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/attribute_methods.rb:205:in
`method_missing'
        from (irb):3

And p.children[0].position is what I would like to use. When I use
has_and_belongs_to_many this works.

I thought about using something like:

  alias_method(:method_missing_old, :method_missing)
  def method_missing(methodname, *args)
    return song.send(methodname) if args.empty?
    child.send(methodname, args)
  end

in the ChildrenParent class. But I don't know how fragile/stable this
is.

Tried the code above and got something like:

Which code above in particular?

I used the code from Jeremy.

I used the code from Jeremy.

Okay, so the problem is this

p.children_parents[0].position

=> 0

p.children[0].position

=> NoMethodError: undefined method `position' for #<Child:0xb76b4114>

Which is right, Child has not position attribute it's in the ChildrenParent.

Now the problem is that a child has_many children_parents, so we can't just do

p.children[0].children_parent.position

We need to say WHICH of the many possible childrenParents we're
talking about, Now I'm guessing that the logic actually dictates that
there really is only one, in which case we can do

p.children[0].children_parent[0].position

or

p.children.find(:first).children_parent.find(:first).position

However the right way to do this, IMHO would be to do this:

class Child

    def position
        children_parent.find(:first).position
    end
end

But of course this raises the question of why position isn't just a
simple attribute of Child, in which case I'd seriously consider
dropping back to HABTM.

If there really are multiple ChildrenParents associated with a single
Child, then you do need to figure out which one you are getting the
position of.

Thanks Rick.

I'll explain what I'm trying to do.

I'm creating a website where people (at our company) can vote at songs.
The song with the most votes gets played.

So I now have:
Playlist, Song, PlaylistItem

But I dont't find:

p = Playlist.find(:first)
p.playlist_items[0].position
p.playlist_items[0].top_top
p.songs[o].title
p.songs[o].artist

make sence.

Maybe it's the naming of the objects I've done. Does someone know a
better name for the join class so it makes more sence doing the
position-thing on that model instead of song?

So where are the votes in this model?

Why not put a vote count attribute in the Song which voting increments?

If you want to actually hold the votes in the database then you can do
something like:

class Vote < ActiveRecord::Base
  belongs_to :song
  belongs_to :voter
  ..
end

def Song < ActiveRecord::Base
  has_many :votes, :counter_cache => true # and add a votes_count
column to the table

  def self.most_popular
      find(:first, :order => "vote_count DESC")
  end
...
end

I'm struggling, possibly, with the *exact* same problem. Hmm, except
that I'm using has_many :through, while yours is HABTM :frowning:

That being said, how is your interface? Do you have an interface to
associate a specific "child" with a "parent"?

Feel free to contact me by e-mail to trade notes.

-Thufir

What about foster children, or step-parents?

-Thufir