如何填充 Rails 6 表单中的隐藏字段,该表单循环遍历一个 table 并将答案存储在另一个 table 中?

How do you populate a hidden field in a Rails 6 form that loops through one table and stores answers in another table?

我正在尝试创建性格测试。

我有一个问题 table 看起来像这样


       ID  | Question      |
    ----------------------------
        1  | How likely would you etc... 


结果 table 看起来像这样

       ID  | Answer      | Question_ID | User_Id
    ------------------------------------------------
        1  |  1          |  1          |   1

我有 68 个问题要循环,我想在我的结果中存储答案(从 1 到 10 的整数)table。

如何创建将数据保存到结果中的表单 table?

我在填充结果 table 的答案栏时遇到问题。

这是我的。没用。

<%= form_with(model: @result, local: true) do |form| %>
  <% @questions.each do |question| %> 
    <div>
      <h4><%= question.id %>. <%=question.question %></h4><br /> 
      <div class="hidden-field">
        <%= form.hidden_field :question_id, value: question.id %>
      </div>
      <div class="field">
        <%= form.number_field :answer, placeholder:'Please answer on a scale from 1 to 10' %>
      </div>
    </div> 
  <% end %>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

在我的控制器中,我有一个家庭控制器(用于显示主页)

class HomeController < ApplicationController
  def index 
      @questions = Question.all.order(:created_at)
      @user = User.new
      @result = Result.new
  end
end

我也有我的结果控制器

class ResultsController < ApplicationController
  before_action :set_result, only: [:show, :edit, :update, :destroy]

  def new
    @result = Result.new
  end

  def create
    @result = Result.new(result_params)
  end

  private
    def set_result
      @result = Result.find(params[:id])
    end

    def result_params
      params.require(:result).permit(:answer, :user_id, :question_id)
    end
end

问题显示得很好。我什至可以存储数据,但只保存了一条记录,它只用 68 填充 question_id 列并留下答案列 NULL

我做错了什么?

一些让您朝着正确方向前进的提示:

User.new是个问题。

新用户没有ID,所以他们不存在的ID无法保存到数据库中。

我注意到您的表单没有 user_id 字段。这很好。由于所有记录都相同,一旦您首先将可行的 @user 记录保存到数据库中,您只需将 @user.id 设置为控制器中的记录:

`@record.create(user_id:@user.id,question_id:results_params[:question_id])

此外,如果它不是表单中的字段,则您不需要在允许的参数中包含 :user_id。这为您打开了形成价值注入的大门:

    def result_params
      params.require(:result).permit(:answer, :question_id) # delete :user_id
    end

您想一次创建多条记录

Totally doable。你不能使用 @result = Result.new(result_params) 因为这只会创建一个 @result.

您需要在创建操作中遍历 params[:results] 并在每个操作上调用 @result.create()

有一天的专业提示:您实际上可以将其委托给模型中的一个方法:Result.batch_create(params)

查看您的表单提交参数以获得提示

在创建操作的顶部放置一个调试器(我使用 byebug or pry)调用。这将停止您的终端输出并在您的服务器内为您提供一个控制台。

您应该能够在您的终端中看到刚刚在您的服务器登录中提交的参数(这取决于您使用的是什么服务器)。

或者,一旦调试器暂停了服务器并为您提供了一个控制台,只需键入 params 即可查看正在发送的内容。您应该会看到一整套结果,而不仅仅是一个。

您已向重复者敞开心扉

每次自动创建一个新的 @result 意味着您的数据库可能有很多重复值。

我认为您应该首先检查 user_idquestion_id 是否与您在表格中的记录相匹配,然后相应地更新或创建记录。

简而言之,此方法看起来像这样(再次记住,我们需要在每个表单结果参数的循环中执行此操作):

params[:results].each do |result_param|
  if Result.where(user_id: result_param[:user_id], question_id: result_param[:question_id]).exists?
    result = Result.where(user_id: result_param[:user_id], question_id: result_param[:question_id])
  else
    result = Result.new(user_id: result_param[:user_id], question_id: result_param[:question_id])
  end

但是,这是 非常糟糕的代码 当然 Rails 为您提供了一个方法:

result = Result.where(user_id: result_param[:user_id], question_id: result_param[:question_id]).first_or_create

Be sure to read this good article about .first_or_create

TL;DR你有几个核心问题需要探索才能完成这项工作,但你走在正确的轨道上。

所以在阅读了这篇文章之后,我有了可以工作的代码。 This post 与@chiperific 回复一起提供了巨大帮助

我将此表格放入我的 results/new.html.erb 文件

    <%= form_with(model: result, local: true) do |form| %>
      <% @questions.each do |question| %> 
        <%= fields_for "result[]", result do |result_field| %>
          <h4><%= question.id %>. <%=question.question %></h4><br /> 
           <%= result_field.hidden_field :question_id, value: question.id %>
           <%= result_field.number_field :answer, placeholder:'Please answer on 
            a scale from 1 to 10' %>
        <% end %>
      <% end %>
      <div class="actions">
        <%= form.submit %>
      </div>
   <% end %>

我把它放在我的结果控制器中

class ResultsController < ApplicationController
  before_action :set_result, only: [:show, :edit, :update, :destroy]

  def new
    @result = Result.new
    @questions = Question.all.order(:created_at)
  end

  def create
    params[:result].each do |result_param|
     result = Result.new(result_param.permit(:answer, :user_id, :question_id))
    end
  end

  private
    def set_result
      @result = Result.find(params[:id])
    end
end

关键的见解是我需要遍历我的结果并为我的每一个结果创建一个新的结果实例。

我删除了主控制器和主视图页面并将 routes.rb 文件更改为 root 'results#new'

我没有解决重复记录的问题(这是非常有效的)所以我知道我的代码需要一些重构,但这段代码回答了我最初的问题(我非常愿意接受反馈)