0

I have a User model and a Product model with a many-to-many association and in both models I have "has_and_belongs_to_many"

I understand that this allows me to work with relations like this:

user = User.first

user.products #shows all products bought by a user

and

product = Product.first

product.users # show all users who bought that product

But there might be a product which has not been bought by any user yet, so this product will be in products table but not in the user_products join-table.

How do I return only user-products associations which have been saved in the join table?

Also, say I want to create a product and at the same time define that it has been bought by - belongs to - first and second user. I thought of:

User.all[0..1].each {|usr| usr.product.create(name: "tv")}

Is this the correct way to imply an association and populate the join-table with a record for it?

What if, as I said above, I have a product that is in products table but still no User had bought it, and now a user buys it: how can I express this so that later I can do

user.products

and see that product?

Redoman
  • 3,059
  • 3
  • 34
  • 62

1 Answers1

1

How do I return only user-products associations which have been saved in the join table?

You can't, because you've decided to use has_and_belongs_to_many where the join table is not accessible at all. Consider using has_many through relation.

Is this the correct way to imply an association and populate the join-table with a record for it?

It should be:

User.limit(2).each {|usr| usr.products.create(name: "tv")}

or

User.limit(2).each {|usr| usr.products << Product.create(name: "tv")}

What if, as I said above, I have a product that is in products table but still no User had bought it, and now a user buys it: how can I express this so that later I can do

Simply user.products.reload

blelump
  • 3,233
  • 1
  • 16
  • 20
  • Thanks! That was really helpful! But in last question I actually meant: how do I actually add a new product to an old user ? Also I've just discovered this: `User.joins(:products)`. Doesn't this do what I asked in first question? – Redoman Oct 28 '14 at 23:02
  • 1
    If you want to add new product to an existing user, simply put `User.last.products.create(name: "tv")`, however if you want to join an exiting user with existing product, then it would be: `User.last.products << Product.last`. For `has_many` relationship, that would be helpful for you: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many . Clarifying the first question, perhaps I misunderstood your purpose, `User.joins(:products)` gives you users having products. I thought you want to access the join table, i.e. `User.last.product_users` – blelump Oct 28 '14 at 23:06
  • Thanks! All parts covered now :) Will try to ask a last one here :) -> Do you think that with the current data modeling setup I can enforce uniqueness in the records of join-table? I see I can join a user to a product multiple times, which is not what I want.... – Redoman Oct 28 '14 at 23:21
  • 1
    You need to add a uniqueness constraint to your association. It might be on application level or database level. Check this post: http://stackoverflow.com/a/4992618/2458753 – blelump Oct 29 '14 at 08:00
  • Thanks, the link you adviced was perfect: as explained there I added an index for the join table composed of product_id and user_id. Works great.. now onto db exception handling.. :) – Redoman Oct 29 '14 at 18:58
  • `User.first(2).each {...}` is nice too. – Redoman Nov 06 '14 at 16:54