Any nicer way to achieve this ? (habtm requiring at least one associated model)

Hi!

I have a QuestionResult, which has_and_belongs_to_many Answers and which has a custom validate to ensure there is at least one Answer associated.

As advertised on http://wiki.rubyonrails.org/rails/pages/has_and_belongs_to_many , the following test fails:

def test_not_working question_result = QuestionResult.new(:question => @question, :interview_result => @interview_result)

question_result.answers << @answer
question_result.save!       # => throws RecordInvalid (at least one answer is required)

end

The save! fails because I should be saving question_result before adding relationships through the << call (otherwise the id is not already known).

My current solution is to bypass the validations using save(false), then add the answers, then call save!, and wrap all the code with a begin/rescue to remove the question_result when RecordInvalid is thrown (I could also use a transaction for the job).

Is there any cleaner or shorter way to achieve this ?

thanks!

Thibaut

Thibaut Barrère wrote:

I have a QuestionResult, which has_and_belongs_to_many Answers and which has a custom validate to ensure there is at least one Answer associated.

As advertised on http://wiki.rubyonrails.org/rails/pages/has_and_belongs_to_many , the following test fails:

  def test_not_working     question_result = QuestionResult.new(:question => @question, :interview_result => @interview_result)     question_result.answers << @answer     question_result.save! # => throws RecordInvalid (at least one answer is required)   end

The save! fails because I should be saving question_result before adding relationships through the << call (otherwise the id is not already known).

My current solution is to bypass the validations using save(false), then add the answers, then call save!, and wrap all the code with a begin/rescue to remove the question_result when RecordInvalid is thrown (I could also use a transaction for the job).

Is there any cleaner or shorter way to achieve this ?

Can you post your validation code?

Hi Mark

Can you post your validation code?

I found where the issue was, here’s a report:

def validate

errors.add(:answers,“At least one answer is required (#{answers.count} actual)”) if (answers.count<1)

end

I can’t use count inside the validation step, because count equals size only once the model has been successfully saved.

Here’s a test to illustrate:

def test_working question_result = QuestionResult.new(:question => @question, :interview_result => @interview_result) question_result.answers << @answer

assert_equal 0,question_result.answers.count

assert_equal 1,question_result.answers.size question_result.save!

assert_equal 1,question_result.answers.count assert_equal 1,question_result.answers.size

end

When using size inside the validations, everything runs smoothly.

thanks for your reply!

Thibaut