#ruby-on-rails
#ruby-on-rails
Вопрос:
Я просмотрел различные ответы на похожие вопросы и не совсем понял это. wine
Модель определяется с has_one :register, :dependent => :destroy
помощью и правильно или неправильно я добавил accepts_nested_attributes_for :register
. A register
определяется с belongs_to :wine
помощью .
Код внутри wines_controller.rb
for create
:
def new
@wine = Wine.new
@register = Register.new
def create
@wine = Wine.new(wine_params)
@register = @wine.registers.build(register_params)
respond_to do |format|
if @wine.save
#success
else
format.json { render json: @wine.errors, status: :unprocessable_entity }
format.json { render json: @register.errors, status: :unprocessable_entity }
end
end
end
Моя форма для создания a new wine
имеет следующий код:
<%= simple_form_for @wine do |f| %>
# various working elements
<div class="field">
<% f.fields_for :register do |r| %>
<%= r.label :short_name %>
<%= r.text_field :short_name %>
<%= r.label :barcode %>
<%= r.text_field :barcode %>
<% end %>
</div>
При вызове этой формы из команды не создаются поля f.fields_for
, но этот блок выполняется, потому что я могу добавить в него тестовые кнопки, чтобы доказать, что к нему обращаются.
Если я пытаюсь создать wine, я получаю следующее сообщение об ошибке:
undefined method `registers' for #<Wine:0x007f1204375330> Did you mean? register register= register_id
Я считаю, что использование .build
предназначено для обеспечения целостности данных: я не хочу создавать a wine
, у которого нет соответствующего register
. Я пытался подумать об этом вложенные атрибуты, но, похоже, многие считают это плохим планом. Этот текущий подход кажется правильным, но я думаю, что мне, по крайней мере, не хватает понимания синтаксиса.
Позже необходимо будет связать другие модели register
, которые не будут связаны с wines. Я рассматривал аналогичный подход, но я рад, что мне сказали переосмыслить!
Ответ №1:
Если я правильно вас понимаю, у вас есть 2 проблемы:
Во-первых, поля для register не отображаются — это отчасти потому, что @wine .регистр равен нулю.
Вы должны изменить свое новое действие на:
def new
@wine = Wine.new
@wine.register = Register.new
Кроме того, поскольку вы используете simple_form_for
, вам нужно будет использовать simple_fields_for
вместо fields_for
Ваша вторая проблема, которая приводит к исключению, говорит вам все… вы пытаетесь получить доступ к @wine.регистры, а не @wine .Зарегистрироваться
Измените свой метод создания на:
@register = @wine.register.build(register_params)
Это устранит эту проблему… однако … все, что вам действительно нужно сделать, это создать объект @wine из ваших параметров — ваши параметры должны быть настроены так, чтобы разрешать правильные вложенные атрибуты — если он настроен правильно, объект register также будет создан при создании объекта @wine .
Ваша модель уже настроена на accept_nested_attributes и, следовательно, также будет проверять и сохранять объект register при вызове @wine .сохранить — нет необходимости явно сохранять объект register.
У вас должно быть что-то вроде:
def wine_params
params.require(:wine).permit(
:attribute1, :attribute2,
register_attributes: [:id, :short_name, :barcode])
end
Комментарии:
1. Хорошо, спасибо за ввод. Первая предлагаемая вами корректировка приводит к появлению » ActiveModel:: MissingAttributeError в WinesController #new` и
can't write unknown attribute 'wine_id'
2. Эта ошибка возникает, если я пытаюсь создать новую запись wine
3. не могли бы вы уточнить… мы говорим о
@wine.register = Register.new
строке? Если это так, проверьте свою таблицу регистров… у него должна быть ссылка на wine_id4. В таблице
wines
действительно есть столбецwine_id
, автоматически созданный Rails. Сообщение об ошибке указывает на строку@wine.register = Register.new
5. Я попытался добавить
wine_id into the attributes of
register`, но, к счастью, это не помогло. Я бы только смутился, если бы это было так!
Ответ №2:
Попробуйте это
Модели Wine и Register
class Wine < ApplicationRecord
has_one :register, inverse_of: :wine, :dependent => :destroy
accepts_nested_attributes_for :register
end
class Register < ApplicationRecord
belongs_to :wine, inverse_of: :register
validates_presence_of :wine
end
Контроллер Wines
class WinesController < ApplicationController
def new
@wine = Wine.new
@wine.build_register
end
def create
@wine = Wine.new(wine_params)
if @wine.save
redirect_to @wine
else
render :new
end
end
private
def wine_params
params.require(:wine).permit(:name, register_attributes: [:simple_name])
end
end
Мои wine_params специфичны для
rails g model wine name:string
rails g model register name:string wine_id:integer
Наконец, форма wine должна выглядеть следующим образом
<%= form_for @wine do |f|%>
<p>
<%= f.label :name%>
<%= f.text_field :name%>
</p>
<%= f.fields_for :register do |r|%>
<p>
<%= r.label :simple_name%>
<%= r.text_field :simple_name%>
</p>
<% end %>
<%= f.submit %>
<% end %>
Таким образом, вы можете изменять wine_params и формировать partial для специфики вашего приложения
Комментарии:
1. регистрация будет сохранена автоматически при создании wine
2. Также вы можете использовать simple_form_for и simple_fields_for вместо form_for и fields_for