reciprocating relationships

57 views
Skip to first unread message

fugee ohu

unread,
Jan 12, 2018, 7:06:12 PM1/12/18
to Ruby on Rails: Talk
Let's say I have a table of products and a table of accessories Each accessory can have many products that it's compatible with while each product has many accessories available for it It In the problem I'm trying to solve accessories cannot belong to products and products cannot belong to accessories So, unless I was to create a third table with fields for product_id and accessory_id, how could I allow each to have many of the other Do I have to create the third table? Thanks in advance

Walter Lee Davis

unread,
Jan 12, 2018, 9:02:27 PM1/12/18
to rubyonra...@googlegroups.com
This is a basic part of what is called a many-to-many relationship, which is what you describe here. These relationships always rely on a third table in any relational database-backed application (i.e. this is not specific to Rails).

There are two ways to model this relationship in Rails. The first (and oldest) is the has_and_belongs_to_many relationship, which uses a simple table consisting of two columns (accessory_id and product_id), and does a "dumb" join between the two models. Nothing (besides the simple fact of bi-directional relation) is stored in the middle table.

The second approach, which has been recommended in preference to the "dumb join" for many years, is the has_many through relationship. That also uses a third table, but that table backs a full ActiveRecord model. It would have an id, along with the product_id and accessory_id, and could include as many other columns as you may need in order to properly model the relationship between the other two objects. For example, you could "decorate" the join between the two main objects with more specific details about their relationship.

Say if you had a Person, Team, and Membership model, you could use the Membership to carry the date the person joined the team, or their role on the team. Your models would look like this:

class Person < ActiveModel
has_many :memberships
has_many :teams, through: :memberships
end

class Team < ActiveModel
has_many :memberships
has_many :people, through: :memberships
end

class Membership < ActiveModel
belongs_to :person
belongs_to :team
end

If you have any thoughts at all that you may want to have a richer connection between products and accessories, then by all means use the has_many through relationship.

Walter

> On Jan 12, 2018, at 7:06 PM, fugee ohu <fuge...@gmail.com> wrote:
>
> Let's say I have a table of products and a table of accessories Each accessory can have many products that it's compatible with while each product has many accessories available for it It In the problem I'm trying to solve accessories cannot belong to products and products cannot belong to accessories So, unless I was to create a third table with fields for product_id and accessory_id, how could I allow each to have many of the other Do I have to create the third table? Thanks in advance
>
> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/e161bc52-f089-493a-8d12-00f597726217%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

fugee ohu

unread,
Jan 13, 2018, 12:02:53 AM1/13/18
to Ruby on Rails: Talk
Thanks Walter
Message has been deleted
Message has been deleted

Walter Lee Davis

unread,
Jan 20, 2018, 10:49:50 AM1/20/18
to rubyonra...@googlegroups.com

> On Jan 19, 2018, at 7:37 PM, fugee ohu <fuge...@gmail.com> wrote:
>
> can create person objects with Adress.....person.new but if I'm creating a new person object from @person from a form, how do i create the entry to the relationships table since I don't have @person.id yet
>
>

You don't need to do that -- Rails cleans up those values for you when it saves the parent. So if you have

@user = User.new(user_params)
@widgets = @user.widgets.build(widget_params)

When you save @user, the @widgets will be saved as well, and the correct ID will be put into each of the @widgets.

Walter

fugee ohu

