【问题标题】:Complex Rails Form Best Practices复杂 Rails 表单最佳实践
【发布时间】:2021-03-13 19:12:14
【问题描述】:

我有一个相对复杂的表单,我正在尝试有效地编写代码。大多数嵌套表单的在线示例都处理非常清晰的层次关系,我的没有。

下面是数据模型。表单的基本工作是创建一个“工作条目”记录,同时创建一个新的“实体”记录 - 这是一个人。这种形式产生了几种关系。

已经创建了一个“作业”。在用户点击此表单之前,作业有一对多的“问题”。但是,他们必须填写问题的“答案”。他们还从许多预先创建的“工作角色”中选择一种。

问题是如何为所有这些相互关联的模型利用“form_with”和“fields_for”。

我的假设是放弃内置帮助程序,只使用 form_tag 并手动将所有内容组合在一起。但也许有一种“正确”的方式来滚动不一定遵守亲子关系的表格?在我的示例中,由于许多子对象已经有记录,因此没有纯粹的顶级对象开始,但也许我错了,实体应该是起点?

  • 实体 has_many Job_Roles
  • 实体 has_many Job_Entries
  • Job 有很多 Job_Roles
  • Job has_many Job_Entries
  • 工作有_许多问题
    • 问题有很多答案
      • 答案属于实体
  • 机构 has_many Job_Entries 等等……

【问题讨论】:

    标签: ruby-on-rails forms


    【解决方案1】:

    没有必要放弃内置的 helper:Rails 已经考虑过这一点,它被称为 nested forms

    这是一个例子:

    <%= form_with model: @job do |f| %>
      Job entries:
      <ul>
        <%= f.fields_for :job_entries do |je_form| %>
          <li>
            <%= je_form.label :kind %>
            <%= je_form.text_field :kind %>
     
            <%= je_form.label :street %>
            <%= je_form.text_field :street %>
            ...
          </li>
        <% end %>
      </ul>
    <% end %>
    

    您可以使用fields_for 嵌套任意数量的子表单。不要忘记在父模型中使用 accepts_nested_attributes_for

    【讨论】:

    • 哦,我对嵌套表单了如指掌,并且尝试了许多不同的方法。这里的问题是嵌套表单假定父子子,是吗?
    • @ScottTallarida 不,我不认为他们只接受亲子形式。如果您将accepts_nested_attributes_for 设置为父级(假设定义了belongs_to),它也应该可以工作。
    【解决方案2】:

    Mike 提出的嵌套表单是解决问题的一种方式。没关系 - 但对于复杂的表单,有很多验证,它可能不是最好的解决方案)。您可以考虑改用 FormObject 模式。

    FormObject 是一个简单的 ruby​​ 类,你可以将它保存在 Forms 文件夹中,如下所示:

    class JobEntryForm
      include ActiveModel::Model
    
      attr_accessor :customer_id, :agency_id, :name, :question_text #you can use atributes from different models
    
      validates :customer_id, presence: true #you can validate yu attributes as you want - your in necessity to use model validation
    
      def initialize(attributes:)
        @customer_id = attributes[:customer_id]
        @agency_id        = attributes[:agency_id]
        @name          = attributes[:name]
        @question_text = attributes[:question_text]
      end
      
    
      #implement whatever you need
    end
    

    比你的控制器: @form = JobEntryForm.new

    你的看法:

    <%= form_for @form do |f| %>
      <%= f.label :customer_id, 'Customer' %>:
      <%= f.text_field :customer_id %>
      ...
      <%= f.submit %>
    <% end %>
    

    并且 - 最后 - 在您的控制器创建方法中:

    def create
      @form = CreateJobEntry.new.call(attributes: form_params) #service object to keep your controller clean. 
    end
    

    【讨论】:

      猜你喜欢
      • 2011-07-21
      • 2012-01-01
      • 1970-01-01
      • 2015-10-24
      • 2017-09-21
      • 2012-07-19
      • 1970-01-01
      • 1970-01-01
      • 2012-01-24
      相关资源
      最近更新 更多