Сильная проблема с параметрами в рельсах 6 - PullRequest
1 голос
/ 12 июля 2020

У меня есть модель "многие ко многим" ProductCategory product_category (объединенная таблица) и У меня проблема с вложением параметра в ProductsController. Ошибка, которую я продолжаю получать, заключается в том, что это недопустимые параметры category_ids, но я вложил их в сильные параметры продукта.

Я сфотографировал важные части кода. Пожалуйста, взгляните и дайте мне знать, спасибо. Вот самая важная часть кода, я думаю:

<%= form_with(model: [:user, @product], local: true) do |f|%>
  <h4>Category</h4> 
  <div class="dropdown-trigger btn"> 
    <%= f.collection_select(:category_ids, Category.all, :id, :name) %>   
  </div>
  
  <h4>Product Name:</h4> 
  <%= f.text_field :name  %><br/>

  <h4>Product Price:</h4> 
  <%= f.number_field :price, value: @product.price ? '%.2f' % @product.price : nil, min: 0, step: 0.01 %>$<br/>

  <h4>Product Description:</h4> 
  <%= f.text_field :description  %><br/>
  <h4>Product Image (recommended)</h4> 
  <%= f.file_field :image  %><br/>

require в ProductsController:

def product_params
  params.require(:product).permit(:name, :price, :description, :image,  category_ids: [])
end

И соответствующие части Product и ProductCategory модель.

class Product < ApplicationRecord
  belongs_to :user
  has_many :product_categories
  has_many :categories, though: :product_categories

  has_one_attached :image
end

class ProductCategory < ApplicationRecord
  belongs_to :product
  belongs_to :category
end

class Category < ApplicationRecord
  belongs_to :user
  has_many :product_categories
  has_many :products, though: :product_categories
end

скриншот кода

1 Ответ

0 голосов
/ 12 июля 2020

Вы получаете сообщение об ошибке «unpermitted params category_ids», потому что вам сначала нужно объявить в своей модели продукта следующее:

accepts_nested_attributes_for :categories , allow_destroy: true

Как только это будет сделано, вы должны начать получать всю информацию о category_ids, действительно вложен в ваши параметры.

Однако я полностью рекомендую НЕ выполнять в ваших представлениях и партиалах запрос ActiveRecord к вашей БД. Например:

  <div class="dropdown-trigger btn"> 
    <%= f.collection_select(:category_ids, Category.all, :id, :name) %>   
  </div>

Это не рекомендуется. Вместо этого вы должны получить от вашего контроллера полный набор категорий. Единственная функция представления в этом случае - заполнить данные пользователем, выбрать категории, а затем после отправки отправить всю эту информацию обратно в контроллер. Вот и все. Не выполняет никаких запросов. Это правда, что вы можете это сделать. Я имею в виду, что это физически возможно сделать там в этом представлении или даже сделать это на помощнике (тоже неправильно, помощник должен выполнять дополнительные действия над ресурсами, уже загруженными или полученными от контроллеров), но MVC означает разделение обязанностей по нескольким причинам.

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

На products_controller.rb:

def edit
  @categories_to_assign = product_service.get_categories_to_assign(@product)
end

def product_service
 ProductService
end

def product_params
  params.require(:product).permit(:name, :price, :description, :image,  categories_to_assign: [])
end

На product_service.rb он получает категории:

def self.get_categories_to_assign(product)
  categories_scope.where.not(id: product.categories.map(&:id)).map do |category|
    ["#{category.name}", category.id]
  end
end

def self.categories_scope()
  Category
end

Затем при редактировании / новом представлении:

<%
  categories_to_assign = @categories_to_assign || []
%>

<% content_for :products_main_content do %>
  <div id="edit_product_content">
    <%= render partial: 'products/form', locals: {
        product: product,
        return_to: return_to,
        categories_to_assign: categories_to_assign
    } %>
  </div>
<% end %>

Затем на _form. html .erb partial:

<%
  categories_to_assign = local_assigns.fetch(:categories_to_assign, [])
%>

      <div class="panel panel-default">
        <div class="panel-heading">
          <h2 class="panel-title"><%= t('products.categories.title') %></h2>
        </div>
        <div class="panel-body">
          <div class="form-horizontal" id="categories_container" data-sjr-placeholder>
            <%= render partial: 'products/categories', locals: {f: f, categories_to_assign: categories_to_assign} %>
          </div>
        </div>
      </div>

И, наконец, на _categories. html .erb partial:

<%
  categories_to_assign = local_assigns.fetch(:categories_to_assign, [])
%>

  <% if categories_to_assign.present? %>
    <%= select_tag "#{f.object_name}[categories_to_assign][]", options_for_select(categories_to_assign), {id: "#{f.object_name}_categories_to_assign", include_blank: true, multiple: true, class: 'form-control', data: {placeholder: t('products.form.select_category')}} %>
  <% end %>

Как видите, общая идея заключается в передаче соответствующей информации от контроллера после того, как она была правильно получена в product_service (вы должны добавить ее), а затем она переходит в редактирование / новое представление, а затем оно, наконец, переходит во вложенные частичные файлы. Таким образом, все будет разделено по сферам ответственности.

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