0
votes

I have an model called assignment, which represents a rich join between users and questions in a multiple choice quiz app. when a user answers a question, the response is recorded in the following update method in the assignments controller


    def edit
        @assignment = Assignment.find_by_id(params[:id])
        @user =     @assignment.user
        @question = @assignment.question
        puts "user #{@user} question #{@question} assignment #{@assignment}"
      end

    def update
        @assignment = Assignment.find(params[:id])
        @user = @assignment.user
        @assignment.update_attributes(:response => params[:assignment][:response])
        if @assignment.save
          flash[:notice] = "Your response has been saved"
          redirect_to(:action => 'show', :id => @assignment.id , :user_id => @user.id)
        else
          puts @assignment.save
          puts "could not save"
          render(user_assignment_path(@user, @assignment) , :html => {:method => :get})
        end
      end

I have a before save called grade that gets called. Here is the model:

 

    class Assignment  ActiveRecord::Base
      belongs_to :user
      belongs_to :question
      attr_accessible :title, :body, :user_id, :question_id , :response
      before_save :grade


      def grade
        self.correct = (response == self.question.solution) unless response == nil
      end
    end

So the first time I submit a response, the save works perfectly and it redirects me accordingly. after that, if i try to edit the question again and resubmit the form, the save fails.

Can anyone think of a reason this might be occurring?

In addition I know there is an error in the second redirect, so if someone could correct my usage that would be a bonus help

EDIT Here is the Edit erb, in case someone can spot something wrong here. I also added the edit method in the controller above.

<div class="admin-display">
  <%if @admin%>
    <p>
      You may edit the user's response below or change the question to override whether the question is marked correct.
    </p>
  <%end%>
</div>
<div class="question body">
  <%= @question.question %>
</div>
<div class="answer-choices">
  <%=  params[:user_id] + " " + params[:id]  %>
  <ol type="A">
    <%=form_for(@assignment , :url => user_assignment_path(params[:user_id] , params[:id]) , :html => {:method => "put"},  :user_id => params[:user_id]) do |f|%>
      <%[@question.answerA, @question.answerB ,@question.answerC ,@question.answerD].each do |choice|%>
        <li>
          <%=  f.radio_button(:response, choice)%>
          <%= choice %>
        </li>
      <%end%>    
    </ol>
    <div class="form-buttons">
      <%= submit_tag("Submit Response") %>
    </div>
  <%end%>
</div>

EDIT 2 I have just gone through the steps by hand in the rails console, without any issue, so there must be something strange going on.

2
Please post your errors.Jesper
I think it would be a good practice to call the grade instance method from the controller instead of adding callbacks to do so, this means it will only call the method in the controller when saving it, this will save you some headaches when callbacks stack and loading time increases.dennis
@Jesper hey, I'm not getting any errors. This is the weird thing. The assignment just fails to save and follows the else logic. I tried printing errors to the console and nothing came out.bluedevil

2 Answers

1
votes

It's probably due to the fact that your grade() callback method is returning a false, which will cancel the action all together (as stated in the documentation).

0
votes

Hope this will work for you.

In Assignment model, add correct field as attr_accessible. First time as the response is nil, it is not executing the statement in before_save method, Hence your code will be

class Assignment  ActiveRecord::Base
  belongs_to :user
  belongs_to :question
  attr_accessible :title, :body, :user_id, :question_id , :response, :correct
  before_save :grade


  def grade
    correct = (response == question.solution) unless response.nil?
  end
end

and cotroller action could be

def update
  @assignment = Assignment.find(params[:id])
  @user = @assignment.user
  @assignment.update_attributes(:response => params[:assignment][:response])
  if @assignment.valid?
    flash[:notice] = "Your response has been saved"
    redirect_to(:action => 'show', :id => @assignment.id , :user_id => @user.id)
  else
    render(user_assignment_path(@user, @assignment) , :html => {:method => :get})
  end
end