Rails 4允许您对has_many
关系进行范围调整:
class Customer < ActiveRecord::Base
has_many :orders, -> { where processed: true }
end
因此,只要您执行customer.orders
,您就只能获得已处理的订单。
但是如果我需要使where
条件动态化呢?如何将参数传递给范围lambda?
例如,我只希望订单显示客户当前在多租户环境中登录的帐户。
以下是我所拥有的:
class Customer < ActiveRecord::Base
has_many :orders, (account) { where(:account_id => account.id) }
end
但是,在我的控制器或视图中,我如何通过正确的帐户?在我做的时候使用上面的代码:
customers.orders
我得到账户ID为1的所有订单,看似随意。
答案 0 :(得分:26)
方法是为has_many
范围定义额外的扩展选择器:
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)
该方法在Association Extension
负责Rails Association
页面中进行了描述。
要访问嵌套方法中的Customer
记录,您只能访问self
对象,它应具有当前Customer
记录的值。
rails的Sinse(大约5.1)你可以将模型范围与相同类型的其他模型 has_many 范围合并,例如,你可以在下面的代码中编写相同的代码。两种型号:
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)
答案 1 :(得分:23)
传入已定义的类的实例。在您的情况下,您将传递客户,然后获得该帐户。
来自API http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
有时在构建查询时访问所有者对象很有用。所有者作为参数传递给块。例如,以下关联将查找用户生日时发生的所有事件:
class User < ActiveRecord::Base
has_many :birthday_events, ->(user) { where starts_on: user.birthday },
class_name: 'Event'
end
在你的例子中,它将是:
class Customer < ActiveRecord::Base
has_many :orders, ->(customer) { where(account_id: customer.account.id) }
end
答案 2 :(得分:0)
我知道这已经过时了,但由于还没有接受答案,我认为加上我对这一点的看法不会伤害任何人。
问题在于,每当您将范围传递给has_many
关系时,将所有者类的实例作为参数传递不仅是可能的,而且是唯一的可能性传递一个论点。我的意思是,你不允许传递更多的参数,而且总是是所有者类的实例。
所以@RobSobers,当你
“获取id为1的帐户的所有订单,看似随意。”
这不是任意的,您获得了id
customer
所谓的关系的所有订单。我想你的代码就像是
Customer.first.orders(@some_account_which_is_ignored_anyway)
似乎has_many
关系并不意味着接受参数。
就个人而言,我更喜欢@МалъСкрылевъ的解决方案。