Rails 创建/更新带有附加字段的连接表

spa*_*kle 1 activerecord ruby-on-rails rails-activerecord ruby-on-rails-5

加入表

  • 类别(外键)
  • 产品(外键)
  • 排名(整数)

每次创建/更新时间连接表时,我都必须插入排名位置。

模型

class Category < ApplicationRecord
  has_and_belongs_to_many :products

class Product < ApplicationRecord
  has_and_belongs_to_many :categories
Run Code Online (Sandbox Code Playgroud)

架构数据库

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
Run Code Online (Sandbox Code Playgroud)

我知道我可以做到这一点。但是我怎样才能传递等级值呢?

c = Category.find(1)
c.products = array_of_products
c.save
Run Code Online (Sandbox Code Playgroud)

导轨 5.2

小智 5

正如@Sean所述,您需要使用has_many :through关联,因为:

has_many :through如果您需要连接模型上的验证、回调或额外属性,则应使用。 2.8 在 has_many :through 和 has_and_belongs_to_many 之间进行选择

例如,要创建一个连接模型rank(我想不出比 rank 更好的名称,抱歉!):

# 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
Run Code Online (Sandbox Code Playgroud)

您的模型:

# 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
Run Code Online (Sandbox Code Playgroud)

因此,您可以“批量”创建您的记录,如下所示:

Rank.create [
  { category: a, product: x, rank: 1},
  { category: b, product: y, rank: 2}
]
Run Code Online (Sandbox Code Playgroud)