2011-03-08 101 views
2

这是很难解释,但我会尽我所能:应用程序设计(Rails 3中)

我建立一个系统,用户可以参加课程。课程由步骤组成,必须按顺序进行。在该系统中有6种步骤类型(下载,演示,视频,文本,测验和调查)

用户访问STEP目前的方法是:

http://example.com/courses/2/course_steps/1

正如你可以告诉course_steps嵌套在课程中。

下面是当然的步骤显示方法:

def show 
    render "show_#{@course_step.step.step_type.name.downcase}" 
end 

正如你可以告诉它基本上挑选一个以show_ [TYPE](竞猜,调查,text..etc)

该作品对于简单的步骤,如文本,视频或下载,但对于复杂的步骤,如测验,这种模式不适合,原因如下效果很好,

  • 我如何验证表单的测验或调查,因为我会是你唱一个不同的控制器(QuizAttemptsController)。
  • 它似乎打破了作为测验的REST校长,survey..etc应该分开处理。 (我知道他们是步骤类型,但他们可以有自己的行动和验证)

STEP模型

class Step < ActiveRecord::Base 
    belongs_to :step_type 
    belongs_to :client 
    has_one :step_quiz, :dependent => :destroy 
    has_one :step_survey, :dependent => :destroy 
    has_one :step_text, :dependent => :destroy 
    has_one :step_download, :dependent => :destroy 
    has_one :step_video, :dependent => :destroy 
    has_one :step_presentation, :dependent => :destroy 
    has_many :course_steps, :dependent => :destroy 
    has_many :courses, :through => :course_steps 
    has_many :patient_course_steps, :dependent => :destroy 

    attr_accessible :step_type_id, :client_id, :title, :subtitle, :summary 

    validates :title, :presence=>true 
    validates :summary, :presence=>true 

    def getSpecificStepObject() 
    case self.step_type.name.downcase 
     when "text" 
     return StepText.find_by_step_id(self.id) 
     when "quiz" 
     return StepQuiz.find_by_step_id(self.id) 
     when "survey" 
     return StepSurvey.find_by_step_id(self.id) 
     when "download" 
     return StepDownload.find_by_step_id(self.id) 
     when "video" 
     return StepVideo.find_by_step_id(self.id) 
     when "presentation" 
     return StepPresentation.find_by_step_id(self.id) 
    end 
    end 
end 

步骤测验型号:

class StepQuiz < ActiveRecord::Base 
    belongs_to :step, :dependent => :destroy 
    has_many :step_quiz_questions, :dependent => :destroy 
    has_many :quiz_attempts, :dependent => :destroy 

    accepts_nested_attributes_for :step 
    accepts_nested_attributes_for :step_quiz_questions, :allow_destroy => true 
    attr_accessible :step_id, :instructions, :step_attributes, :step_quiz_questions_attributes 
    validates :instructions, :presence=>true 
end 

CourseStep型号

class CourseStep < ActiveRecord::Base 
    belongs_to :step 
    belongs_to :course 

    validates_uniqueness_of :step_id, :scope => :course_id 

    def next_step() 
    Course.find(self.course.id).course_steps.order(:position).where("position >= ?", self.position).limit(1).offset(1).first 
    end 

    def previous_step() 
    Course.find(self.course.id).course_steps.order("position DESC").where("position <= ?", self.position).limit(1).offset(1).first 
    end 
end 

你会如何解决这个问题?

回答

0

我已经解决了这个问题的一种方法是在course_steps控制器中添加一个“submit_quiz”成员动作。我不确定我是否喜欢这个,因为代码看起来很丑。我将不胜感激反馈。(注:我使用的康康舞所以@course_step在course_steps_controller自动地创建)

我不喜欢的事情是:

  • show_quiz观点有大量的代码在它
  • submit_quiz是在course_steps_controller
  • quiz_attempt模型具有quiz_questions的虚拟属性(用于验证目的)

show_quiz.html.erb

<%= form_for (@quiz_attempt.blank? ? QuizAttempt.new(:started => Time.now.utc, :step_quiz_id => @course_step.step.step_quiz.id) : @quiz_attempt, :url => submit_quiz_course_course_step_path(@course_step.course, @course_step)) do |f| %> 
<%= render :partial => 'shared/error_messages', :object => f.object %> 
    <% @course_step.step.step_quiz.step_quiz_questions.each do |quiz_question| %> 
     <h3><%= quiz_question.value %></h3> 
     <% quiz_question.step_quiz_question_choices.each do |quiz_question_choice| %> 
     <%= radio_button_tag("quiz_attempt[quiz_questions][#{quiz_question.id}]", quiz_question_choice.value, f.object.get_quiz_question_choice(quiz_question.id) == quiz_question_choice.value)%> 
     <%= quiz_question_choice.value %><br /> 
     <% end %> 

    <% end %> 
    <%= f.hidden_field(:step_quiz_id)%> 
    <%= f.hidden_field(:started)%> 
    <%= submit_tag("Submit Quiz")%> 
<% end %> 

course_steps_controller.rb

def show 
    PatientCourseStep.viewed(current_user.id, params[:course_id], @course_step.step.id) 
    render "show_#{@course_step.step.step_type.name.downcase}" 
    end 

    def submit_quiz 
    @quiz_attempt = QuizAttempt.new(params[:quiz_attempt]) 

    if [email protected]_attempt.save() 
     render 'show_quiz' 
    end 
    end 

quiz_attempt.rb

class QuizAttempt < ActiveRecord::Base 
    belongs_to :step_quiz 
    belongs_to :patient 

    attr_accessor :quiz_questions 
    attr_accessible :step_quiz_id, :patient_id, :started, :ended, :correct, :incorrect, :quiz_questions 

    validate :answered_all_questions? 

    def get_quiz_question_choice(quiz_question_id) 
    unless self.quiz_questions.blank? 
     quiz_questions[quiz_question_id.to_s] 
    end 
    end 

    private 
    def answered_all_questions? 
     #Making sure they answered all the questions 
     if self.quiz_questions.blank? or self.quiz_questions.try(:keys).try(:count) != self.step_quiz.step_quiz_questions.count 
     errors.add_to_base "Not all questions were answered" 
    end 
    end 
end 


    def submit_quiz 
    @quiz_attempt = QuizAttempt.new(params[:quiz_attempt]) 

    if [email protected]_attempt.save() 
     render 'show_quiz' 
    end 
    end 
2

你想要做的是实现模型作为Finite State Machine不断重新加载newedit动作,直到达到所需的状态,那么你的控制器可以根据状态,以允许多个步骤发生显示不同的看法。