#ruby-on-rails #ruby #rails-activerecord #strong-parameters
#ruby-on-rails #ruby #rails-activerecord #строгие параметры
Вопрос:
Я новичок в ruby, и у меня возникли проблемы в следующем сценарии. Я пытаюсь построить взаимосвязь между счетом и товарами. В моем случае я хочу сгенерировать счет во время выполнения, например, когда пользователь нажимает «Создать новый счет», он направляется на маршрут, подобный http://localhost:3000/bills/new и затем у него есть список элементов, из которых он должен выбрать, установив флажки и добавив количество. У меня есть 3 таблицы, элементы, счета, BillItems. В них есть следующие поля:
create_table "bill_items", force: :cascade do |t|
t.integer "bill_id"
t.integer "item_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "quantity"
end
create_table "bills", force: :cascade do |t|
t.integer "user_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "items", force: :cascade do |t|
t.string "name"
t.float "price"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "category_id"
end
Мои модели созданы следующим образом:
Bill.rb
class Bill < ApplicationRecord
has_many :bill_items
has_many :items, through: :bill_items
accepts_nested_attributes_for :bill_items, :allow_destroy => true, :reject_if => :all_blank
end
Item.rb
class Item < ApplicationRecord
has_many :bill_items
has_many :bills, through: :bill_items
end
BillItem.rb
class BillItem < ApplicationRecord
belongs_to :bill
belongs_to :item
end
У меня есть такая форма, как:
<%= form_for @bill do |f| %>
<% if @allItems %>
<% @allItems.each_with_index do |item, index| %>
<tr class="table-success" scope="col-8">
<%= f.fields_for :bill_items do |s| %>
<td class="text-secondary"><%= item.category.name %></td>
<%= s.hidden_field :name, value: item.name %>
<td class="text-primary"><%= s.label item.name %></td>
<td><%= check_box_tag "item_ids[]", item.id, false, class: 'selectable' %> </td>
<td><%= s.number_field(:quantity, in: 1.0..100.0, step: 1) %></td>
<td><%= s.label :price, item.price %></td>
<% end %>
</tr>
<% end %>
<% end %>
</tbody>
</table>
<div class="form-group row justify-content-center">
<%= f.submit "Create Order with Selected items", class: "btn btn-secondary" %>
</div>
<% end %>
Затем у меня есть настройка моего контроллера следующим образом:
def new
@bill = Bill.new
@bill_items = @bill.bill_items.build
end
def create
byebug
@bill = Bill.new(bill_params)
@bill.save
redirect_to new_bill_path
end
private
def bill_params
params.require(:bill).permit(bill_items_attributes: [:quantity, :item_ids])
end
Когда я запускаю свой код и отправляю данные в форму и проверяю параметры через byebug, он показывает мне следующие параметры, в то время как я выбрал два элемента с идентификаторами 1 и 4:
<ActionController::Parameters {"authenticity_token"=>"hVnrTkWxWwuXqS4tb01INVkNwRaFooVERKe2L8YkXykyPqImKCVRrvqjhK8sA0Q26nsOS dSNdLvIOPTfis8nQ==", "bill"=>{"bill_items_attributes"=>{"0"=>{"name"=>"sheer", "quantity"=>"2"}, "1"=>{"name"=>"burger", "quantity"=>""}, "2"=>{"name"=>"custurs", "quantity"=>""}, "3"=>{"name"=>"sib", "quantity"=>"4"}}}, "item_ids"=>["1", "4"], "commit"=>"Create Order with Selected items", "controller"=>"bills", "action"=>"create"} permitted: false>
Затем я нажимаю «Отправить», и это только сохраняет счет в БД и выдает мне ошибку
Unpermitted parameter: :name
Unpermitted parameter: :name
Unpermitted parameter: :name
Unpermitted parameter: :name`
Я перепробовал много методов и не смог найти решение. Будет очень полезно, если кто-нибудь сможет мне с этим помочь. Даже если мне нужно перепроектировать свою логику, помогите мне с этим. Спасибо.
Ответ №1:
<td><%= check_box_tag "item_ids[]", item.id, false, class: 'selectable' %> </td>
должно быть
<td><%= check_box_tag "bill[item_ids[]]", item.id, false, class: 'selectable' %> </td>
Комментарии:
1. пожалуйста, дайте мне знать о любых других изменениях, которые необходимо внести в параметры моего контроллера или модальные параметры. Спасибо
Ответ №2:
Проблема: существует несоответствие в именовании вложенных атрибутов
Модель Bill принимает вложенные атрибуты для :items
указанного вами контроллера :bill_items_attributes
и формирует генерирующие поля для bill_items — f.fields_for :bill_items
Решение: сделайте его согласованным
В модели Bill —
accepts_nested_attributes_for :items
На контроллере счетов —
permit(items_attributes:
В форме new.html.erb —
f.fields_for :items
Однако это создаст еще одну проблему для items_id, которую я не уверен, чего там пытаются достичь.
Ответ №3:
Вы получали эти ошибки, потому что у вас было hidden_field :name
в форме, которая не требуется при отправке формы. Я удалил это. Однако возникла проблема с сильными параметрами и наименованием флажков. Я исправил сильные параметры и сохранил название флажка описательным, чтобы вы могли видеть, как форма будет его генерировать.
Попробуйте этот код. Я смог создавать записи с помощью этого кода.
bills_controller.rb
private
def bill_params
params.require(:bill).permit(bill_items_attributes: [:quantity, :item_id])
end
new.html.erb
<%= form_for @bill do |f| %>
<% if @allItems %>
<% @allItems.each_with_index do |item, index| %>
<%= f.fields_for :bill_items do |s| %>
<tr class="table-success" scope="col-8">
<td class="text-primary"><%= s.label item.name %></td>
<td><%= check_box_tag "bill[bill_items_attributes][#{index}][item_id]", item.id, false, class: 'selectable' %> </td>
<td><%= s.number_field(:quantity, in: 1.0..100.0, step: 1) %></td>
<td><%= s.label :price, item.price %></td>
</tr>
<% end %>
<% end %>
<% end %>
<div class="form-group row justify-content-center">
<%= f.submit "Create Order with Selected items", class: "btn btn-secondary" %>
</div>
<% end %>