嵌套资源如何工作?

时间:2011-08-05 10:15:43

标签: ruby-on-rails resources

作为官方网站,我定义了两个模型PostCommentComment嵌套在Post

resources :posts do
  resources :comments
end

所以我可以使用@post.comments来访问帖子所拥有的所有评论。在控制台中:

$ post = Post.new()
$ post.comments.class
> Array

可是:

$ post.comments.respond_to?("build")
> true

为什么呢?数组的方法是build? Rails是怎么做的?我如何知道post.comments的其他隐藏方法?

2 个答案:

答案 0 :(得分:1)

首先,您的resources调用位于routes.rb文件中,该文件仅处理Rails的URL解析端。这与您的模型之间的关联无关,这些关联是使用相关模型文件中的has_manybelongs_to调用设置的。暂时忽略路线文件,因为它与问题的主要部分无关。

关于关联,您会发现post.comments没有向您返回Array,它实际上返回了ActiveRecord::Relation个对象。 Relation对象就像一个数组 - 实际上你在其上调用的任何非关系特定的方法(如build)实际上都传递给了{{ 1}} Array内容的表示。因此,当您调用Relation时,post.comments.length关联对象正在其内部数组上调用comments

其中一个后果是,调用.length实际上也会传递对{Array}的post.comments.class调用!

那么,.class对象实际上可以做什么?由于该关联是通过Relation电话设置的,因此您可以在has_many documentation中找到答案。类似地,has_many关联

答案 1 :(得分:0)

在ruby中,您可以添加或更改任何对象中的任何方法。您甚至可以向字符串实例添加新方法,例如:

x = "xyzzy"
x.name     # => NoMethodError: undefined method `name' for "xyzzy":String
x.instance_eval do
  class << self
    define_method(:name) {"I got a name"}
  end
end
x.class    # => String
x.name     # => "I got a name"

y = "other"
y.class    # => String
y.name     # => NoMethodError: undefined method `name' for "other":String

build方法可能已被“添加”到由comments访问者返回的由has_many宏创建的Array实例。 (正如Gareth指出的那样,Rails使事情变得复杂,并且关联不会以这种方式工作。但是,与作为透明代理工作相比,扩展对象可能是一种更“干净”的方式。考虑我的例子作为红宝石相关,而非铁路)

至于问题的第二部分,您可以通过访问其methods函数来了解给定对象的方法。它返回为此对象定义的所有(公共)方法的名称。 (如果您想要私有的,请参阅private_methods功能。)

在我的示例x.methods中还会包含新定义的“名称”方法,但y.methods不会。

ruby​​中还有其他功能,您可以使用它们检查对象。您可以在Ruby API documentation找到它们。 API可能在各种版本的ruby中有一些(通常是轻微的)更改。请参阅您正在使用的版本的文档。

如果你想检查一些方法的代码,那么它可能有点问题,因为函数的“可执行代码”可能通过多种方式创建:它可能是一个副本(别名)< / em>的另一个函数,可以使用eval函数动态创建,依此类推。

知道方法的名称,你可以'grep'你可用的源代码,也许你想要的方法还没有动态创建。

我看到项目ParseTree仍然存在。如果你真的想知道你没有来源的函数的代码,也许你会觉得它很有帮助。