【问题标题】:How do I create/maintain a valid reference to a particular object in an ActiveRecord association?如何在 ActiveRecord 关联中创建/维护对特定对象的有效引用?
【发布时间】:2009-04-28 03:05:16
【问题描述】:

使用 ActiveRecord,我有一个对象 Client,它有零个或多个用户(即通过 has_many 关联)。客户端还具有可以手动设置的“primary_contact”属性,但始终必须指向关联用户之一。 IE。如果没有关联用户,primary_contact 只能为空。

实现 Client 的最佳方式是:

a) 第一次将用户添加到客户端时,primary_contact 是否设置为指向该用户?

b) primary_contact 始终保证在用户关联中,除非所有用户都被删除? (这有两个部分:设置新的 primary_contact 或从关联中删除用户时)

换句话说,我如何将“主要联系人”的标题指定并重新分配给给定客户的用户之一?我已经修改了许多过滤器和验证,但我就是无法做到正确。任何帮助将不胜感激。


更新:虽然我确信有无数的解决方案,但我最终让用户在删除它时通知客户端,然后在客户端中使用 before_save 调用来验证(并在必要时设置)它的 primary_contact。此调用由用户在被删除之前触发。在更新关联时,这并不能捕捉到所有的边缘情况,但它足以满足我的需要。

【问题讨论】:

    标签: ruby-on-rails ruby validation activerecord


    【解决方案1】:

    我的解决方案是在连接模型中做所有事情。我认为这在客户端转换到零关联或从零关联转换时正常工作,始终保证如果存在任何现有关联,则指定主要联系人。我很想听听任何人的反馈。


    我是新来的,所以不能在下面评论弗朗索瓦。我只能编辑我自己的条目。他的解决方案假定用户对客户是一对多,而我的解决方案假定多对多。我在想用户模型可能代表一个“代理”或“代表”,并且肯定会管理多个客户端。这个问题在这方面是模棱两可的。


    class User < ActiveRecord::Base
      has_many :user_clients, :dependent => true
      has_many :clients, :through => :user_client
    
    end
    
    class UserClient < ActiveRecord::Base
    
      belongs_to :user
      belongs_to :client
    
      # user_client join table contains :primary column
    
      after_create :init_primary
      before_destroy :preserve_primary
    
      def init_primary
        # first association for a client is always primary
        if self.client.user_clients.length == 1 
          self.primary = true
          self.save
        end
      end
    
      def preserve_primary
        if self.primary
          #unless this is the last association, make soemone else primary
          unless self.client.user_clients.length == 1 
            # there's gotta be a more concise way...
            if self.client.user_clients[0].equal? self
              self.client.user_clients[1].primary = true
            else
              self.client.user_clients[0].primary = true
            end
          end
        end
      end
    
    end
    
    class Client < ActiveRecord::Base
      has_many :user_clients, :dependent => true
      has_many :users, :through => :user_client
    
    end
    

    【讨论】:

      【解决方案2】:

      虽然我确信有无数的解决方案,但我最终让用户在删除它时通知客户端,然后在客户端中使用 before_save 调用来验证(并在必要时设置)它的 primary_contact。此调用在删除之前由用户触发。在更新关联时,这并不能捕捉到所有的边缘情况,但它足以满足我的需要。

      【讨论】:

        【解决方案3】:

        我会使用用户的布尔属性来做到这一点。 #has_one 可用于查找第一个将此布尔值设置为 true 的模型。

        class Client < AR::B
          has_many :users, :dependent => :destroy
          has_one  :primary_contact, :class_name => "User",
                                     :conditions => {:primary_contact => true},
                                     :dependent  => :destroy
        end
        
        class User < AR::B
          belongs_to :client
        
          after_save    :ensure_only_primary
          before_create :ensure_at_least_one_primary
          after_destroy :select_another_primary
        
          private
          # We always want one primary contact, so find another one when I'm being
          # deleted
          def select_another_primary
            return unless primary_contact?
            u = self.client.users.first
            u.update_attribute(:primary_contact, true) if u
          end
        
          def ensure_at_least_one_primary
            return if self.client.users.count(:primary_contact).nonzero?
            self.primary_contact = true
          end
        
          # We want only 1 primary contact, so if I am the primary contact, all other
          # ones have to be secondary
          def ensure_only_primary
            return unless primary_contact?
            self.client.users.update_all(["primary_contact = ?", false], ["id <> ?", self.id])
          end
        end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多