验证 habtm 关联的长度而不保存

发布于 2024-08-09 02:21:15 字数 611 浏览 7 评论 0原文

我有一个与组具有 HABTM 关系的用户模型。我不希望用户能够加入超过 5 个组,因此想验证 HABTM 关系的长度。

在编辑用户页面上,我有一个复选框列表,用户可以在其中选择他们想要加入的组(我使用 formtastic 作为表单)。

在我的用户控制器中,我调用:

@user.update_attributes(params[:user])

这导致 Rails 自动更新关联。

在我的用户模型中,我有以下内容:

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

这导致表单验证失败,但 update_attributes 调用已经更新了数据库以反映对关联组的更改。这样,每次用户单击“保存”按钮时,即使记录无效,也会保存其组关联。

解决这个问题的最佳方法是什么?

我认为验证可能需要在组模型而不是用户模型上进行,这可行吗?理想情况下,我想更新关联的组而不保存记录,进行验证,然后保存记录。

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

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

In my users controller I'm calling:

@user.update_attributes(params[:user])

which is causing rails to update the associations automatically.

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 is causing the form to fail the validation, but the update_attributes call has already updated the database to reflect the changes to the associated groups. This way every time a user clicks the save button their group associations are saved, even though the record is invalid.

What's the best way to solve this?

I think perhaps the validation needs to be on the group model instead of the user model, would this work? Ideally I'd like to update the associated groups without saving the record, do the validation, and THEN save the record.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

美胚控场 2024-08-16 02:21:15

您在这里遇到了两个问题:

  1. 您覆盖了验证
  2. 保存时的操作顺序导致了问题。

您正在覆盖验证方法,这是一件坏事,因为内置行为会拒绝将带有验证错误的记录保存到数据库中。要添加自定义验证,您需要执行以下操作:

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

但是,HABTM 关系的本质要求您将其作为 after_save 回调来执行。只是因为事情完成的顺序。 user.groups 基于隐式联接表,并且在联接表更新之前不会更新。

如果您尝试将验证作为回调的一部分(before_save、after_creation 等),则向对象添加错误将不会触发回滚。回调仅在返回 false 时才会触发回滚。这将处理问题建议的保存后实现。

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

另一种解决方案是使用显式连接模型。还有一个 has_many :through 关系。连接模型的表在更新语句中更新。其中 has_many :through 和 HABTM 关系在保存后更新关系。

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 隐式使用连接表,因此不需要在组端进行更改。

但是,您需要修改表单以更新表单,以在 params 哈希中提供 group_id 作为 params[:user][:user_group_attributes][0][:group_id][3]

You had two problems here:

  1. You're overriding validations
  2. The order of operations in saving is causing problems.

You're overwriting the validate method which is a bad thing, because the built in behaviour to deny records with validation errors to be saved to the database. To add custom validations 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 HABTM relationships requires you to do it as an after_save callback. Just because of the order that things are done. user.groups is based on the implicit join table and there for isn't updated until the join table is updated.

If you're trying to validate as part of a callback (before_save, after_creation, etc.), then adding an error to the object won't trigger a roll back. Callbacks will only trigger a rollback if they return false. This will handle the after save implementation the question suggest.

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 a has_many :through relationship. The join model's table is updated in the update statement. Where as the has_many :through and HABTM relationships update the relationship after the save.

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 a join table, so it doesn't need to be changed on the group side.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文