我尝试在本文后面实现多步骤表单:https://medium.com/@nicolasblanco/developing-a-wizard-or-multi-steps-forms-in-rails-d2f3b7c692ce
问题是我的模型有关系,并且在显示错误的步骤3中无法识别这些关系,请参阅下面的完整代码和错误消息:
class Evaluation < ApplicationRecord
belongs_to :user
belongs_to :teacher
belongs_to :school
belongs_to :subject
has_many :evaluation_tags
has_many :tags, through: :evaluation_tags
accepts_nested_attributes_for :evaluation_tags
validates :teacher_id, presence: true
validates :subject_id, presence: true
validates :school_id, presence: true
validates :user_id, presence: true
validates :rating, presence: true
end
module Wizard
module Evaluation
STEPS = %w(step1 step2 step3).freeze
class Base
include ActiveModel::Model
attr_accessor :evaluation
delegate *::Evaluation.attribute_names.map { |attr| [attr, "#{attr}="] }.flatten, to: :evaluation
def initialize(evaluation_attributes)
@evaluation = ::Evaluation.new(evaluation_attributes)
end
end
class Step1 < Base
validates :teacher_id, presence: true
end
class Step2 < Step1
validates :subject_id, presence: true
end
class Step3 < Step2
validates :school, presence: true
validates :user, presence: true
validates :rating, presence: true
end
end
end
class EvaluationsController < ApplicationController
before_action :complete_sign_up, except: [:index]
# before_action :load_evaluation_wizard, except: %i(validate_step)
before_action :load_evaluation_wizard, except: [:validate_step, :new]
def step1
@teachers = Teacher.includes(:schools).where(schools: {id: current_user.student_details.last.school_id}).order(full_name: :ASC)
end
def step2
@teacher_id = session[:evaluation_attributes]["teacher_id"]
@subjects = Subject.includes(:teachers, :schools).where(teachers: {id: @teacher_id}).where(schools: {id: current_user.student_details.last.school_id}).order(name: :ASC)
end
def step3
pp session[:evaluation_attributes]
end
def validate_step
current_step = params[:current_step]
@evaluation_wizard = wizard_evaluation_for_step(current_step)
@evaluation_wizard.evaluation.attributes = evaluation_wizard_params
session[:evaluation_attributes] = @evaluation_wizard.evaluation.attributes
# pp session[:evaluation_attributes]
if @evaluation_wizard.valid?
next_step = wizard_evaluation_next_step(current_step)
create and return unless next_step
redirect_to action: next_step
else
render current_step
end
end
def load_evaluation_wizard
@evaluation_wizard = wizard_evaluation_for_step(action_name)
end
def wizard_evaluation_next_step(step)
Wizard::Evaluation::STEPS[Wizard::Evaluation::STEPS.index(step) + 1]
end
def wizard_evaluation_for_step(step)
raise InvalidStep unless step.in?(Wizard::Evaluation::STEPS)
"Wizard::Evaluation::#{step.camelize}".constantize.new(session[:evaluation_attributes])
end
def evaluation_wizard_params
params.require(:evaluation_wizard).permit(:teacher_id, :subject_id, evaluation_tags_attributes: {tag_ids: []}).merge(user: current_user, school: current_user.student_details.last.school)
end
class InvalidStep < StandardError; end
end
#STEP3.HTML.ERB
<%= f.collection_check_boxes(:tag_ids, Tag.all, :id, :name) do |tag| %>
<%= tag.label(class: "tags tags-bom") { tag.check_box(class: "checkbox_tags") + tag.text} %>
<% end %>
#ERROR
undefined method `tag_ids' for #<Wizard::Evaluation::Step3:0x00007fadb2be6a88>
如何让该模块识别关系?
答案 0 :(得分:0)
我认为您需要tag_ids
的自定义验证。我不认为rails会一步验证多个项目。也许在应用程序控制器的底部添加自定义验证:
def validate_tag_ids
if !tag_ids.is_a?
errors.add(:tag_ids, :invalid)
end
end
然后使用:
validates: :validate_tag_ids
而不是:
validates :tag_ids, presence: true