【问题标题】:Rails 3 Two Fields Uniqueness Validation when combinedRails 3组合时的两个字段唯一性验证
【发布时间】:2012-12-31 23:20:12
【问题描述】:

我有一个模型Friendship,其中:friend_id 也是:user_id 的外键

friendships
id | user_id | friend_id

我知道验证这两个字段的唯一性是这样的

validates :user_id, :uniqueness => {:scope => :friend_id}

但是有没有办法验证

user_id = 1, friend_id = 3
user_id = 3, friend_id = 1 

所以只有 user_id = 1, friend_id = 3 被存储了吗?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3


    【解决方案1】:

    更仔细地阅读这个问题,我现在认为它是真的

    validates :friend_id, :uniqueness => {:scope => :user_id}
    

    【讨论】:

      【解决方案2】:
      validate :relationship_uniqueness
      
      def relationship_uniqueness
      
        existing_record = Friendship.find(:first, :conditions => ["user_id = ? AND friend_id = ?", user_id, friend_id])
        unless existing_record.blank?
          errors.add(:user_id, "has already been saved for this relationship")
        end
      
      end
      

      【讨论】:

      • 它需要像 :conditions => ["user_id = ? ANDfriend_id = ?",friend_id, user_id])。它有效!谢谢
      【解决方案3】:

      这是个难题。

      如何为对称关系建模?

      上次我这样做时,我决定实际上它不是对称的。 有关如何建模的想法,请查看Disapora's Contact class

      class Contact < ActiveRecord::Base
        belongs_to :user
        belongs_to :person
        validates :person, :presence => true
        validates_presence_of :user
        validates_uniqueness_of :person_id, :scope => :user_id
      end
      

      你会注意到他们没有做任何特别的事情来确保唯一性。

      相反,他们所做的是仔细考虑互动中产生或破坏友谊的每一点。我们需要小心地将它们包装在事务中。

      基本上,当用户发送“好友请求”时

      1. 我们创建一个从“用户”到“朋友”的联系人,状态为“待处理”
      2. 我们创建一个从“朋友”到“用户”的联系人,状态为“已请求”

      当“朋友”接受这个“请求”时

      1. 两个联系人都设置为“已接受”

      如果“朋友”选择破坏友谊

      1. 两个联系人均已删除

      这些动作中的每一个都需要在一个事务中完成。

      只要这些交易是正确的,我们就永远不会有单向的友谊。

      【讨论】:

      • 是的,我见过很多这样的创建联系模型的例子。我知道我的方式会很痛苦。只是我正在考虑不需要状态字段的情况,我只想保持表格很小。那时我可能应该回到旧的方式。
      • 只有一条记录,如果我们想知道“用户 1 是否连接到用户 2?”只有一条记录,我们需要说“WHERE (user_id=1 ANDfriend_id=2) OR (user_id=2 ANDfriend_id=1)”。效率不高
      • 另一种选择是强制执行“user_id
      • 好吧,所有这些方法只有在我们在 Rails 端验证时才有效,一旦我们进入数据库并手动插入记录,一切都会崩溃。最好的解决方案是想出一种在数据库端强制执行此操作的方法。
      • 一切可以通过触发器在数据库中完成,但通常不值得这样做。如果您的代码在事务中小心地执行此类操作,那么这应该不是问题。
      【解决方案4】:

      再来一个!

      def unique_relationship?
          self.class.where("(user_id = ? and friend_id = ?) or 
                            (user_id = ? and friend_id = ?)", 
                            user_id, friend_id, friend_id, user_id).empty?
      end
      

      【讨论】:

        【解决方案5】:

        所以我想了一个办法来解决这个问题,但是很乱

        friendships
        id
        1
        
        friend_lists
        id | friendship_id | user_id
        1  |       1       |   1
        2  |       1       |   3
        

        这样,我必须确保一个friendship_id 只能在friend_lists 中输入两次,然后进行

        validates :friendship_id, :uniqueness => {:scope => :user_id}
        

        【讨论】:

        • 那么你需要确保每个好友恰好有 2 个用户
        【解决方案6】:

        我会尝试:

        validate :unique_relationship
        
        def unique_relationship
          (user_id.to_s + friend_id.to_s).uniq
        end
        

        【讨论】:

        • 这个有意思,我试试
        • 我不明白。此代码创建一个字符串,然后尝试在其上调用uniq
        • 是的,我得到了 NoMethodError: undefined method 'uniq' for "31":String。但我喜欢这种方法
        • 是的,我也刚刚发布了一个关于如何以这种方式进行操作的问题 - 但正确。
        • 是的,我没有以正确的方式放置标题。所以人们可能会认为我只是在问老问题。
        猜你喜欢
        • 1970-01-01
        • 2011-11-17
        • 2019-01-04
        • 2011-05-01
        • 2019-07-12
        • 2010-12-10
        • 2011-03-17
        • 1970-01-01
        • 2015-07-04
        相关资源
        最近更新 更多