2016-10-16 7 views
0

私はレール付きのクイズアプリを書いています。私は質問作成用に多段階のフォームを持っています。Rails多段形式

モデル:

class Mcq < ApplicationRecord 
    attr_accessor :option_count 
    has_many :options, dependent: :destroy 
    belongs_to :quiz 

    accepts_nested_attributes_for :options 
    validates :question_text, presence: true 
end 

class Option < ApplicationRecord 
    belongs_to :mcq, optional: true 
    validates :option_text, presence: true 
end 

はスキーマ:

create_table "mcqs", force: :cascade do |t| 
    t.string "question_text" 
    t.boolean "required" 
    t.boolean "multiselect" 
    t.integer "quiz_id" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
end 


create_table "options", force: :cascade do |t| 
    t.string "option_text" 
    t.integer "mcq_id" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
end 

最初のページには、質問のセットアップのためのものであり、次のフィールドがあります。

  1. オプションカウント
  2. 必要(はい/いいえ)
  3. (マルチ/シングル)を選択することができるオプションなし

2ページ目はオプションのためのものであり、次のフィールドがあります。

  1. 質問テキスト
  2. ネストされたフォームのオプションのために

コントローラ:

class McqsController < ApplicationController 
    def new 
    session[:current_step] ||= 'setup' 
    session[:mcq_params] ||= {} 

    @current_step = session[:current_step] 
    @quiz = Quiz.find(params[:quiz_id]) 
    @mcq = Mcq.new(session[:mcq_params]) 

    if session[:current_step] == 'options' 
     @option_count = session[:mcq_params]['option_count'] 
     @option_count.times { @mcq.options.build } 
    end 
    end 

    def create 
    if params[:previous_button] 
     session[:current_step] = 'setup' 
     redirect_to new_quiz_mcq_path 
    elsif session[:current_step] == 'setup' 
     save_session(params[:mcq]) 
     redirect_to new_quiz_mcq_path 
    elsif session[:current_step] == 'options' 
     @mcq = Mcq.new(whitelisted_mcq_params) 
     @mcq.quiz_id = params[:quiz_id] 
     @quiz = Quiz.find(params[:quiz_id]) 
     if @mcq.save 
     session[:current_step] = session[:mcq_params] = nil 
     redirect_to quiz_new_question_path(@mcq.quiz_id) 
     else 
     @current_step = session[:current_step] 
     render :new 
     end 
    end 
    end 

    private 

    def whitelisted_mcq_params 
    params.require(:mcq) 
     .permit(:question_text, :multiselect, :required, options_attributes: [:option_text]) 
    end 

    def save_session(mcq_params) 
    session[:mcq_params][:option_count] = mcq_params[:option_count].to_i 
    session[:mcq_params][:required] = mcq_params[:required] 
    session[:mcq_params][:multiselect] = mcq_params[:multiselect] 
    session[:current_step] = 'options' 
    end 
end 

上記の解決策は機能しますが、コードは面倒で分かりにくいです。私はこれを見つけたrailscasts episodeは、よりクリーンな方法で何か似ています。私が続かないように自分のコードを更新しました:

class Mcq < ApplicationRecord 
    has_many :options, dependent: :destroy 
    belongs_to :quiz 

    attr_writer :current_step 
    attr_accessor :option_count 

    accepts_nested_attributes_for :options 
    validates :question_text, presence: true 

    def current_step 
    @current_step || steps.first 
    end 

    def steps 
    %w[setup options] 
    end 

    def next_step 
    self.current_step = steps[steps.index(current_step)+1] 
    end 

    def previous_step 
    self.current_step = steps[steps.index(current_step)-1] 
    end 

    def last_step? 
    current_step == steps.last 
    end 
end 

