【问题标题】:How do I pass an argument to a has_many association scope in Rails 4?如何将参数传递给 Rails 4 中的 has_many 关联范围?
【发布时间】: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 stackoverflow.com/questions/16203576/…
  • @Pavan 在我的案例中,关键区别在于需要传递的值不是来自另一个模型的值,而是只有控制器知道的(即当前帐户)。

标签: ruby-on-rails associations scopes


【解决方案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 关系并不意味着接受参数。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 1970-01-01
    • 2016-07-23
    • 2015-04-21
    相关资源
    最近更新 更多