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.
精彩评论