So I have two associated models Users and Magazines. They are associated by a has_many :through relationship via Subscriptions. So this is what it looks like:
class User < ActiveRecord::Base
has_many :subscriptions
has_many :magazines, :through => :subscriptions
end
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :magazine
end
class Magazine < ActiveRecord::Base
has_many :subscriptions
has_many :users, :through => :subscriptions
end
Users have a boolean attribute called paid
. I only want users where paid == true
to be able to subscribe to any magazines. How can I set up a conditional association like this? Thanks in advance for the help!
For the associations, you can pass a lambda before the hash options. In this lambda you can specify conditions, ordering, etc.
class Magazine < ActiveRecord::Base
has_many :subscriptions
has_many :users, ->{ where(users: {paid: true}) }, through: :subscriptions
end
For users, you could do something like this:
class User < ActiveRecord::Base
has_many :subscriptions
has_many :magazines, through: :subscriptions
def magazines
self.paid ? super : Magazine.none
end
end
While it's neat, the above might behave unpredictably when you're joining tables e.g. User.joins(:magazines)
might ignore the paid
condition or crash.
A better alternative:
class User < ActiveRecord::Base
has_many :subscriptions
has_many :magazines,
->{ where("subscriptions.user_id IN (
SELECT id FROM users WHERE users.paid = 't')") },
through: :subscriptions
end
That where
in the lambda might be replaceable by a joins
like so:
joins(subscriptions: :user).where(users: {paid: true})
But I think that'll join subscriptions
twice - once for the lambda and once for the association. I'm not certain. If so, and if that bothers you, then:
joins("INNER JOIN users ON (users.id = subscriptions.user_id)").
where(users: {paid: true})
or:
joins("INNER JOIN users ON (
(users.id = subscriptions.user_id) AND (users.paid = 't')
)")
Also, I think you mislabeled your Subscription
model as Registration
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다