Reputation: 909
I have a survey and I would like to add participants to a Participant
model whenever a user answers to a question for the first time. The survey is a bit special because it has many functions to answer questions such as Tag words, Multiple choices and Open Question and each function is actually a model that has its own records. Also I only want the Participant to be saved once.
The Participant model is fairly simple:
class Participant < ActiveRecord::Base
belongs_to :survey
attr_accessible :survey_id, :user_id
end
The Survey model is also straightforward:
class Survey < ActiveRecord::Base
...
has_many :participants, :through => :users
has_many :rating_questions, :dependent => :destroy
has_many :open_questions, :dependent => :destroy
has_many :tag_questions, :dependent => :destroy
belongs_to :account
belongs_to :user
accepts_nested_attributes_for :open_questions
accepts_nested_attributes_for :rating_questions
accepts_nested_attributes_for :tag_questions
...
end
Then you have models such as rating_answers
that belong to a rating_question
, open_answers
that belong to open_questions
and so on.
So initially I thought for within my model rating_answers
I could add after_create
callback to add_participant
like this:
class RatingAnswer < ActiveRecord::Base
belongs_to :rating_question
after_create :add_participant
...
protected
def add_participant
@participant = Participant.where(:user_id => current_user.id, :survey_id => Survey.find(params[:survey_id]))
if @participant.nil?
Participant.create!(:user_id => current_user.id, :survey_id => Survey.find(params[:survey_id]))
end
end
end
In this case, I didn't know how to find the survey_id, so I tried using the params but I don't think that is the right way to do it. regardles it returned this error
NameError (undefined local variable or method `current_user' for #<RatingAnswer:0x0000010325ef00>):
app/models/rating_answer.rb:25:in `add_participant'
app/controllers/rating_answers_controller.rb:12:in `create'
Another idea I had was to create instead a module Participants.rb
that I could use in each controllers
module Participants
def add_participant
@participant = Participant.where(:user_id => current_user.id, :survey_id => Survey.find(params[:survey_id]))
if @participant.nil?
Participant.create!(:user_id => current_user.id, :survey_id => Survey.find(params[:survey_id]))
end
end
end
and in the controller
class RatingAnswersController < ApplicationController
include Participants
def create
@rating_question = RatingQuestion.find_by_id(params[:rating_question_id])
@rating_answer = RatingAnswer.new(params[:rating_answer])
@survey = Survey.find(params[:survey_id])
if @rating_answer.save
add_participant
respond_to do |format|
format.js
end
end
end
end
And I got a routing error
ActionController::RoutingError (uninitialized constant RatingAnswersController::Participants):
I can understand this error, because I don't have a controller for participants with a create method and its routes resources
I am not sure what is the proper way to add a record to a model from a nested model and what is the cleaner approach.
Ideas are most welcome!
Upvotes: 0
Views: 63
Reputation: 909
In the end I ended up using the after_create
callback but instead of fetching the data from the params, I used the associations. Also if @participant.nil?
didn't work for some reason.
class RatingAnswer < ActiveRecord::Base
belongs_to :rating_question
after_create :add_participant
...
protected
def add_participant
@participant = Participant.where(:user_id => self.user.id, :survey_id => self.rating_question.survey.id)
unless @participant.any?
@new_participant = Participant.create(:user_id => self.user.id, :survey_id => self.survey.rating_question.id)
end
end
end
The cool thing with associations is if you have deeply nested associations for instead
Survey has_many questions
Question has_many answers
Answer has_many responses
in order to fetch the survey id from within the responses model you can do
self.answer.question.survey.id
very nifty!
Upvotes: 0
Reputation: 5214
current_user is a helper that's accessible in views/controller alone. You need to pass it as a parameter into the model. Else, it ain't accessible in the models. May be, this should help.
Upvotes: 1