unread,
Jan 20, 2018, 10:49:59 PM1/20/18
to Ruby on Rails: Talk
i was actually able to get @person.id after if  @person.save Relationship.find_or_create_by(person_id: @person.id ...

fugee ohu

unread,
Feb 2, 2018, 2:39:41 PM2/2/18
to Ruby on Rails: Talk
So if I'm using the second approach the has_many_through then how do i create a new record? 

Colin Law

unread,
Feb 2, 2018, 5:01:05 PM2/2/18
to Ruby on Rails: Talk
On 2 February 2018 at 19:39, fugee ohu <fuge...@gmail.com> wrote:

So if I'm using the second approach the has_many_through then how do i create a new record? 

Start by reading the rails guide on active record relations, that shows you how to do that sort of thing.

Colin
 
Message has been deleted

fugee ohu

unread,
Feb 2, 2018, 9:07:41 PM2/2/18
to Ruby on Rails: Talk
This code `@person.pictures << @picture` causes an error

Could not find the association :people_pictures in model Person


class PeoplePictures < ApplicationRecord
 belongs_to :person
 belongs_to :picture

class Person < ApplicationRecord
 has_many :pictures, through: :people_pictures

class Picture < ApplicationRecord
  has_many :people, through: :people_pictures

Walter Lee Davis

unread,
Feb 3, 2018, 11:21:17 AM2/3/18
to rubyonra...@googlegroups.com
If you have read the guide, as Colin recommended, really read every line of it, you would have seen this:

class Physician < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end

class Appointment < ApplicationRecord
belongs_to :physician
belongs_to :patient
end

class Patient < ApplicationRecord
has_many :appointments
has_many :physicians, through: :appointments
end

See how each has_many is described with two, separate has_many relationships? One goes to the "join object" and another to the "joined object". You are missing the association to the 'join object', which in your relationship would be:

has_many :people_pictures

Walter

> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/81d55ecb-6bda-41b1-a2c5-2d5f868affed%40googlegroups.com.

fugee ohu

unread,
Feb 3, 2018, 2:19:35 PM2/3/18
to Ruby on Rails: Talk
Yikes Actually was falling asleep messin with it last night Sorry 

fugee ohu

unread,
Feb 3, 2018, 2:54:33 PM2/3/18
to Ruby on Rails: Talk


On Friday, January 12, 2018 at 7:06:12 PM UTC-5, fugee ohu wrote:
Let's say I have a table of products and a table of accessories Each accessory can have many products that it's compatible with while each product has many accessories available for it It In the problem I'm trying to solve accessories cannot belong to products and products cannot belong to accessories So, unless I was to create a third table with fields for product_id and accessory_id, how could I allow each to have many of the other Do I have to create the third table? Thanks in advance

Naming conventions for the join table are the same as for  has_and_belongs_to_many ?

Walter Lee Davis

unread,
Feb 3, 2018, 3:03:26 PM2/3/18
to rubyonra...@googlegroups.com
There are no requirements on this. The join table should be named for the join model, not the sides of the relationship. The reason that the HABTM naming convention exists at all is because there is no model in the middle, just the table. That means that the table name must be inferred from the sides of the relationship, since there would be no other way to configure that.

Often in this area, you will see a join table name that means something specific to the relationship. So between User and Group, you might see Membership, and that might mean that User has:

has_many :memberships
has_many :groups, through: :memberships

and Group has:

has_many :memberships
has_many :users, through: :memberships

But you may want to say @group.members because it expresses the semantics of the relationship better:

has_many :members, through: :memberships, class_name: 'User', foreign_key: :user_id

This sort of relationship is endlessly configurable and flexible, which is another reason why it is preferred over HABTM.

Walter

>
> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/ddab7848-1da5-44fc-a748-63ade27a54f7%40googlegroups.com.

fugee ohu

unread,
Feb 3, 2018, 3:56:18 PM2/3/18
to Ruby on Rails: Talk


On Friday, January 12, 2018 at 7:06:12 PM UTC-5, fugee ohu wrote:
Let's say I have a table of products and a table of accessories Each accessory can have many products that it's compatible with while each product has many accessories available for it It In the problem I'm trying to solve accessories cannot belong to products and products cannot belong to accessories So, unless I was to create a third table with fields for product_id and accessory_id, how could I allow each to have many of the other Do I have to create the third table? Thanks in advance

@person.pictures << @picture tries to, create a new picture, not add it to the person_picture association table

Walter Lee Davis

unread,
Feb 3, 2018, 5:49:13 PM2/3/18
to rubyonra...@googlegroups.com
Where does @picture come from? Did you build it in memory, or load it from the database? Rather than adding an object you created to an association, try building the associated object from the beginning, like this:

@picture = @person.pictures.build(picture_attributes)

Now that picture is automatically in the @person.pictures association, and has whatever other attributes you assigned to it.

When you save the picture, the corresponding person_picture instance will be persisted as well. The picture has to be created and saved before the person_picture record can be, otherwise where would the person_picture.picture_id value come from?

Walter

fugee ohu

unread,
Feb 4, 2018, 7:54:26 AM2/4/18
to Ruby on Rails: Talk
to do that i added accepts_nested_attributes_for :picture it didn't create the  association

fugee ohu

unread,
Feb 11, 2018, 8:49:17 PM2/11/18
to Ruby on Rails: Talk

fugee ohu

unread,
Feb 11, 2018, 8:51:44 PM2/11/18
to Ruby on Rails: Talk


On Friday, January 12, 2018 at 9:02:27 PM UTC-5, Walter Lee Davis wrote:
I was thinking of another use for has_many_through If I  wanna put a new abstraction in between two existing relationships like adding a Blog model and letting users have many posts through blogs instead of users having many posts and all the layers under posts i can leave alone i don't have to recode them

fugee ohu

unread,
Aug 12, 2018, 10:49:38 PM8/12/18
to Ruby on Rails: Talk
Can we revisit this one I'm doing a family tree and trying to manage spousal relationships so i have person has_many people through: :partnerships But now partnerships can't have person_id twice so this is perplexing me  

Colin Law

unread,
Aug 13, 2018, 2:35:04 AM8/13/18
to Ruby on Rails: Talk
On Mon, 13 Aug 2018 at 03:49, fugee ohu <fuge...@gmail.com> wrote:

Can we revisit this one I'm doing a family tree and trying to manage spousal relationships so i have person has_many people through: :partnerships But now partnerships can't have person_id twice so this is perplexing me  

Google for
rails self referential has_many through

Colin

David Merrick

unread,
Aug 13, 2018, 3:56:26 AM8/13/18
to Ruby on Rails: Talk
Surely if every person object(eg.father) has a unique Id. Then that Id can be included in their childrens identity and fathers Id can be put into his brothers identity and sister identity and parents identity.
Then it becames a searching for matching Id's both depth wise and breadth wise.

Isn't that what a family tree is all about creating relationships and you build it.

Cheers Dave

--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


--
Dave Merrick

Daves Web Designs

Website http://www.daveswebdesigns.co.nz

Email merri...@gmail.com

Ph   03 216 2053

Cell 027 3089 169

David Merrick

unread,
Aug 13, 2018, 4:08:18 AM8/13/18
to Ruby on Rails: Talk
If you have ever finished https://www.railstutorial.org/ deals with relationshps rather well. Can't send code.

Cheers Dave

On Mon, Aug 13, 2018 at 6:34 PM Colin Law <cla...@gmail.com> wrote:
--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/CAL%3D0gLve84pFng5RTUKFSCKgnMW%2BCVLAOdNen4uKFE9XAaOpcA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages