Rails Wicked多步形式 - param缺失或者值为空与未允许的参数

时间:2016-12-08 18:03:08

标签: ruby-on-rails strong-parameters wicked-gem

我正在关注this tutorial使用Wicked gem创建一个多步形式。每个用户都有一个答案(存储一组问题答案的模型),我有一个QuestionnaireController,可以逐步解决用户将回答并存储在答案中的问题。到目前为止,我只有两个步骤,每个步骤都有一个问题(答案表上的布尔列)。当我逐步完成并回答每个问题时,一切都很完美,但是当我提交的时候我没有得到任何价值:

  

param丢失或值为空:回答

我的代码......

answer.rb:

class Answer < ApplicationRecord
  belongs_to :user

  cattr_accessor :questionnaire_steps do
    %w(step_one step_two)
  end

  attr_accessor :current_step #stores the current questionnaire step

  validates :user_id, presence: true

  with_options if: -> { required_for_step?(:step_one) } do |step|
    step.validates :question_one, inclusion: [true, false]
  end
  with_options if: -> { required_for_step?(:step_two) } do |step|
    step.validates :question_two, inclusion: [true, false]
  end

  def required_for_step?(step)
    # All fields are required if no questionnaire step is present
    return true if current_step.nil?
    # All fields from previous steps are required if the
    # step parameter appears before or we are on the current step
    return true if self.questionnaire_steps.index(step.to_s) <= self.questionnaire_steps.index(current_step)
  end
end

answers_controller.rb:

class AnswersController < ApplicationController
  before_action :setup

  def setup
    @user = current_user
  end

  def show
    @answer = @user.answer
  end

  def new
    @answer = Answer.new
    @answer = @user.build_answer
    @answer.save(validate: false)
  end

  def create
    @answer = @user.answer
    redirect_to questionnaire_path(@answer, Answer.questionnaire_steps.first)
  end
end

questionnaire_controller.rb:

class QuestionnaireController < ApplicationController
  include Wicked::Wizard

  before_action :setup

  steps *Answer.questionnaire_steps

  def setup
    @user = current_user
  end

  def show
    @answer = @user.answer
    render_wizard
  end

  def update
    @answer = @user.answer
    @answer.update_attributes(answer_params(step))
    render_wizard @answer
  end

  private

  def answer_params(step)
    permitted_attributes = case step
      when "step_one"
        [:question_one]
      when "step_two"
        [:question_two]
    end

    params.require(:answer).permit(permitted_attributes).merge(current_step: step)
  end
end

step_one.html.erb:

<div id="questionnaire" class="container-fluid well inline-headers">
  <%= form_for @answer, method: :put, url: wizard_path do |f| %>
  <div class="row">
    <% if f.object.errors.any? %>
      <div id="error_explanation" class="alert alert-dismissible alert-danger" >
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
        <ul>
          <% f.object.errors.each do |attribute, message| %>
            <%= content_tag :li, f.object.errors.full_message(attribute, message), :id => "error_#{attribute}" %>
          <% end %>
        <ul>
      </div>
    <% end %>
  </div>
  <div class="row">
    <div class="col-md-8 form-group">
      <p>Are you any good at this?</p>
    </div>
    <div class="col-md-4 form-group">
      <%= label_tag(:question_one, "Yes") %>
      <%= f.radio_button :question_one, true %>
      <%= label_tag(:question_one, "No") %>
      <%= f.radio_button :question_one, false %>
    </div>
  </div>
  <div class="row">
    <div class="col-md-4 col-md-offset-8 form-group">
      <p><%= f.submit "Save & Continue", class: "btn btn-warning" %></p>
    </div>
  </div>
  <% end %>
</div>

routes.rb(诚然,我试着用这些来掩饰这些ID,请随意羞辱我这样做):

resources :answers, only: [:show, :new, :create]
  get 'user/questionnaire', to: 'answers#show'
  get 'user/questionnaire/new', to: 'answers#new'
  post 'user/questionnaire/new', to: 'answers#create'

resources :questionnaire

当我选择一个选项并提交时,它会保存到数据库并重定向到下一步,但是如果我在没有选择选项的情况下提交,那么当我希望获得验证错误时,我会得到param错误。从服务器日志:

  

