Why / how can you call the model class methods for the set / array returned by the link?

So, today I found an interesting code, and it caught my attention. I did not think it was possible. Line of code:

@post.comments.approved_comments 

It looks good, right? But in fact, what happens is that the approved_comments method is called on the Array object instance, which is returned by the has_many relation (i.e. the Message has many comments). Even more interesting is that approved_comments is a class method defined in the Comment model.

Which puzzles me a bit, I thought you could not relate the relationship, not directly, because the relationship returns an Array object, not an ActiveRecord::Relation object. I asked a question related to this before, and the answer I was given is that you can bind relationships using the scoped method or one of many methods that are added to the array due to the relationship (i.e., Section 4.3.1 Methods added by has_many ).

What puzzles me is that approved_comments is the method we wrote; this is not a method added by the has_many relationship method. So how is it possible that I can access it? Even more confusing, how can I access it from an Array object?

There is, of course, some kind of magic. I am wondering if anyone can point me to some documentation or if any experts will answer this. Not a big problem, because it works pretty well, but I would love to know how easy it is to educate myself.

Thanks for the help in advance!

code

Message

 class Post has_many :comments end 

A comment

 class Comment def self.approved_comments where(:approved => true) end end 

Using

 @post.comments.approved_comments 
+4
source share
2 answers

It relates to the method of loading an ActiveRecord request. It is not executed until you call the method on the object. As a result, it can effectively build the entire query. HOWEVER, what you are trying to do is easier to accomplish using the scope:

 class Post has_many :comments end class Comment scope :approved_comments, where(:approved => true) end 

You can now comment on Comment.approved_comments to get ALL approved comments or @ post.comments.approved_comments to get approved comments for posting.

In addition, the scope may take optional parameters. If you want to receive all messages approved from the last visit by the User (for example):

 class Comment scope :approved_since, lambda{ |date| where(['approved_at > ?', date]) } end 

Then you can call: @post.comments.approved_since(@user.last_login) for example

See the Rails ActiveRecord Named Scope for more information.

+2
source

It describes exactly what you are asking for http://railscasts.com/episodes/5-using-with-scope

+1
source

Source: https://habr.com/ru/post/1334437/


All Articles