Checking habtm association length without saving

I have a user model with a HABTM group relationship. I do not want the user to be in more than 5 groups, so I would like to confirm the length of the HABTM relationship.

On the user edit page, I have a list of checkboxes where the user can select the groups they want to be in (I use formtastic for the form).

In my user controller, I call:

@user.update_attributes(params[:user]) 

which causes rails to automatically update associations.

In my user model, I have the following:

 def validate if self.groups.length > 5 self.errors.add(:groups, "cannot have more than 5 groups") end end 

This causes the validation form to fail, but the call to update_attributes has already updated the database to reflect changes in related groups. Thus, each time the user presses the save button, their group associations are saved, even if the entry is invalid.

What is the best way to solve this problem?

I think that perhaps the validation should be on the group model, and not on the user model, will this work? Ideally, I would like to update related groups without saving the record, perform validation and THEN save the record.

+4
source share
1 answer

You had two problems:

  • You override validations
  • The order of operations when saving causes problems.

You are rewriting a validation method, which is bad because the built-in behavior prohibits entries with validation errors that must be stored in the database. To add custom checks, you want to do this:

 validate :maximum_group_length def maximum_group_length if self.groups.length > 5 self.errors.add(:groups, "cannot have more than 5 groups") end end 

However, the nature of the HABTM relationship requires you to do this as an after_save callback. Just because everything is done. user.groups based on an implicit connection table, and there it is not updated for it until the connection table is updated.

If you try to check as part of a callback (before_save, after_creation, etc.), then adding an error to the object will not result in a rollback. Callbacks will only rollback if they return false. This question will be considered after implementation after saving the question.

 after_save :validate_maximum_group_length def validate_maximum_group_length if self.groups.length > 5 self.errors.add(:groups, "cannot have more than 5 groups") return false end end 

Another solution is to use an explicit join model. And has_many: through relationships. The connection model table is updated in the update instruction. Where, when has_many: through and HABTM relationships update relationships after saving.

 class User < ActiveRecord::Base has_many :user_groups has_many :groups, :through => user_groups, allow_destroy validate :max_group_length errors.add(:groups, "cannot have more than 5 groups") if self.user_groups.length > 5 end end class UserGroup < ActiveRecord::Base belongs_to :user belongs_to :group end class Group < ActiveRecord::Base has_and_belongs_to_many :users end 

HABTM implicitly uses the connection table, so it does not need to be changed on the group side.

However, you will need to change your form to update the form to provide group_id in the params hash as params[:user][:user_group_attributes][0][:group_id][3]

+11
source

All Articles