Ruby on Rails: как создавать связанные модели на лету? - PullRequest
1 голос
/ 30 декабря 2010

У меня есть следующие модели:

class Product < ActiveRecord::Base
  belongs_to :brand
  belongs_to :model
  accepts_nested_attributes_for :brand, :model
  ...
end

class Brand < ActiveRecord::Base
  has_many :products
  has_many :models
  ...
end

class Model < ActiveRecord::Base
  has_many :products
  belongs_to :brand 
  accepts_nested_attributes_for :brand
  ...
end

У меня проблема с созданием нового продукта.

Вот соответствующий код в контроллере:

class ProductsController < ApplicationController
  ...
  def create
    @product = Product.new(params[:product])
    if @product.save ...     # Here is the error
  end
  ...
end

Когда пользователь добавляет новый бренд и новую модель, params[:product] содержит следующее:

"brand_attributes"=>{"name"=>"my_new_brand"}
"model_attributes"=>{"model_no"=>"my_new_model"}

и я получил следующую ошибку:

Mysql2::Error: Column 'brand_id' cannot be null: INSERT INTO `models` ...

потому что модель имеет внешний ключ brand_id, который не установлен. Я не могу установить его, потому что бренд (как и модель) создается на лету, когда создается продукт. Я не хочу создавать бренд перед продуктом, потому что тогда, когда у продукта есть ошибки, мне нужно будет удалить созданный бренд.

Затем я попытался изменить params[:product] так:

"brand_attributes"=>{"name"=>"my_new_brand", 
                     "model_attributes"=>{"model_no"=>"my_new_model"}}

но я получаю следующее:

unknown attribute: model_attributes

Каков был бы правильный способ справиться с этим?

Ответы [ 2 ]

2 голосов
/ 30 декабря 2010

1.) Вам следует избегать использования модели в качестве названия модели (я думаю, вы понимаете, почему это может привести к ошибкам, хотя я не вижу в этом вашей проблемы)

2.) Вы ссылаетесь на слишком большой круговой паттерн. У продукта есть модель, а у модели есть торговая марка. Почему у вас есть продукт принадлежит модели и бренду? Я предлагаю следующую настройку:

class Product < ActiveRecord::Base
  belongs_to :model
  accepts_nested_attributes_for :model
end

class Brand < ActiveRecord::Base
  has_many :models
end

class Model < ActiveRecord::Base
  has_many :products
  belongs_to :brand 
  accepts_nested_attributes_for :brand
end

Меня немного смущает ваша структура данных, которая является вашей основной проблемой.

Product < Model <> Brand

Когда у вас есть круговая ссылка, как вы определили выше, вы не можете иметь формы NESTED, потому что ваши модели NESTED ...

# schema
create_table :products do |t|
  t.string :name
  t.references :model
end

create_table :brands do |t|
  t.string :name
end

create_table :models do |t|
  t.string :name
  t.references :brand
end
1 голос
/ 30 декабря 2010

Ну, во-первых, если вы включите сохранение в транзакцию, сбой в любой момент транзакции откатит все записи, поэтому ваш бренд и другие не будут затронуты.

Product.transaction do
  @product.save
end

Вы можете попробовать это:

before_create :save_associated
validates_associated :brand, :model

def save_associated
  brand.save if brand.new_record?
  model.save if model.new_record?
end

Что вы будете делать, это когда вы создадите запись о продукте, она проверит себя, а затем проверит привязанную марку и модель.Если все пойдет хорошо, он перейдет к обратному вызову before_save, который сохранит связанные с вами модели, а затем модель вашего продукта будет сохранена.Если какая-либо из трех моделей недействительна, вы никогда не доберетесь до save_associated, и если вы чувствуете дополнительный параноик, вы можете заключить сохранение в транзакцию, как указано выше, чтобы автоматически откатить любые изменения, если какая-либо частьсохранить не удалось.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...