如何将参数传递给 Rails 4 中的 has_many 关联范围?

Posted

技术标签:

【中文标题】如何将参数传递给 Rails 4 中的 has_many 关联范围?【英文标题】:How do I pass an argument to a has_many association scope in Rails 4? 【发布时间】:2014-06-01 02:16:40 【问题描述】:

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 的帐户的所有订单,这似乎是任意的。

【问题讨论】:

这样的? scope:account lambda |account| :conditions =&gt; :account_id =&gt; account 并查看此 SO ***.com/questions/16203576/… @Pavan 在我的案例中,关键区别在于需要传递的值不是来自另一个模型的值,而是只有控制器知道的(即当前帐户)。 【参考方案1】:

方法是定义额外的扩展选择器到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)

Rails Association 页面中的 Association Extension head 中描述了该方法。

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

Sinse of rails(大约 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)

【讨论】:

如果您希望它成为您的条件的一部分,是否可以在 by_account 方法中访问客户记录?【参考方案2】:

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

来自 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

【讨论】:

这个答案预设了客户和客户之间的 1:1 关系。然而,该问题指定了一个相反的场景,即一个多租户系统,一个给定的客户可以代表多个账户下订单。【参考方案3】:

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

问题在于,每当您将作用域传递给has_many 关系时,将所有者类的实例作为参数传递不仅是一种可能性,而且是唯一可能传递一个争论。我的意思是,您不能传递更多参数,而这个参数将始终是所有者类的实例。

所以@RobSobers,当你

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

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

Customer.first.orders(@some_account_which_is_ignored_anyway)

似乎has_many 关系并不意味着接受参数。

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

【讨论】:

以上是关于如何将参数传递给 Rails 4 中的 has_many 关联范围?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地将参数传递给rails表单

如何在 Rails 中使用环境将参数传递给 Rake 任务? [复制]

如何将查询参数传递给 Rails API 控制器?

Rails:将参数传递给关注点

在rails应用程序中通过ajax请求将参数传递给控制器

将参数传递给Lua 4中的函数[重复]