Rails 4 lets you scope a has_many
relationship like so:
class Customer < ActiveRecord::Base
has_many :orders, -> { where processed: true }
e
I know this is old, but since no answer was accepted yet, I thought adding my views on the point would harm no one.
The problem is that whenever you pass a scope to a has_many
relationship, passing the instance of the owner class as an argument is not only a possibility but it is the only possibility to pass an argument. I mean, you are not allowed to pass more arguments, and this one will always be the instance of the owner class.
So @RobSobers, when you
"get all orders for account with an id of 1, seemingly arbitrarily."
it is not arbitrary, you get all orders with th id
of the customer
you called the relation on. I guess your code was something like
Customer.first.orders(@some_account_which_is_ignored_anyway)
Seems like has_many
relation was not meant to accept arguments.
Personally, I prefer the solution of @МалъСкрылевъ.
The way is to define additional extending selector to has_many
scope:
class Customer < ActiveRecord::Base
has_many :orders do
def by_account(account)
# use `self` here to access to current `Customer` record
where(:account_id => account.id)
end
end
end
customers.orders.by_account(account)
The approach is described in Association Extension
head in Rails Association page.
To access the Customer
record in the nested method you just can access self
object, it should have the value of current Customer
record.
Sinse of rails (about 5.1) you are able to merge models scope with the othe model has_many scope of the same type, for example, you are able to write the same code as follows in the two models:
class Customer < ApplicationRecord
has_many :orders
end
class Order < ApplicationRecord
scope :by_account, ->(account) { where(account_id: account.id) }
end
customers.orders.by_account(account)
You pass in an instance of the class you have defined. In your case, you would pass in a customer and then get the account.
From the API http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Sometimes it is useful to have access to the owner object when building the query. The owner is passed as a parameter to the block. For example, the following association would find all events that occur on the user's birthday:
class User < ActiveRecord::Base
has_many :birthday_events, ->(user) { where starts_on: user.birthday },
class_name: 'Event'
end
In your example it would be:
class Customer < ActiveRecord::Base
has_many :orders, ->(customer) { where(account_id: customer.account.id) }
end