【问题标题】:Rails check if HABTM association is changedRails 检查 HABTM 关联是否已更改
【发布时间】:2017-07-04 10:55:07
【问题描述】:

我有一个角色表

select * from roles;

 id |   name
----+----------
  1 | admin
  2 | user
  3 | author
  4 | guest
  5 | manager

还有另一个表 user_roles

select * from user_roles;

 role_id | user_id
---------+---------
       3 |       1
       3 |       2
       3 |       3
       4 |       5
       3 |       6
       5 |       7
       5 |       8
       1 |       9
       1 |      11



#role.rb

class Role < ActiveRecord::Base
  has_and_belongs_to_many :users, join_table: 'user_roles', class_name: user_class.to_s
end

我正在尝试在用户角色更新时执行一些操作,例如从 guestauthor

#user.rb

class Use < ActiveRecord::Base
  after_update :print_role_updated if: :user_roles_changed?
  .
  .

  private

  def user_roles_changed?
    user_roles.any? { |role| role.changed? }
  end

  def print_role_updated
    puts "User role changed from #{old_role} to #{new_role}"
  end
end

但它没有按预期工作(.changed? 正在检查role 表中的值是否已更新?)。

每当用户角色更新为不同的角色时,我如何运行print_role_updated 方法?

编辑

我尝试了医生的回答,但即使记录正在更新,role_updated? 仍返回 false

class Use < ActiveRecord::Base
  has_many :user_roles
  after_update :print_role_updated if: role_updated?
  .
  .


  private

  def role_updated?
    user_roles.any? {|a| a.changed?} 
  end

  def print_role_updated
    puts "User role changed from #{old_role} to #{new_role}"
  end
end

【问题讨论】:

    标签: ruby-on-rails ruby activerecord callback


    【解决方案1】:

    在模型中尝试以下代码:

    user.rb

    class User < ActiveRecord::Base
      after_update :print_role_updated if: :user_roles_changed?
      .
      .
    
      private
    
      def print_role_updated
        puts "User role changed"
      end
    
      def user_roles_changed?
        u = User.find(self.id)
        u.role != self.role # it check existing role and role saved in db 
      end
    end
    

    【讨论】:

      【解决方案2】:

      我找到了解决方案。问题是一旦设置了新值,数据库中的 HABTM 关系就会更新

      这是我为您的示例实施 HABTM 更改方法的解决方法。可能不适用于您的具体情况,但知道这一点您就会明白

      class User < ActiveRecord::Base
      
        ...
        def user_role_ids=(ids)
          @user_roles_changed = ids != user_role_ids
          super(ids)
        end
      
        def user_roles_changed?
          !!@user_roles_changed
        end
      end
      

      【讨论】:

        【解决方案3】:

        我认为_changed? 只适用于属性而不是类。 而且由于您具有多对多关联,因此您无法检查一个对象。 我会朝这个方向尝试:

        if user_roles.any? {|a| a.changed?} 
        

        如果用户只有一个角色(抱歉,从您的代码中不清楚),那么以下应该可以工作,或者不是吗?

        if user_roles.changed?
        

        更新,因为您指定用户可以拥有多个角色。您应该考虑一些更正:

        class Use < ActiveRecord::Base
          has_many :user_roles
          after_update :print_role_updated if: user_roles.any? {|a| a.changed?} 
          .
          .
        
        
          private
        
          def print_role_updated
            puts "User role changed from #{old_role} to #{new_role}"
          end
        end
        

        更新 2: 事实证明,changed? 在新创建的对象上是错误的,所以我之前的更新不起作用。

        尝试将changed? 更改为以下内容:

        user_roles.any? { |a| a.new_record? || a.marked_for_destruction? || a.changed? }
        

        说实话,我在这里做的有点猜测,但你能试试吗?我很想看看这是否有效

        【讨论】:

        • 托尼感谢您的更新。但有趣的部分是知道用户是否具有单个角色或可以具有多个角色。
        • 一个用户可以有多个角色
        • user_role 表没有belongs_to 用户
        • 我已经更新了我的答案,你有没有试过我的如果。如果是这样,您看到的行为是什么?
        • 我试过你的答案(见编辑),但role_updated? 返回的是假的。坚果记录更新成功
        猜你喜欢
        • 1970-01-01
        • 2017-11-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-14
        • 2018-09-13
        • 1970-01-01
        相关资源
        最近更新 更多