HABTM: join table records being deleted & not restored when validation fails

Rails: 2.1.2
Ruby: 1.8.6

I have two models joined by HABTM: Sessions and Learners. On the
Session edit form, there’s a checkbox list of Learners. Users check
which Learners will attend the session. Very straight forward.

One of the business rules is that a Session must have at least one
learner. We’re enforcing that with a validation procedure in the
Session model.

validate :has_at_least_one_learner?

def has_at_least_one_learner?
if (self.learners.empty?)
errors.add_to_base(“At least one learner must be selected.”)
end
end

In the Session controller, we have this code for the Update action:

@session = @project.sessions.find(params[:id])
params[:session][:learner_ids] ||= []

if @session.update_attributes(params[:session])
… successful update
else
… bad update
end

All pretty simple. And, indeed, if you try to save a Session without
any learners selected, you get the correct validation error.

But what I’m seeing is that even though Rails is displaying the error
message, it’s still deleting the associated records in the join table,
learners_sessions.

What I’d like is for Rails to restore the deleted join records if the
update fails. I thought that using transactions would do the trick,
but so far I haven’t had any success there either.

@session = @project.sessions.find(params[:id])
params[:session][:learner_ids] ||= []

@session.transaction do
begin
@session.update_attributes!(params[:session])
rescue ActiveRecord::RecordInvalid
– bad update
else
– good update
end
end

Any ideas? How can I get the validation error message to display and
still keep my records in the join table?

… what I’m seeing is that even though Rails is displaying the error
message, it’s still deleting the associated records in the join table,
learners_sessions.

Though I have not used it, there seems to be a plugin that addresses
this kind of issue:

http://code.google.com/p/habtm-with-deferred-save/

Good luck!


Kurt W.
I am looking for a new Rails job:
http://www.CircleW.org/kurt/pages/resume

On 18 February 2010 21:47, Ian [email protected] wrote:

learners_sessions.

What I’d like is for Rails to restore the deleted join records if the
update fails. I thought that using transactions would do the trick,
but so far I haven’t had any success there either.

I may be missing a piece of the jigsaw; but instead of putting a blank
array into the params[:session][:learner_ids] if it’s nil, why don’t
you populate it with the existing ids? So Rails will either use the
newly selected ids from the form, of repopulate with the old ones?

UI wise, that ends up being a bit awkward. The user thinks they’ve
deselected all learners, but if they edit the page again, all the
learners are still selected.

After a little bit of testing, this plugin seems to solve the problem.
Thanks.

On 19 February 2010 16:19, Ian [email protected] wrote:

UI wise, that ends up being a bit awkward. The user thinks they’ve
deselected all learners, but if they edit the page again, all the
learners are still selected.

Sheesh.
The save the learners in an array, and restore them yourself on any
failure to update

old_learners = @session.learners.map {|learner| learner.id}

if @session.update_attributes(params[:session])
… successful update
else
… bad update
@session.update_attributes{:learner_ids => old_learners}
end

But seeing as you’ve got the plugin doing what you need, it’s academic.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs