Rails: Uniqueness of two attributes in join table causing 500 error
Asked Answered
P

2

7

I have the following models, which basically are trying to mean that a professor has knowledge of many subjects for a particular level. The subjects are fixed, so there will be no new subjects created, there will be just "related" to a professor through the knowledge join table.

class Subject < ActiveRecord::Base
  # Self Associations
  has_many :subcategories, :class_name => "Subject"
  belongs_to :category, :class_name => "Subject",:foreign_key => "parent_id"

  # Associations
  has_many :knowledges
  has_many :professors, :through => :knowledges
end


class Professor < ActiveRecord::Base
  # Associations
  has_many :knowledges
  has_many :subjects, :through => :knowledges
  ...
end

class Knowledge < ActiveRecord::Base
  # Associations
  belongs_to :professor
  belongs_to :subject
  has_one :level

  attr_accessible :subject_id, :professor_id

  validates :subject_id, :uniqueness => { :scope => :professor_id }
end

I want to have a form that will let a professor to add a subject to his account, and I decided to have a form for a knowledge (as I want to be able to insert a level too).

It looks like this:

<%= simple_form_for @knowledge,:url => professor_knowledges_path, :html => { :class => 'form-horizontal' } do |f| %>
    <div class="control-group select optional">
      <%= label_tag "Subject Type", nil, :class => "select optional control-label"%>
      <div class="controls">
    <%= select_tag "Parent Subject", options_from_collection_for_select(@parent_subjects, "id", "name"), :id => "knowledge_parent_subject" %>
      </div>
    </div>
    <%= f.input :subject_id, :collection => @subjects, :label => "Subject" %>
    <%= f.input :level %>
  <%= f.button :submit, t('add_form'),:class => 'btn-primary' %>
<% end %>

And in the create action of the Knowledges controller I have this:

def create
    @knowledge = Knowledge.create(:professor_id => current_professor.id, :subject_id => params[:knowledge][:subject_id]) 
  end

I would like/expect to get an ActiveRecord saying that this knowledge can't be inserted because there is a uniqueness violation, but nops, I just see a 500 in the logs and a rollback, but it seems the execution goes on. So my question is: What am I doing wrong, or how I could improve this modeling situation? I believe the form needs to be related to the join model as I want to have fields of that model on it...But maybe I am wrong, and I could do in an easy/cleaner way.

EDIT:

As asked in one of the comments, here is the log of the submission of the form and the 500 error right after the rollback:

Started POST "/professors/1/knowledges" for 127.0.0.1 at 2012-07-01 00:45:39 -0700
Processing by KnowledgesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"4JVyxWnIh37kyBwLwLGTHk/znsI1c5wrJvaWjKKT5tM=", "Parent Subject"=>"1", "knowledge"=>{"subject_id"=>"1"}, "commit"=>"Añadir", "professor_id"=>"1"}
  Professor Load (0.4ms)  SELECT `professors`.* FROM `professors` WHERE `professors`.`id` = 1 LIMIT 1
Completed 500 Internal Server Error in 4ms

I added some conditions in the create action, like this:

  def create
    @knowledge = Knowledge.new(:professor_id => current_professor.id, :subject_id => params[:knowledge][:subject_id]) 
    if @knowledge.save
      flash[:notice] = "Success..."
      redirect_to professor_path(current_professor)
    else
      render :action => 'new'
    end
  end

And this actually shows the following right after the 500:

Completed 500 Internal Server Error in 6ms

ActiveRecord::RecordInvalid (Validation failed: Subject has already been taken):

I wonder why the exception is raised instead of just adding the errors into the object and let me manage that situation. Isn't what the following line should be doing?

validates :subject_id, :uniqueness => { :scope => :professor_id }
Pastoralize answered 30/6, 2012 at 5:26 Comment(3)
Please post the logs that lead to 500. That would be helpful.Repast
logs have been posted :)Pastoralize
Yes, the errors should've been added into the object. I don't think that is causing the 500 error. Can you halt the execution before if @knowledge.save line in KnowledgesController#create, using debugger or pry. Then try @knowledge.save and @knowledge.save! just to confirm the validation errors have been embedded into @knowledge. You could verify that even from the console. Also, can you please post a gist of the entire stack trace. I've a strong feeling that this is not due to validating uniqueness.Repast
O
0

That error means you are trying to insert duplicate subject_id / professor_id pairs on that table. Most often happens when either the subject_id or professor_id is null.

Are you sure the controller is getting the correct parameters? I would check the logs to make sure the inserts are what you would expect.

Occupy answered 7/7, 2012 at 5:36 Comment(0)
C
0

I don't have enough reputation to comment...my answer is more some things to try than a definitive answer, sorry.

It looks like the save is failing due to validation errors. You can try to handle those in your 'else' block. The following will give you a description of all validation errors (useful for debugging).

@knowledge.errors.full_messages

You haven't shown what is happening in the 'new' action. I suspect this is where the errors are occurring.

Does the same issue occur (i.e. the validation problem) in the console? If so, try cleaning out your databases (beware - the following will erase & rebuild all your databases).

rake db:drop:all db:create:all db:migrate db:test:prepare

Also, if you haven't already, add an index to your migration for Knowledge to prevent duplicates being added to the db. e.g.

    add_index :knowledges, [ :professor_id, :subject_id ], unique: true
Cuttlefish answered 2/7, 2012 at 19:1 Comment(0)
O
0

That error means you are trying to insert duplicate subject_id / professor_id pairs on that table. Most often happens when either the subject_id or professor_id is null.

Are you sure the controller is getting the correct parameters? I would check the logs to make sure the inserts are what you would expect.

Occupy answered 7/7, 2012 at 5:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.