【问题标题】:Rails simple form doen't pass params from inputRails 简单表单不从输入传递参数
【发布时间】:2021-04-16 00:03:01
【问题描述】:

我想显示 InvestorTypes 的列表(作为单选按钮),但在每种类型之前我应该​​能够添加该类型的说明。这是我所拥有的:

<%= simple_form_for(resource, as: resource_name, url: users_user_experience_level_path(resource_name), html: { method: :put }) do |f| %>
  <div class="form-inputs">
    <% User::USER_EXPERIENCE_LEVEL.each do |level| %>
    <b>Investor type <%= level %></b>
    <%= t("user.description.#{level}") %>
    <%= f.input :experience_level, collection: [level], as: :radio_buttons, label: false %>
    <% end %>
  </div>

  <div class="form-actions">
  <%= f.button :submit, 'Submit' %>
  </div>
<% end %>

这给了我预期的看法:

Investor type Beginner
Some explanation of what is going on
[checkobox] type Beginner

Investor type Expert
Some clarification of who is an expert and what ever you want to display here
[checkbox] type Expert

Investor type Institutional
Some clarification of who is an institutional client and some legal stuff
[checkbox] type Institutional

但是当按下提交按钮时,它不会将输入值(用户选择的单选框选择)传递给参数:

=> #<ActionController::Parameters {"experience_level"=>""} permitted: true>

[编辑]

class User < ApplicationRecord
  USER_EXPERIENCE_LEVEL = %w[institutional beginner expert].freeze
end

【问题讨论】:

  • 我敢打赌,如果您单击最后一个单选按钮,它就会起作用。现在我认为问题是您正在创建一堆同名的单选按钮,并且它按名称自上而下组合它们,因此最后一个框获胜。通常单选框会创建为&lt;%= f.input :experience_level, collection: User::USER_EXPERIENCE_LEVEL, as: :radio_buttons, label: false %&gt;,而不是您现在使用的循环。
  • @engineersmnky 你是对的,如果我选择最后一个就可以了。我知道标准方法是什么,但如果我使用它,每次初始迭代后我都会有 3 个输入。你知道如何解决它吗?

标签: ruby-on-rails


【解决方案1】:

在我看来,您使用的简单形式是错误的。简单表单中的“集合”输入期望获得完整的选项列表,而不仅仅是一个选项。

循环方式是为每个体验级别创建一个组,每个组中只有一个按钮。所以它可能在视觉上看起来是正确的,但它并没有按照你想要的方式运行。相反,您希望为体验级别创建一组单选按钮,以便每个按钮更改体验级别的值。

因为您在执行此操作时需要对外观进行大量自定义,所以简单表单可能不是一个很好的用途,相反您应该回退到普通的 Rails 表单助手。

【讨论】:

  • 我猜你是对的,但是一个常规的表单助手会是什么样子呢?
【解决方案2】:

您想将一个块传递给f.input 以获取简单的表单包装器,然后使用较低级别的rails helpers

<%= simple_form_for(resource, as: resource_name, url: users_user_experience_level_path(resource_name), html: { method: :put }) do |f| %>
  <div class="form-inputs">
    # adds the simple form wrapper 
    <%= f.input :experience_level do %>
      # iterates across the options and yields a input builder to each iteration
      <%= f.collection_checkboxes(:experience_level, User::USER_EXPERIENCE_LEVEL, :value_method, :label_method) do |cb| %>
        # There are three special methods available: 
        # object, text and value, 
        # which are the current item being rendered, its text and value methods, respectively.
        <%= t("user.description.#{cb.text}") %>
        <%= cb.check_box %>
      <% end %>
    <% end %> 
  </div>

  <div class="form-actions">
    <%= f.button :submit, 'Submit' %>
  </div>
<% end %>

如果您实际上没有模型,您可以使用 #itself 遍历平面数组:

<%= f.collection_checkboxes(:experience_level, User::USER_EXPERIENCE_LEVEL, :itself, :itself) do |cb| %>

或成对数组:

<%= f.collection_checkboxes(:experience_level, User::USER_EXPERIENCE_LEVEL.zip(User::USER_EXPERIENCE_LEVEL), :first, :last) do |cb| %>

甚至是一个结构体。

【讨论】:

  • 在所有三种情况下,我都会遇到相同的错误:ActionView::Template::Error (undefined method collection_select' for nil:NilClass):
  • 啊,我编辑了答案。我猜 f.input 不会对块产生任何影响。
  • 好的,这些是复选框(多选)而不是单选按钮。我已将其更改为collection_radio_buttons,最后更改为cb.radio_button。但是我仍然需要一个标签,每个单选按钮的某种&lt;%= cb.check_box, "Investor type #{cb.text}" %&gt;。知道该怎么做吗?
  • 这真的取决于User::USER_EXPERIENCE_LEVEL 是什么。如果您需要有单独的标签和值,您可以使用对数组、结构甚至模型。您可以使用&lt;%= cb.label %&gt; 输出标签。见api.rubyonrails.org/v6.1.3/classes/ActionView/Helpers/…
  • 这可能有助于解释您尝试实现的业务逻辑和数据结构。
猜你喜欢
  • 2011-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-11
  • 2010-11-28
  • 1970-01-01
  • 2020-06-14
相关资源
最近更新 更多