如何创建具有多对多关系的ActiveRecord对象

时间:2014-11-14 10:30:09

标签: ruby-on-rails ruby activerecord many-to-many

我创建了一个空白的rails应用程序(rails new cheese_shop),有两个模型和一个连接表。我想在创建时创建一个奶酪店并指定它包含哪些奶酪,如下所示:

cheeses = [
  Cheese.create!(name: "Bree"),
  Cheese.create!(name: "Kačkavalj"),
]
Shop.create! name: "The Whistling Cheese", cheeses: cheeses

但是,我收到此错误:

SQLite3::ConstraintException: NOT NULL constraint failed: stocks.shop_id: INSERT INTO "stocks" ("cheese_id", "created_at", "updated_at") VALUES (?, ?, ?)

显然,我在创建商店时没有将商店ID插入stocks表。是否有可能解决这个问题,而不必分两步完成(即没有先创建商店,然后添加奶酪?)

以下是我的模特:

class Cheese < ActiveRecord::Base
  has_many :shops, through: :stocks
  has_many :stocks
end

class Shop < ActiveRecord::Base
  has_many :cheeses, through: :stocks
  has_many :stocks
end

class Stock < ActiveRecord::Base
  belongs_to :shop
  belongs_to :cheese
end

我的迁移看起来像这样:

class CreateTables < ActiveRecord::Migration
  def change
    create_table :cheeses do |t|
      t.string :name, null: false

      t.timestamps null: false
    end

    create_table :shops do |t|
      t.string :name, null: false

      t.timestamps null: false
    end

    create_table :stocks do |t|
      t.integer :shop_id,   null: false
      t.integer :cheese_id, null: false

      t.integer :amount
      t.float :price
    end
  end
end

2 个答案:

答案 0 :(得分:1)

也许您应该尝试使用嵌套属性:

class Shop < ActiveRecord::Base
    has_many :cheeses, through: :stocks
    has_many :stocks

    accepts_nested_attributes_for :stocks
end

然后您将能够执行以下操作:

cheese = Cheese.create!(name: "Bree")
params = { attrib: { name: "The Whistling Cheese", stocks_attributes: { cheese_id: cheese.id} } }
Shop.create params[:attrib]

这里是doc:http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

答案 1 :(得分:0)

事实证明,Rails分两步创建关联,首先省略商店ID,然后在一个事务中设置商店ID以UPDATE。所以NOT NULL约束导致问题。

更改此内容:

  t.integer :shop_id,   null: false
  t.integer :cheese_id, null: false

......对此:

  t.integer :shop_id
  t.integer :cheese_id, null: false

...解决了这个问题,虽然我对此不满意,因为现在我不能依靠数据库来确保数据的完整性。

相关问题