All threads / CRUD on attribute in N/N join table

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.

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.

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 ?

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.

Join the discussion

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

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

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

    logo Created with Sketch.

    Ruby on Rails tutorials, guides, and screencasts for web developers learning Ruby, Rails, Javascript, Turbolinks, Stimulus.js, Vue.js, and more. Icons by Icons8

    © 2020 GoRails, LLC. All rights reserved.