(ActiveRecord) Why is there no "belongs_to_many"?

On 6 Aug 2008, at 13:51, Shawn … wrote:

something else).

Fred

yes, i tried to say that above: belongs_to_many/has_one is a synonym
for
has_many/belongs_to and is only syntattically differnt, the has_one
oculd be called has_helper or has_utility (thats the items that fit
into
this relationship) to fix that problem.

Then just alias the methods as I showed.

Fred

Hi –

On Wed, 6 Aug 2008, Shawn … wrote:

a special case as such. Do you guys understand how it works? Its
implementation would be quite useful, its ugly to use a refrence table
thats completely unnecciary.

The has/belongs semantics are, indeed, not always a perfect fit for
the way things relate when we describe them in English. For example, I
remember coming up with an example once where I ended up with a Club
belonging to a Member (or something like that; I’m not remembering
exactly), whereas normally we’d say “He belongs to that club.”

My advice would be to use it as is for a while. If you want two-way
has_many’s, then just use has_many. Remember that the main point of
associations, in any case, is that they generate methods for you. It’s
nice to have them as close as possible to the domain you’re modeling,
but it’s often not very close since “has” and “belongs to” are not
general terms for expressing every possible connection between two
things.

In the end, I think it’s better to keep the number of association
methods down, partly because it helps when it comes to learning how
the associations themselves behave – which ones trigger automatic
saves, and when, and things like that.

David


Rails training from David A. Black and Ruby Power and Light:

  • Advancing With Rails August 18-21 Edison, NJ
  • Co-taught by D.A. Black and Erik Kastner
    See http://www.rubypal.com for details and updates!

On 5 Aug 2008, at 23:53, Shawn … wrote:

imamented, and only work as a pair belongs_to_many with has_one, and
as
a special case as such. Do you guys understand how it works? Its
implementation would be quite useful, its ugly to use a refrence table
thats completely unnecciary.

Well as other people have said, you could just alias has_many to
belongs_to_many and has_one

class ActiveRecord::Base
class << self
alias_method :belongs_to_many, :has_many
end
end

Your belongs to many cannot work with the existing has_one: with your
belongs_to_many the foreign key has to exist on the other table, and
with has_one the foreign key also has to work on the associated table.
When you’ve got a pair of relations, one of them has to be a
belongs_to and the other one a has_many/has_one (even if you call them
something else).

Fred

On Sat, Mar 5, 2011 at 4:13 PM, Alexey M. [email protected] wrote:

class Member < ActiveRecord::Base
This can me implemented the same way as has_and_belongs_to_many, except
that in the joint table the Foreign Key for Members must be required to
be unique.

An Address can be then automatically deleted when the last Member living
at that address is deleted.

The advantage over [belongs_to, has_many] is the same as for has_one
over belongs_to: the Members table does not need to “know” about the
Addresses table.

The thing is, this would just duplicate existing associations; I don’t
see
how it’s needed. The relationship you describe above can be written much
simpler (no join table at all) by just having User belongs_to :address,
and
Address has_many :users.

If it’s the readability of the code that you want, you can always do
things
like

class Address << ActiveRecord::Base

has_many :residents, :class_name => “User”

end

class User << ActiveRecord::Base

belongs_to :address, :foreign_key => “resident_id”

end

For many-to-many, I really tend to favor has_many :through associations
from
both sides, as they’re more flexible.

But honestly; I don’t think belongs_to_many is missing. Just my 2. :slight_smile:

Can you please show the database layout you have in mind that this
would map to?

The normal way would be:

User (belongs_to :address)

  • id
  • address_id

Address (has_many :users)

  • id

If you want the user to not know about the address, you could do:

User

Addressable

  • address_id
  • object_id
  • object_type

Address

and then user and address would both use have_* :through.

Thanks for your replies.

Probably there are ways around (i have not finished reading the
RailsGuides yet), but what seems to be nice to have is:

  1. not to store any foreign key in Members table,
  2. have a kind of (:dependent => …) option that would allow to
    automatically delete an Address when the last Member living at that
    address is deleted.

Adam, was your question addressed to me or to Phil?

Hello, I am re-opening this again, sorry :).

I have just read in RailsGuides (
Active Record Associations — Ruby on Rails Guides )
about the proper way to choose between belongs_to and has_one.
From this point of view, something like belongs_to_many seems to be
really missing, but i do not know if maybe there is a better name, and
how to call the other side of the association (has_a ?).
I am talking about something like this:

class Member < ActiveRecord::Base
has_an :address
end

class Address < ActiveRecord::Base
belongs_to_many :members
end

Different members can have the same address, if they are a couple for
example.

This can me implemented the same way as has_and_belongs_to_many, except
that in the joint table the Foreign Key for Addresses must be required
to be unique (or set as the Primary Key).

An Address can be then automatically deleted when the last Member living
at that address is deleted, and Members should not be deleted if an old
Address is deleted.

The advantage over [belongs_to, has_many] is the same as for has_one
over belongs_to: the Members table does not need to “know” about the
Addresses table.

Just use a couple of aliases if you’re so bothered by the lack of
semantic readability.

belongs_to_many = has_many
has_a = belongs_to

but beware that in your need to make the code more semantically
readable, you’ve just confounded a seasoned railer. :slight_smile:

David A. Black wrote in post #712598:

Hi –

On Wed, 6 Aug 2008, Shawn … wrote:

The has/belongs semantics are, indeed, not always a perfect fit for
the way things relate when we describe them in English. For example, I
remember coming up with an example once where I ended up with a Club
belonging to a Member (or something like that; I’m not remembering
exactly), whereas normally we’d say “He belongs to that club.”

My advice would be to use it as is for a while. If you want two-way
has_many’s, then just use has_many. Remember that the main point of
associations, in any case, is that they generate methods for you. It’s
nice to have them as close as possible to the domain you’re modeling,
but it’s often not very close since “has” and “belongs to” are not
general terms for expressing every possible connection between two
things.

In the end, I think it’s better to keep the number of association
methods down, partly because it helps when it comes to learning how
the associations themselves behave – which ones trigger automatic
saves, and when, and things like that.

David

I am very grateful for this response. I, too was having a bit of
difficulty earlier when the “English just wasn’t making sense”. See, I
have an Event model and a DressCode model and I want to say that Event
has_one DressCode, but I put the foreign key (dress_code_id) in the
Event model (just as I would in my usual SQL/PHP ways. It turned out
that I had to say DressCode has_many Events and Event belongs_to
DressCode. Unorthodox but it works because now I can run
Event.dress_code and I get the result i’m looking for.

Rails is so advanced that I sometimes forget that it is still just a
programming language and, as you said, can’t always be semantically
correct all the time when illustrating real world relationships.

I spent a while searching, ended up on this thread and I finally got my
head around it. To the original poster - just take the advice and do
what needs to be done in order to satisfy the rails convention. Reading
your code might be weird, but that’s nothing that a few comments can’t
fix :wink: