В отличие от ассоциаций has_many
, вы не можете создавать новые экземпляры из ассоциации has_one/belongs_to
, поскольку она равна нулю, если вы не назначили ассоциацию.
Вместо этого has_one/belongs_to
методы класса сгенерируйте следующие методы:
| | belongs_to |
generated methods | belongs_to | :polymorphic | has_one
----------------------------------+------------+--------------+---------
other | X | X | X
other=(other) | X | X | X
build_other(attributes={}) | X | | X
create_other(attributes={}) | X | | X
create_other!(attributes={}) | X | | X
reload_other | X | X | X
Ваш контроллер должен на самом деле читать:
def new
@flight = Flight.new(flight_params)
# this just seeds the inputs
@flight.build_pilot
end
def create
@flight = Flight.new(flight_params)
if @flight.save
redirect_to @flight
else
# this just seeds the inputs
@flight.build_pilot unless @flight.pilot
render :new
end
end
Как вы можете видеть здесь, построение действительно имеет мало общего с вставкой в базу данных. Вместо этого он просто заполняет поля в форме, которые не будут присутствовать, если связь равна нулю. Вложенные атрибуты заботятся о фактическом создании записи полета. Не указывайте второй параметр для fields_for
, поскольку он не обеспечивает значение по умолчанию - он перезапишет любую существующую запись, которая была там.
<%= f.fields_for :pilot do |pilot_attributes| %>
<%= pilot_attributes.label :name, "Pilot name:" %>
<%= pilot_attributes.text_field :name %>
<br>
<%= pilot_attributes.label :rank, "Rank:" %>
<%= pilot_attributes.text_field :rank %>
<br>
<% end %>
Если вы хотите назначить существующие записи, вам просто нужно передать и внесите в белый список параметр pilot_id
:
<%= form_with(model: @flight) do |f| %>
<%= f.collection_select(:pilot_id, Pilot.all, :name, :id) %>
<% end %>
def flight_params
# be nice to maintainers and don't write your strong parameters
# in one mega-line
params.require(:flight)
.permit(
:flight_number, :destination, :pilot_id,
pilot_attributes: [:name, :rank]
)
end
Однако это может вызвать проблемы, если пользователь передает и pilot_id, и вложенные атрибуты, поэтому вам придется иметь дело с этой возможностью.