Reputation: 2450
I have a Transaction
model. A transaction has a seller_id
column and a buyer_id
. Both are filled with a User
ID.
so:
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
What I want to do is add a has_many
to User
to associate transactions that are incomplete, whether the User
is the seller or the buyer.
class User
has_many :incomplete_transactions, :class_name => 'Transaction', :conditions => ???
end
_
I wrote it out in pure SQL, and got the results I wanted. The join in my SQL is:
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))
How do I translate that join
to a has_many
association?
EDIT:
I was hoping to keep incomplete_transactions as a ActiveRecord::Relation (instead of an Array), so I can do something like user.incomplete_transactions.limit(15)
Thanks.
Upvotes: 1
Views: 7775
Reputation: 33732
Fixed it!
This is very similar to @DRobinson's solution, but using a proc and a has_many definition instead of defining a local method.
According to the 3.1 release notes you can now use a proc in a condition!
Inside the proc, self is the object which is the owner of the association, unless you are eager loading the association, in which case self is the class which the association is within.
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
See:
Upvotes: 0
Reputation: 1
Assuming you are using rails 3.2, I'd recommend creating named scopes
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
Then you can access the incomplete as such,
user.selling_transactions.incomplete_sales
user.buying_transactions.incomplete_purchases
EDIT - also corrected associations above
If you want to limit, you can always just do the following with an array
user.selling_transactions.incomplete_sales[0,15]
Upvotes: 0
Reputation: 3848
you can use option like below
:conditions = ["(t.seller_id = #{self.id} and t.buyer_id is NULL) or (t.buyer_id = #{self.id} and t.seller_id is NULL)"]
Upvotes: 0
Reputation: 4471
Similar answer to pdevisser's: You could use something similar to the answer given on this question: https://stackoverflow.com/a/307724/624590
Which would basically result in:
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
EDIT: Alright, not totally sure how to set it up the way you wish (using has_many), but something along these lines might work for you:
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
The where statement will return an ActiveRecord::Association
, so you can follow it with limit (or other activerecord functions) when calling it.
Upvotes: 1