开发者

How do nested resources work?

As the official site, I defined two models Post and Comment. Comment is nested in Post.

resources :posts do
  resources :comments
end

So I can use @post.comments to access all comments a post own. In console:

$ post = Post.new()
$ post.comments.class
开发者_开发知识库> Array

But:

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

Why? An array has the method build? How did Rails do? And how can I know other hidden methods of post.comments?


Firstly, your resources calls are in your routes.rb file, which only deals with the URL parsing side of Rails. It's nothing to do with the associations between your models, which are set up using has_many and belongs_to calls in the relevant model files. Ignore the routes file for now as it's not related to the main part of your question.

With respect to associations, you'll find that post.comments is not returning you an Array, it's actually returning an ActiveRecord::Relation object. A Relation object is like an array - in fact any method you call on it which isn't relation-specific (like build) is actually passed on to an Array representation of the Relation's contents. So, when you call post.comments.length, the comments association object is calling .length on its internal array.

One of the consequences of this is that calling post.comments.class actually passes on the .class call to the Array too!

So, what can that Relation object actually do? Since the association is set up by the has_many call, you can find out in the has_many documentation. Similarly for a belongs_to association


In ruby you can add or change any method in any object. You can even add a new method to a string instance, for example:

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

That build method might have been 'added' to an instance of Array returned by the comments accessor, created by a has_many macro. (As Gareth pointed, Rails complicated things a little, and the associations do not work this way. However, extending the objects may be a more 'clean' way in comparison to working as transparent proxy. Consider my example as a ruby-related, not rails)

As for the second part of your question, you may know the methods of a given object by accessing its methods function. It returns the names of all the (public) methods defined for this object. (If you want private ones, see the private_methods function.)

In my example x.methods would include also the newly defined "name" method, but y.methods will not.

There are also other functions in ruby, with which you can examine the objects. You may find them in Ruby API documentation. The API may have some (usually slight) changes in various versions of ruby. See the documentation for the version you are using.

If you want to examine the code of some method, then it may be a little problem, because the "executable code" of a function may be created by many ways: it may be a copy (alias) of another function, it may be created dynamically by using eval function, and so on.

Knowing the name of the method you may 'grep' the source code you have available, and maybe the method you want has not been created dynamically.

I see that the project ParseTree is still alive. Maybe you will find it helpful, if you really want to know the code of a function to which you do not have sources.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