3

I'm sure this is a common problem, but it has me stumped.

I have a has_many :through table on a 'Step' model:

has_many :questions, :through => :question_step

That question_step model has presence validators on the question_id and step_id fields:

validates_presence_of :question_id, :step_id

And there are checkboxes that determine which questions belong to which step

td= check_box_tag "step[question_ids][]", question.id, @step.question_ids.include?(question.id)

Now, this works just fine, except when I want to add questions to a new step. Because step_id is blank, the question_step model fails validation. It works fine if I remove the validate_presence_of :step_id argument in the question_step model, but I actually do want to ensure that the step_id is there.

I'm sure this is a common problem. ...Any thoughts?

2

2 Answers 2

1

Rather than validating the step and question IDs are present, you could check if there is a question and step object:

validates_presence_of :question, :step

If that doesn't work you should consider removing the application level validations and adding database constraints instead, you just need to add a not null constraint to the columns in a migration:

def up
  change_column question_steps, :question_id, :integer, :null => false
  change_column question_steps, :step_id,     :integer, :null => false
end
Sign up to request clarification or add additional context in comments.

Comments

0

I had a very similar issue. According to this question there is a race condition occurring.

In my controller's create action I decided to create my main model without the associations first using params which exclude the association params. And then update the model with the association params.

So in your case it might be

def create
  @step = Step.create(create_params)
  @step.update_attributes(association_params) unless @step.errors.any?
  respond_to do |format|
    if @step.errors.empty?
      format.html #etc..
    else
      format.html#...etc..
    end
  end
end

private
def create_params
  perm_params = step_params
  perm_params.delete :question_ids
  perm_params
end
def association_params
  params.require(:step).permit(question_ids: [])
end
def step_params
  params.require(:step).permit(:name, :other_attributes, question_ids: [])
end

This way you do not have to move the validations to your db. You would still use the normal step_params in your update method.

The params methods could probably be DRYed up a bit and I am wondering why I need to go to all this fuss for something which worked simply in rails 3, but it works now for me.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.