Ask A Question

Notifications

You’re not receiving notifications from this thread.

CRUD on attribute in N/N join table

Nic asked in Rails

Hi!

I am struggling with a many to many relation to access an attribute stored in the join table.

I basically have two models :

  • "User" which has_or_belongs_to_many :items
  • "Item" which has_or_belongs_to_many :users

In between, I have a join table "items_users" created via migration, where I added an extra attribute "quantity".

In order to CRUD these entities, what should be the process ? I came across this topic https://stackoverflow.com/questions/25235025/rails-4-accessing-join-table-attributes/25238779#25238779 but I couldn't make it work.

I came to Rails from a Laravel background and we use to do this for the problem exposed (it is just to show by code what I could mistakely explain by words):

  • In a model Item, I declare my relationship as such: public function users() { return $this->belongsToMany(User::class)->withPivot('quantity') }

Which allows me to fetch all users that have the item like so (and access the property in the join table): $item->users

  • In a model User, I declare my relationship as such:

public function items()
{
return $this->belongsToMany(Item::class)->withPivot('quantity')
}

Which allows me to fetch all items that have the user like so (and access the property in the join table): $user->items

To create this relation in DB, we execute:

$user->items()->attach($item->id, ['quantity' => 10]);

To access the property in a datatable for example, after a loop on $user->items, we display the quantity via $item->pivot->quantity

Hope I have been concise enough to explain the problem, I am junior on RoR, so I may misuse the terminology of things.

Regards.

Reply

has_and_belongs_to_many does not allow you to access the join table, and therefore it's very rarely used.

Instead, you just want to define a has_many :through association.

class User
  has_many :user_items
  has_many :items, through: :user_items
end

class UserItem
  belongs_to :user
  belongs_to :item
end

class Item
  has_many :user_items
  has_many :users, through: :user_items
end

This way you can interact with the join table and add things like quantity.

Reply

Thanks a lot for your answer.

Is there any simplier way to access that attribute that what I am doing ? I am sure yes.

<% @user.items.each do |i| %>


<%= i.user_items.where(:user_id => @user.id).first.quantity %>
<%= i.name %>


<% end %>

Also, when it comes to create this relationship, how to write the create call ?

Reply

You should loop through @user.user_items.includes(:item) instead so you can access the quantity without an extra query. The includes will load the items records efficiently so you aren't doing any N+1 queries.

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 87,563+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.