【问题标题】:Ruby/Rails: Complex conditions in a has_many associationRuby/Rails:has_many 关联中的复杂条件
【发布时间】:2012-08-08 20:31:17
【问题描述】:

我有一个Transaction 模型。一个事务有一个seller_id 列和一个buyer_id。两者都填充了User ID。

所以:

class Transaction
  belongs_to :seller, :class_name => 'User'
  belongs_to :buyer, :class_name => 'User'
end

_

class User
  has_many :selling_transactions, :class_name => 'Transaction', :foreign_key => 'seller_id'
  has_many :buying_transactions, :class_name => 'Transaction', :foreign_key => 'buyer_id'
end

我想做的是在User 上添加一个has_many 来关联不完整的交易,无论User 是卖方还是买方。

class User
  has_many :incomplete_transactions, :class_name => 'Transaction', :conditions => ???
end

_

我用纯 SQL 写出来,得到了我想要的结果。我的 SQL 中的联接是:

left outer join transactions t on ((t.seller_id = users.id and t.buyer_id is NULL) or (t.buyer_id = users.id and t.seller_id is NULL))

如何将 join 转换为 has_many 关联?

编辑:
我希望将不完整事务保留为 ActiveRecord::Relation (而不是数组),所以我可以执行类似 user.incomplete_transactions.limit(15) 的操作

谢谢。

【问题讨论】:

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


    【解决方案1】:

    pdevisser's 的类似回答: 您可以使用与此问题给出的答案类似的内容:https://stackoverflow.com/a/307724/624590

    这基本上会导致:

    class User
      has_many :selling_transactions, :class_name => 'Transaction', :foreign_key => 'seller_id'
      has_many :buying_transactions, :class_name => 'Transaction', :foreign_key => 'buyer_id'
    
      has_many :incomplete_sales, :class_name => 'Transaction', :foreign_key => 'seller_id', :conditions => { :buyer_id => nil }
      has_many :incomplete_purchases, :class_name => 'Transaction', :foreign_key => 'buyer_id', :conditions => { :seller_id => nil }
    
      def incomplete_transactions
        incomplete_sales + incomplete_purchases
      end
    end
    

    编辑:好的,不完全确定如何按您希望的方式进行设置(使用 has_many),但类似的方法可能适合您:

    class User
      has_many :selling_transactions, :class_name => 'Transaction', :foreign_key => 'seller_id'
      has_many :buying_transactions, :class_name => 'Transaction', :foreign_key => 'buyer_id'
    
      def incomplete_transactions
        Transaction.where("(buyer_id = ? and seller_id = NULL) or (seller_id = ? and buyer_id = NULL)", id, id)
      end
    end
    

    where 语句将返回一个ActiveRecord::Association,因此您可以在调用它时使用limit(或其他activerecord 函数)跟随它。

    【讨论】:

    • 我希望将不完整的事务保留为 ActiveRecord::Relation(而不是数组),所以我可以执行类似 user.incomplete_transactions.limit(15) 的操作
    • 你完全正确。不确定如何使用 has_many 进行操作,可以使用上述定义(在编辑中)。
    • 很好的解决方案,+1!我添加了一个使用 has_many 但在其他方面与您的非常相似的解决方案。
    • 不是我问题的确切答案,而是最实用的,并且完成了我想要的。谢谢!
    【解决方案2】:

    你可以使用下面的选项

    :conditions = ["(t.seller_id = #{self.id} and t.buyer_id is NULL) or (t.buyer_id = #{self.id} and t.seller_id is NULL)"]
    

    【讨论】:

    • 这在 Rails 3.1 中不起作用(您需要“=>”而不是“=”,并且您必须使用 proc 才能访问 self.id。
    • 更正语法没有帮助。它仍然失败,因为它试图加入不存在的 user_id 字段上的 transactions 表。
    【解决方案3】:

    假设您使用的是 rails 3.2,我建议您创建命名范围

    class Transaction
      belongs_to :seller, :class_name => 'User'
      belongs_to :buyer, :class_name => 'User'
    
      scope :incomplete_sales, :conditions => { :buyer_id => nil }
      scope :incomplete_purchases, :conditions => { :seller_id => nil }
    end
    

    那么你就可以像这样访问不完整的了,

    user.selling_transactions.incomplete_sales
    user.buying_transactions.incomplete_purchases
    

    EDIT - 也更正了上述关联

    如果你想限制,你总是可以对数组执行以下操作

    user.selling_transactions.incomplete_sales[0,15]
    

    【讨论】:

      【解决方案4】:

      修好了!

      这与@DRobinson 的解决方案非常相似,但使用了 proc 和 has_many 定义 而不是定义本地方法。

      根据 3.1 发行说明,您现在可以在条件中使用 proc!

      在 proc 中,self 是关联所有者的对象,除非您急于加载关联,在这种情况下,self 是关联所在的类。

      class User < ActiveRecord::Base
        has_many :incomplete_transactions , :class_name => 'Transaction', 
          :conditions => proc { incomplete_sales + incomplete_purchases }
      
        has_many :incomplete_sales, :class_name => 'Transaction', :foreign_key => 'seller_id', :conditions => { :buyer_id => nil }
        has_many :incomplete_purchases, :class_name => 'Transaction', :foreign_key => 'buyer_id', :conditions => { :seller_id => nil }
      
        has_many :selling_transactions, :class_name => 'Transaction', :foreign_key => 'seller_id'
        has_many :buying_transactions, :class_name => 'Transaction', :foreign_key => 'buyer_id'
      end
      
      class Transaction < ActiveRecord::Base
        belongs_to :seller, :class_name => 'User'
        belongs_to :buyer, :class_name => 'User'
      
      # scope :incomplete_sales , :conditions => {:buyer_id => nil}
      # scope :incomplete_purchases , :conditions => {:seller_id => nil}
      end
      

      见:

      【讨论】:

      • 不行。 proc 生成 SQL 尝试访问 User 模型而不是 Transaction 模型上的 Seller_id 和 buyer_id。如果我对此更加明确(类似于 Loken Makwana 的回答),它仍然会失败,因为它正在尝试加入 user_id 字段上的 transactions 表,该字段不存在。
      • 是的,不幸的是它使用了 User 类,而不是 proc 中的 self 的 Transaction 类。我修好了它。与 DRobinson 的解决方案非常相似,但使用 has_many..
      • hmm.. 我得到“对象不支持#inspect”。结果应该是一个事务数组。可能的 Rails 错误?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 2014-01-26
      相关资源
      最近更新 更多