代码之家  ›  专栏  ›  技术社区  ›  jonnii

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

  •  4
  • jonnii  · 技术社区  · 15 年前

    在编辑用户页面上,我有一个复选框列表,用户可以在其中选择他们想要加入的组(我使用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
    

    解决这个问题的最好办法是什么?

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

    1 回复  |  直到 15 年前
        1
  •  11
  •   EmFi    15 年前

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

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

    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关系的性质要求您将其作为“保存后”回调来执行。只是因为做事的顺序。 user.groups 基于隐式联接表,在联接表更新之前不会更新。

    如果尝试作为回调的一部分进行验证(保存前、创建后等),则向对象添加错误不会触发回滚。回调只有在返回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
    

    另一个解决方案是使用显式连接模型。而且有很多:通过关系。联接模型的表在update语句中更新。Where as_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]