Search code examples
ruby-on-railsmodel-associations

Ruby on Rails Use Model Association


I have the rails_best_practices gem and I'm getting the following warning:

APP/app/controllers/users_controller.rb - use model association (for @user_answer)

in reference to this gist of code:

begin
  @user_answer = @user.user_answers.where(:question_id => @question_id).first
  if @user_answer
    @user_answer.answer_id = @answer_id
    @user_answer.save!
    @message = 'Answer updated successfully!'
  else
    @user.user_answers.create(:question_id => params[:questionId], :answer_id => params[:answerId])
    @message = 'Answer submitted successfully!'
  end
rescue ex
  @message = ex.message.split(':')[1].chomp
end

but according to the page on model association it doesn't look like it's violating this, it looks like it is following along correctly. Am I missing something about this?


Solution

  • The problem lies in directly accessing the variables in the @user_answer object, and not updating the user_answer within the @user variable...and since Rails has an update method, we can do this like so:

    begin
      @user_answer = @user.user_answers.where(:question_id => @question_id).first
      if @user_answer
        @user.user_answers.update(:question_id => @question_id, :answer_id => @answer_id)
        @message = 'Answer updated successfully!'
      else
        @user.user_answers.create(:question_id => @question_id, :answer_id => @answer_id)
        @message = 'Answer submitted successfully!'
      end
    rescue ex
      @message = ex.message.split(':')[1].chomp
    end
    

    But we can do better. Rather than differ by create and update, we can simply use Ruby's short circuit evaluation to create a `@user_answer symbol and update it whether it is new or not.

    begin
      @user_answer = @user.user_answers.where(:question_id => @question_id).first || @user.user_answers.new
      @user_answer.update_attributes!(question_id: @question_id, answer_id: @answer_id)
      @message = 'Answer submitted successfully!'
    rescue ex
      @message = ex.message.split(':')[1].chomp
    end