【问题标题】:form_for collection_select not showing saved selections on editform_for collection_select 在编辑时不显示保存的选择
【发布时间】:2020-03-28 03:53:06
【问题描述】:

我有一个用于新建和编辑的表单。表格中包含产品名称、描述等内容。

此外,用户可以从嵌套下拉列表 (collection_select) 中选择一个项目,也可以创建一个新项目。在“新”表单上工作正常 - 所有条目和选择都保存。

当用户编辑保存的产品时,表单会预加载该项目的所有已填写条目,但不会在 collection_select 中预加载他们的原始选择。

并且,如果用户想要编辑该项目并决定创建一个新项目而不是先前选择的 collection_select 项目,则会出现错误,说明该产品已使用该化学组创建。 对于这种双重困境的任何帮助将不胜感激。我是 RoR 的新手,我确定我在某处遗漏了一些东西。

这是我的表格

<%= render partial: 'layouts/errors', locals: {object: @product} %>

<%= form_for(@product) do |f| %>
    <div>
        <%= f.label :name %><br>
        <%= f.text_field :name %><br>
    <div>
    <div>
        <%= f.label :active_ingredient %><br>
        <%= f.text_field :active_ingredient %><br>
    <div>
    <div>
        <%= f.label :description %><br>
        <%= f.text_area :description %><br>
    </div>
    <div>
        <%= f.label :image %><br>
        <%= f.file_field :image %><br>
    </div>
    <div>
        <p>Select a Chemical Group:</p>
        <%= f.collection_select :chem_group_id, ChemGroup.all, :id, :name, include_blank: 'Select One', selected: @product.chem_group, value: @product.chem_group.name %>
    </div>
    <div>
        <p>Or, create a new Chemical Group:</p>
        <!-- NESTED FORM! User writing attributes for another object. Use fields_for -->
        <%= f.fields_for :chem_group do |cg| %>
            <%= cg.label :name %>
            <%= cg.text_field :name %>
        <% end %>
    </div>
    <div>
        <p>Select an Application Area:</p>
        <%= f.collection_select :application_area_id, ApplicationArea.all, :id, :area_name, include_blank: 'Select One', selected: @product.application_area, value: @product.application_area.area_name %>
    </div>
    <div>
        <p>Or, create a new Application Area:</p>
        <!-- NESTED FORM! User writing attributes for another object. Use fields_for -->
        <%= f.fields_for :application_area do |aa| %>
            <%= aa.label :area_name %>
            <%=aa.text_field :area_name %>
        <% end %>
    </div>
    <br>
    <%= f.submit "Save" %>
<% end %>

这是我的模型

class Product < ApplicationRecord
  belongs_to :chem_group
  belongs_to :application_area
  belongs_to :user #admin creator
  accepts_nested_attributes_for :chem_group #tells the model to accept chem_group attributes from cg nested form in new product form
  accepts_nested_attributes_for :application_area

  validates :active_ingredient, presence: true
  validates :application_area, presence: true
  validates :description, presence: true
  validates :name, presence: true
  validate :not_a_duplicate #checking for what we DON'T WANT

  def chem_group_attributes=(attributes)
    self.chem_group = ChemGroup.find_or_create_by(attributes) if !attributes['name'].empty?
    self.chem_group
  end

  def application_area_attributes=(attributes)
    self.application_area = ApplicationArea.find_or_create_by(attributes) if !attributes['area_name'].empty?
    self.application_area
  end

  #if there is already a product with that name && chem_group, give error
  def not_a_duplicate
    #calling the instance of the attribute [string/integer: key]
      if Product.find_by(name: name, chem_group_id: chem_group_id)
        errors.add(:name, 'has already been created for that Chemical Group')
      end
    end
end

这是我的控制器

class ProductsController < ApplicationController

    def new
        if logged_in?
            @product = Product.new
            1.times {@product.build_chem_group} #for the nested form. Builds the chem_group attributes
            @product.build_application_area
        else
            flash[:error] = "Sorry, you must be logged in to create a new product."
            redirect_to products_path
        end
    end

    def create
        @product = Product.new(product_params)
        @product.user_id = session[:user_id] #bc product belongs_to user. user_id required from model
        if @product.save #validation
            # @product.image.purge
            # @product.image.attach(params[:product][:image]) # allows image to be replaced if user changes image
            redirect_to product_path(@product)
        else
            @product.build_chem_group
            @product.build_application_area
            render :new
        end
    end

    def edit
        find_product
        1.times {@product.build_chem_group}
        if @product.user != current_user
            flash[:error] = "Sorry, you can only edit your own products"
            redirect_to products_path
        end
    end

    def update
        find_product
        if @product.update(product_params)
            redirect_to product_path(@product)
        else
            render :edit
        end
    end

    private

    def product_params
        params.require(:product).permit(:name, :description, :active_ingredient, :image, :chem_group_id, :application_area_id, chem_group_attributes: [:id, :name], application_area_attributes: [:id, :area_name])
        #chem_group_id and chem_group_attributes [:name] is permitting elements from new product form
    end

    def find_product
        @product = Product.find_by(id: params[:id])
    end

end

【问题讨论】:

  • 如果从collection_select 中删除selectedvalue 选项会怎样?

标签: ruby-on-rails nested-form-for collection-select


【解决方案1】:

阅读您提供的表格:

  1. 如果您正在编辑产品,该系列应显示以前的 选择chem_group,并填写创建应填写 它的名字,因为它是同一个关联对象。不是因为你 弄乱了selectedvalue 选项。 selectedcollection_select 这样的应该指向 id 而不是反对。 喜欢:selected: @product.chem_group.id 但真的没必要 这里。您应该直接跳过这些选项(selected nad value 因为您正在为@product 使用表单生成器)。
  2. 在有人尝试用新值编辑chem_group 后填写 真正的混乱开始了,因为在选择字段中仍然有一个 id 指向以前的chem_groupchem_group_attributes 只有:name我现在猜Rails会通过 chem_group_id 并且您的自定义验证将失败,因为它是 现有对象(看起来这个验证永远不会让你 保存对象而不更改chem_group,因为它显然 现有 - 您正在编辑它!)

试试看:

  1. 更改或删除自定义验证。或检查是否在 验证不是您正在编辑但之前保存的验证
  2. 默认禁用其中一个输入(<%= cg.text_field :name, disabled: @product.chem_group.present? %>)并切换它们 取决于用户在做什么 - 选择或输入(例如,使用 复选框和 JS onchange)。这是为了确定你是什么参数 路过。
  3. 也:chem_group_attributes: [:id, :name] 拜托你没有通过 这里有一个 id - 删除它。
  4. def chem_group_attributes=(attributes) 覆盖是危险的。一世 知道你想要得到什么,但它可能不是最重要的 实现这一目标的绝妙方式。

通常您也可能希望看到:https://select2.org/tagging。它仍然与您在这里的复杂逻辑相同,并且一些 JS 可以使标记在创建新的关联对象时工作得很好,但它看起来更好,具有更好的 UX,而且我一直在那里 - 我通常将它与 accept_nested_attributes_for 一起使用,你可以打我的例子。

【讨论】:

  • 感谢您的意见,@blazpie!我会试一试并报告。
  • @TracyReuther,accept 如果有帮助,请回答
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多