Должны ли вложенные ресурсы и сильные параметры использовать 'model' или 'model_attributes' и почему?(недопустимый параметр: модель) - PullRequest
0 голосов
/ 12 марта 2019

У меня есть вложенная форма, которая создает @address с каждым успешным @purchase.

Мои схемы и ассоциации моделей настроены так, что Purchase содержит внешние ключи для всего остального:

address.rb

belongs_to :user
has_many :purchases, foreign_key: :address_id
has_many :items, foreign_key: :address_id

purchase.rb

belongs_to :sender, class_name: "User"
belongs_to :recipient, class_name: "User"
belongs_to :address
belongs_to :item
accepts_nested_attributes_for :address

item.rb

belongs_to :user
has_many :purchases, foreign_key: :item_id
belongs_to :address

Я нашел некоторые ответы , которые предлагают внести в белый список вложенные параметры атрибута в моем контроллере с .permit(address_attributes: [:name]) в контроллере вместо .permit(address: [:name]), но ни один из них не создает запись.

purchases_controller.rb

def confirmation
 @item = Item.friendly.find(params[:item_id])
 @address = @transaction_wizard.transaction.build_address
end

def confirm
 current_step = params[:current_step]
 @item = Item.friendly.find(params[:item_id])
 @transaction_wizard = wizard_transaction_for_step(current_step)
 @transaction_wizard.transaction.attributes = address_params
 session[:transaction_attributes] = @transaction_wizard.transaction.attributes

 if @transaction_wizard.valid?
  next_step = wizard_transaction_next_step(current_step)
  create and return unless next_step

  redirect_to action: next_step
 else
  redirect_to action: current_step
 end
end

def create
 if @transaction_wizard.transaction.save
  redirect_to root_path, notice: "Bid sent. If you would like to cancel before it's approved, you can do so #{view_context.link_to('here', transactions_sent_unapproved_path)}.".html_safe
 else
  redirect_to item_path(@transaction_wizard.transaction.item), notice: 'There was a problem making this bid.'
 end
end

private
def address_params
 params.require(:transaction_wizard).permit(address_attributes: [:name, :street, :street_2, :city, :state, :zip_code])
end

Использую ли я address_attributes или address, результат одинаков:

Parameters: {"transaction_wizard"=>
             {"address"=>
              {"name"=>"name", 
               "street"=>"123 st", 
               "street_2"=>"apt 5", 
               "state"=>"AL", 
               "zip_code"=>"48489"}
             }, 
             "current_step"=>"confirmation", 
             "commit"=>"Complete offer", 
             "item_id"=>"friendly-item-id"
            }
Unpermitted parameter: address

Это моя форма:

<%= form_for @transaction_wizard, as: :transaction_wizard, url: confirm_item_transaction_wizard_path(@item) do |f| %>
 <%= f.fields_for :address do |address| %>
  <%= address.text_field :name %>
  <%= address.text_field :street %>
  <%= address.text_field :street_2 %>
  <%= address.text_field :city %>
  <%= address.text_field :state %>
  <%= address.text_field :zip_code %>
 <% end %>

 <%= f.submit "Submit" } %>
<% end %>

Что дает? Как я могу заставить мой контроллер принимать эти параметры?


Обновление: изменение address на addresses требует, чтобы я изменил эту переменную @address в контроллере на @address = @transaction_wizard.transaction.build_addresses. Это вызывает ошибку uninitialized constant Transaction::Addresses.

Ответы [ 2 ]

1 голос
/ 12 марта 2019

Вы можете настроить вложенные атрибуты с помощью ассоциации own_to, но связь должна быть установлена ​​как необязательная (если вы не используете Rails 4 или более раннюю версию):

class Address < ApplicationRecord
  has_many :purcases
end

class Purchase < ApplicationRecord
  belongs_to :address, optional: true
  accepts_nested_attributes_for :address
end

require 'rails_helper'

RSpec.describe Purchase, type: :model do
  it "accepts nested attributes" do
    purchase = Purchase.create!(address_attributes: { name:  'foo', street: 'bar' })
    address = purchase.address
    expect(address.persisted?).to be_truthy
    expect(address.name).to eq 'foo'
    expect(address.street).to eq 'bar'
  end
end

Это потому, что вложенныеАтрибуты созданы для работы с has_one связями, поэтому «родительская» запись проверяется перед вложенной записью, поэтому внешний ключ (родительский идентификатор) может быть установлен для вложенной записи.

Вы должны быть в белом спискеaddress_attributes.Вложенные атрибуты создают установщик на основе первого аргумента:

accepts_nested_attributes_for :foo
accepts_nested_attributes_for :bars

Это будет принимать foo_attributes= и bars_attributes=.Это, конечно, должно следовать за плюризацией вашей ассоциации (единственное число для has_one / assign_to, множественное число для has_many).

Установщик address= в вашей модели не имеет ничего общего с вложенными атрибутами - он создается ассоциацией belongs_to :address и принимает экземпляр Address.Фактически, если вы внесете в белый список этот параметр, вы получите исключение ActiveRecord::AssociationTypeMismatch.

irb(main):004:0> Purchase.new.address = { street: 'foo' }
ActiveRecord::AssociationTypeMismatch: Address(#70264542836680) expected, got {:street=>"foo"} which is an instance of Hash(#70264511691080)
    from (irb):4

Вам также необходимо настроить форму следующим образом:

<%= f.fields_for :address do |address| %>
  # ...
<% end %>

При использовании fields_for просто введитеназвание ассоциации.Вам не нужно передавать экземпляр, и использование as: :address дает неверный параметр.

1 голос
/ 12 марта 2019

Вы должны использовать address_attributes. Проблемы ваших отношений:

Чтобы использовать accepts_nested_attributes_for, вы должны использовать has_many или has_one, а вы используете belongs_to.

В вашем случае отношения перевернуты, см .:

Покупка принадлежит по адресу

Адрес has_many покупок

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

Вложенные атрибуты - это функция, которая позволяет сохранять атрибуты записи через связанного с ней родителя.

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