34

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 的帐户的所有订单。

4

3 回答 3

39

方法是定义额外的扩展选择器到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在 RailsAssociation页面的 head 中进行了描述。

要访问Customer嵌套方法中的记录,您只需访问self对象,它应该具有当前Customer记录的值。

轨道的罪恶(大约 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)
于 2015-11-26T12:50:30.403 回答
30

你传入你定义的类的一个实例。在您的情况下,您将传递一个客户,然后获取该帐户。

来自 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
于 2014-12-03T02:09:03.640 回答
0

我知道这是旧的,但由于尚未接受任何答案,我认为添加我的观点不会伤害任何人。

问题是,每当您将范围传递给has_many关系时,将所有者类的实例作为参数传递不仅是一种可能性,而且是传递参数的唯一可能性。我的意思是,你不能传递更多的参数,而这个永远是所有者类的实例。

所以@RobSobers,当你

“获取id为1的账户的所有订单,看似随意。”

这不是任意的,你得到所有的订单,idcustomer调用了关系。我猜你的代码是这样的

Customer.first.orders(@some_account_which_is_ignored_anyway)

似乎has_many关系并不意味着接受论点。

就个人而言,我更喜欢@МалъСкрылевъ的解决方案。

于 2016-11-22T08:16:41.920 回答