1

I have created a blank rails app (rails new cheese_shop), with two models and a join table. I am trying to create a cheese shop and specifying which cheeses it contains, at creation time, like this:

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

However, I'm getting this error:

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

Apparently, the shop ID is not inserted to the stocks table when I create the shop. Is it possible to fix this, without having to do it in two steps (i.e. without first creating the Shop, and then adding the cheeses?)

Here are my models:

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

My migrations look like this:

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 Answers 2

1

maybe you should try to use nested attributes:

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

    accepts_nested_attributes_for :stocks
end

and then you will be able to do something like:

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

here is doc: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Sign up to request clarification or add additional context in comments.

Comments

0

It turns out Rails creates the associations in two steps, first leaving out the Shop ID, then setting the Shop IDs with an UPDATE, all in one transaction. So The NOT NULL constraints are causing the problem.

Changing this:

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

…to this:

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

…solves the problem, although I'm unhappy with this since now I cannot rely on the database to ensure the integrity of my data.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.