sparkle
sparkle

Reputation: 7400

Rails create / update join table with additional field

JOIN TABLE

Each time I create/update time join table I have to inser the rank position.

Model

class Category < ApplicationRecord
  has_and_belongs_to_many :products

class Product < ApplicationRecord
  has_and_belongs_to_many :categories

Schema.db

create_table "products_categories", id: false, force: :cascade do |t|
    t.bigint "category_id", null: false
    t.bigint "product_id", null: false
    t.integer "rank"
    t.index ["category_id", "product_id"], name: "index_products_categories_on_category_id_and_product_id"
  end

I know I can do this. But how can I pass the rank value ?

c = Category.find(1)
c.products = array_of_products
c.save

Rails 5.2

Upvotes: 1

Views: 2456

Answers (2)

s3tjan
s3tjan

Reputation: 1168

As @Sean described, you need to use a has_many :through association since:

You should use has_many :through if you need validations, callbacks or extra attributes on the join model. 2.8 Choosing Between has_many :through and has_and_belongs_to_many

For example, to create a join model rank (I can`t come up with a better name than rank, sorry!):

# join table migration
class CreateRanks < ActiveRecord::Migration[5.2]
  def change
    create_table :ranks do |t|
      t.references :product
      t.references :category
      t.integer    :rank

      t.timestamps
    end
  end
end

Your models:

# product.rb
class Product < ApplicationRecord
  has_many :ranks
  has_many :categories, through: :ranks
end

# rank.rb 
class Rank < ApplicationRecord
  belongs_to :product
  belongs_to :category
end

# category.rb
class Category < ApplicationRecord
  has_many :ranks
  has_many :products, through: :ranks
end

So you can create your records "in bulk" as follows:

Rank.create [
  { category: a, product: x, rank: 1},
  { category: b, product: y, rank: 2}
]

Upvotes: 6

Sean
Sean

Reputation: 983

You need to use a has_many :association, through: :through_association with an explicit model as the join model. That way you can store data about the association itself.

Upvotes: 1

Related Questions