Rails: Where, and how, should I initialize a set of QuizAnswers in my user model?

advertisements

I've been reading the Hartl book, searching online, but I still find myself guess-working my way through learning Rails:
I'm trying to set up a short multiple-choice quiz at the start of an e-learning. Here's my User model which, amongst other things, 'has_many QuizAnswers':

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  serialize :planning_progress
  serialize :facilitation_progress
  serialize :teamwork_progress
  serialize :communication_progress

  # following used to record which roles a user is involved in
  serialize :leadership_roles

  before_create :set_progress_vars

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  validates :age, presence: { :message => ": Please choose your age" }
  validates :section, presence: { :message => ": Please choose the section you belong to"}
  has_many :posts
  has_many :quiz_answers

  private  

  # this function triggered 'before_create'
  def set_progress_vars
    self.planning_progress = [false, false, false, false, false, false, false, false, false, false, false, false, false]
    self.facilitation_progress = [false, false, false, false, false, false, false, false, false, false, false, false, false]
    self.teamwork_progress = [false, false, false, false, false, false, false, false, false, false, false, false, false]
    self.communication_progress = [false, false, false, false, false, false, false, false, false, false, false, false, false]
  end

end

My QuizAnswer model, so far, is this:

class QuizAnswer < ActiveRecord::Base
    belongs_to :user
    attr_reader :questionID
    def initialize(p_id)
        @questionID = p_id
    end
end

I'd like to know how I would set up 8 QuizAnswers with questionIDs from 0 to 7. I'm assuming this should be done in the User model, given that it's the thing that has the 'has_many' relationship.

I could add the following code to the set_progress_vars, as this is triggered when (before) a User is created:

8.times {
      quiz_answers.push(QuizAnswer.new)
    }

But is quiz_answers an Array? How do I pass an index value to each new QuizAnswer, so it can track which question it refers to?

If anyone has some code pointers, that would be great.


I wouldn't do it in model nor controller, I would crete another object, Service or Form object depending on what do you want to do with QuizAnswers ( maybe save them to database or create form for them ).

I think that if you keep any logic for QuizAnswer in you user Model, then SRP is broken.

You can take a look at this article : http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

But, if you really want to go down that road then:

def createQuizAnswers
   for i in 0...7
      quiz_answers.create(i) // to save to database && connect it to user
    end
end

EDIT:

First, check database schema (db/schema.rb) and see if your QuizAnswers table has user_id column. if not create migration ( rails generate migration add_user_id_to_quiz_answers , add "add_column :quiz_answers, :user_id, :integer" to first function.

Next thing, you have QuizAnswers controller for take quiz answers ( where is the question with possible answers ). On next/submit button you can take params and create for the current_user corresponding quiz answer, for instance

current_user.quiz_answers.create(quiz_params)

Then, wherever you need these answers you can call them by

current_user.quiz_answers

Let's say you need to go through answers:

current_user.quiz_answers.each do |qa|

end

In this loop you can check if the answer is correct or whatever you want. So in the end this is possible code

current_user.quiz_answers.each do |qa|
    if qa.correct
      current_user.points++
    end
end

Or maybe, as an admin, you want to go through some users and for each user check their answers:

users = User.where(some_condition)
users.each do |user|
   user.quiz_answers.each do |qa|
      if qa.correct
         user.points++
      end
      user.save
   end
end