通过QuestionnaireController处理#update更新为HTML参数:   {&#34; UTF8&#34; = GT;&#34;&#34 ;,   &#34; authenticity_token&#34; = GT;&#34; J45sG / YIqTaBECgBqNLr9Ys3rJewDK78d / cKHWFHYEIzAaOiTXhgH6evPZKl5LhnSAMnQnA94CXonqriyj0fCQ ==&#34 ;,   &#34;提交&#34; =&gt;&#34;保存&amp;继续&#34;,&#34; id&#34; =&gt;&#34; step_one&#34;}

我尝试了一些可能的修复方法,包括从require(:answer)中移除params.require(:answer).permit(permitted_attributes).merge(current_step: step),这会让我得到我期望的验证错误,但不允许保存有效值。在那种情况下,我仍然在服务器日志中收到以下验证错误:

  

开始PUT&#34; / questionnaire / step_one&#34; for :: 1 at 2016-12-08   23:26:14 +0545由QuestionnaireController处理#update为HTML
  参数:{&#34; utf8&#34; =&gt;&#34;���&#34;,   &#34; authenticity_token&#34; = GT;&#34; RWAHfu0BE82ik6gTChh3nmtuyOUa5j0qiz4H03ejIkRR78jHVnHa5IQsvYAHLiQMqFpDMNrXc / MUV6cs3NldDw ==&#34 ;,   &#34;回答&#34; =&gt; {&#34; question_one&#34; =&gt;&#34; true&#34;},&#34;提交&#34; =&gt;&#34;保存和放大;继续&#34 ;,   &#34; id&#34; =&gt;&#34; step_one&#34;} ... SQL ...未经许可的参数:utf8,_ method,   authenticity_token,answer,commit,id

非常感谢帮助新秀。

更新:我修改了我的路线以匹配教程(嵌套),认为这可能与它有关(即可能没有得到答案ID),但我仍然得到参数丢失错误。

resources :answers, only: [:show, :new, :create] do
    resources :questionnaire, only: [:show, :update], controller: 'questionnaire'
  end
  get 'user/questionnaire', to: 'answers#show'
  get 'user/questionnaire/new', to: 'answers#new'
  post 'user/questionnaire/new', to: 'answers#create'

我还尝试在提交之前添加hidden_​​field_tag,如下所示:

<%= hidden_field_tag(:answer, @answer) %>

但后来我得到了:

  

未定义的方法`permit&#39;对于#

可能是因为当强参数声明需要哈希值时,hidden_​​field_tag将@ answer.attributes作为字符串传递。从服务器:

  

开始PUT&#34; / answers / 46 / questionnaire / step_one&#34; for :: 1 at   2016-12-12 13:25:19 +0545由QuestionnaireController处理#update   作为HTML参数:{&#34; utf8&#34; =&gt;&#34;���&#34;,   &#34; authenticity_token&#34; = GT;&#34; wlLpKoMvqgyfwB5gyP / qubR4ZpZa6jm9KHeMuiwJTc6IOJZi9PgiSegvF + OzlN09ctEuxuxiAuRs + / B2InRGhA ==&#34 ;,   &#34;回答&#34; =&gt;&#34; {\&#34; id \&#34; =&gt; 46,\&#34; user_id \&#34; =&gt; 4,\& #34; question_one \&#34; = GT;零,   \&#34; question_two \&#34; = GT;零,   \&#34; percentage_complete \&#34; = GT;#,   \&#34;已完成\&#34; =&gt; false,\&#34; created_at \&#34; =&gt;周一,2016年12月12日02:12:31美国东部时间   -05:00,\&#34; updated_at \&#34; =&gt;周一,2016年12月12日02:12:31 EST -05:00}&#34;,&#34; commit&#34; =&gt; ;&#34;保存&amp;继续&#34;,&#34; answer_id&#34; =&gt;&#34; 46&#34;,&#34; id&#34; =&gt;&#34; step_one&#34;}

请帮忙!

2 个答案:

答案 0 :(得分:0)

问题仍然有效吗?

我想把它放在评论中,但不能。 我认为问题在于vaildations。它会检查您是否在相关字段中输入了值,并在您没有​​输入时抛出错误。如果从模型中删除step.validates会发生什么?

答案 1 :(得分:0)

我将params.require更改为params.fetch并且有效(验证会被恰当地触发,我也可以成功完成有效值的步骤)。