Rails邪恶的多步表单 - param丢失或值为空vs不允许的参数

问题描述:

我正在关注this tutorial以使用Wicked gem创建多步表单。每个用户都有一个答案(存储对一组问题的答案的模型),并且我有一个QuestionnaireController,用于逐步解答用户将回答并存储在答案中的问题。到目前为止,我只有两个步骤,每个步骤都有一个问题(答案表上的布尔列)。当我步,并回答每一个问题的一切完美的作品,但是当我提交没有值的获取:Rails邪恶的多步表单 - param丢失或值为空vs不允许的参数

参数是丢失或为空值:答案

我的代码...

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 

当我选择一个选项并提交时,它保存到数据基地和重定向到下一步,但是,如果我提交时没有选择一个选项,我得到的参数缺少错误,当我预计会得到验证错误。从服务器日志:

处理由QuestionnaireController#更新为HTML参数: { “UTF8”=> “”, “authenticity_token”=> “J45sG/YIqTaBECgBqNLr9Ys3rJewDK78d/cKHWFHYEIzAaOiTXhgH6evPZKl5LhnSAMnQnA94CXonqriyj0fCQ ==”, “提交” =>“保存&继续”,“ID” =>“step_one”}

我已经尝试了一些潜在的修复,包括params.require(:answer).permit(permitted_attributes).merge(current_step: step)去除require(:answer),这让我验证错误,我期待但然后不允许保存有效的值。在那种情况下我仍然得到验证错误,在服务器日志如下:在2016年12月8日23时26分14秒 处理0545开始PUT“/问卷/ step_one”为:: 1

通过QuestionnaireController#更新为HTML
参数:{ “UTF8”=> “”, “authenticity_token”=> “RWAHfu0BE82ik6gTChh3nmtuyOUa5j0qiz4H03ejIkRR78jHVnHa5IQsvYAHLiQMqFpDMNrXc/MUV6cs3NldDw ==”, “回答”=> { “question_one”=>“真“},”commit“=>”保存&继续“, ”id“=>”step_one“} ... 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) %> 

但后来我得到:

未定义的方法'许可证”为#

可能是因为hidden_​​field_tag将@ answer.attributes作为字符串传递给强壮标准ameter声明期望散列。从服务器:

发起者QuestionnaireController#更新 为HTML参数PUT “/答案/ 46 /问卷/ step_one” 为:: 1在 2016年12月12日13时25分19秒0545的处理: { “UTF8”=> “”, “authenticity_token”=> “wlLpKoMvqgyfwB5gyP/qubR4ZpZa6jm9KHeMuiwJTc6IOJZi9PgiSegvF + OzlN09ctEuxuxiAuRs +/B2InRGhA ==”, “回答”=> “{\” ID \ “=> 46,\” USER_ID \“=> 4,\”question_one \“=>无, \”question_two \“=>无, \”percentage_complete \“=>#, \”completed \“=> false,\”created_at \“ => 2016年12月12日星期一02:12:31 EST -05:00,\“updated_at \”=> 2016年12月12日星期一02:12:31 EST -05:00}“,”commit“=>保存&继续“,”answer_id“=>”46“,”id“=>”step_one“}

请帮忙!

我将params.require更改为params.fetch并且工作正常(验证适当触发,我也可以成功通过有效值的步骤)。

问题仍然有效吗?

我想把这个评论,但不能。 我认为问题是与vaildations。它会检查你是否在相关领域输入了一个值,并在没有时会抛出错误。如果从模型中删除step.validates,会发生什么情况?

+0

仍然有效,我想我解决了它。我需要验证,因此我将'params.require'更改为'params.fetch',这似乎工作(验证适当触发,我也可以成功通过有效值的步骤)。 – CChandler81