Rails能够在Array上调用我的类方法

时间:2014-03-10 15:46:56

标签: ruby-on-rails

考虑到我在每个数据库中都有以下类和一些记录:

class User < ActiveRecord::Base
  has_many :user_roles
  has_many :roles, :through => :user_roles
end

class Role < ActiveRecord::Base
  has_many :user_roles
  has_many :users, :through => :user_roles

  def self.method1
    "boo!"
  end
end

为什么User.first.roles.method1成功运作?我以为User.first.roles返回一个Array,其类没有定义method1。

> User.first.roles.method1
=> "boo!"

当然,Role.all.method1会按照我的预期抛出未定义的方法错误。

我的堆栈:Ruby 1.9.3p484,Rails 3.2.13

4 个答案:

答案 0 :(得分:1)

User.first.roles将返回您的数组,因此您无法在数组上调用您的方法

您可以调用此类方法

User.first.roles.collect{|role| role.method1}

答案 1 :(得分:1)

实际上它不是一个数组。 它是ActiveRecord :: Associations :: CollectionProxy 你可以在这里查看定义 activerecord / lib / active_record / associations / collection_proxy.rb

它更改了method_missing,它将所有请求发送到父类。

答案 2 :(得分:1)

好的 - 我明白你现在在问什么 - 我想包括我在内的很多人都对这个问题感到困惑,抱歉。我认为这种混乱是因为你重写了这个问题,因为“我能做到这一点”是一个非常模糊和广泛的问题。

我认为你所要求的,具体而言,可以改为“如果我在一个Role对象数组上调用一个Role类级别方法(”method1“),从User.first.roles返回,然后它返回调用Role.method1的结果相同。不应该失败,因为Array没有那个方法吗?“

答案是当rails返回关联的结果时,它会混合一个模块(或更可能是一堆模块),这会增加额外的方法。其中一种方法是method_missing,它试​​图在已经收集的类上调用该方法。所以,它仍然是一个数组,但它是一个带有额外方法的数组。

如果你想看看它发生了什么,把raise "BANG!"放在你的method1方法中,然后再次调用你的代码:在堆栈跟踪中,你将能够看到魔法发生的位置。

答案 3 :(得分:0)

在Ruby中,您可以使用“map”方法(也就是“收集” - 我更喜欢“收集”自己)来调用相同的方法(或者更一般地,运行相同的代码块),因为在Java是一个“地图”,我们称之为ruby中的“哈希”。

例如

User.first.roles.map{|role| role.method1}
=> #an array of the values of method1

我不确定这是不是你想做的,你的问题不是很清楚。

编辑:我刚想到你想在一个角色而不是数组上调用method1。在那种情况下,你可以说

User.first.roles.first.method1

假设您确实想要第一个角色对象。