class McqsController < ApplicationController 
    def new 
    session[:mcq_params] ||= {} 
    @quiz = Quiz.find(params[:quiz_id]) 
    @mcq = Mcq.new(session[:mcq_params]) 
    @mcq.current_step = session[:mcq_step] 
    end 

    def create 
    @quiz = Quiz.find(params[:quiz_id]) 
    session[:mcq_params].deep_merge!(params[:mcq]) if params[:mcq] 
    @mcq = Mcq.new(session[:mcq_params]) 

    @option_count = session[:mcq_params]['option_count'] 
    @option_count.times { @mcq.options.build } 

    @mcq.quiz_id = params[:quiz_id] 
    @mcq.current_step = session[:mcq_step] 

    if params[:previous_button] 
     @mcq.previous_step 
    elsif @mcq.last_step? 
     @mcq.save if @mcq.valid? 
    else 
     @mcq.next_step 
    end 
    session[:mcq_step] = @mcq.current_step 

    if @mcq.new_record? 
     render "new" 
    else 
     session[:mcq_step] = session[:mcq_params] = nil 
     redirect_to edit_quiz_path(@mcq.quiz_id) 
    end 
    end 
end 

しかし、2ページ目が表示されるたびに、オプションのフィールドの一切が2倍またはQUESTION_TEXTのための無効なエントリフィールドのみの場合に示されています。オプションを正しく表示するにはどうすればよいですか?私は私の最初の解決策と一緒に行かなければならないのですか?私はレールが新しく、ベストプラクティスについてあまり知らない。

編集:あなたが中に見えるかもしれ

new.html.erb

<div class="sub-heading">Add a Multiple Choice Question:</div> 

<%= render "mcq_#{@mcq.current_step}", quiz: @quiz, mcq: @mcq %> 

_mcq_setup.html.erb

<div class="form-container"> 
    <%= form_for [quiz, mcq] do |f| %> 

    <div class="form-row"> 
     <div class="response-count">How many options should the question have?</div> 
     <%= f.select(:option_count, (2..5)) %> 
    </div> 

    <div class="form-row"> 
     <div class="response-count">How many options can be selected?</div> 

     <div class="option"> 
     <%= f.radio_button :multiselect, 'false', checked: true %> 
     <%= f.label :multiselect, 'Just One', value: 'false' %> 
     </div> 

     <div class="option"> 
     <%= f.radio_button :multiselect, 'true' %> 
     <%= f.label :multiselect, 'Multiple', value: 'true' %> 
     </div> 
    </div> 

    <div class="form-row"> 
     <div class="response-count">Is the question required?</div> 

     <div class="option"> 
     <%= f.radio_button :required, 'true', checked: true %> 
     <%= f.label :required, 'Yes', value: 'true' %> 
     </div> 

     <div class="option"> 
     <%= f.radio_button :required, 'false' %> 
     <%= f.label :required, 'No', value: 'false' %> 
     </div> 

    </div> 
    <%= f.submit "Continue to the Next Step" %> 
    <% end %> 
</div> 

_mcq_options.html.erb

<%= form_for [quiz, mcq] do |f| %> 

    <%= f.label :question_text, 'What is your question?' %> 
    <%= f.text_field :question_text %> 

    <%= f.fields_for :options do |option_fields| %> 
    <%= option_fields.label :option_text, "Option #{option_fields.options[:child_index] + 1}:" %> 
    <%= option_fields.text_field :option_text %> 
    <% end %> 

    <%= f.hidden_field :multiselect %> 
    <%= f.hidden_field :required %> 

    <%= f.submit "Add Question" %> 
    <%= f.submit "Back to previous step", name: 'previous_button' %> 
<% end %> 
+0

ビューを表示すると役立つ場合があります。 – SteveTurczyn

+0

ビューを追加するための質問を編集しました。 – meris1889

答えて

0

の方向。これを使用すると、ステートマシンの状態としてステップを使用して、与えられた状態(state :first_gear, :second_gear doにあるhere)にのみ有効な検証を定義する能力を使用して、最初に2番目のステップで必要なフィールドは不要です。また、現在のステップの複雑なチェックを避けることができます(状態はモデル内で保持されるため)、将来的にはさらに多くのステップで拡張が容易になります。

+0

ありがとうございますが、私は追加のプラグインや宝石を使用せずにこれをしたいと思います。 – meris1889

+0

あなたはほんの少しのステップがある限り、[条件付き検証](http://guides.rubyonrails.org/active_record_validations.html#using-a-symbol-with-if-and)を使って同じトリックを検証することができます - なし)。 –