Determine the class to which a method belongs in rails - ruby-on-rails

Ap::Application.routes.draw do
resources :accounts
end
I want to know the class or module to which the "resources" method belongs. If i search for "resources" method in http://apidock.com/rails/ (in the search text box provided), a list of classes are appearing which has the method name "resources". Confused, with knowing the origin of the method.
Is their any command which i can use in puts to see the origin.
The question is bit of beginners level.
Thanks

Ruby is an object-oriented language. And while methods aren't objects in Ruby, you can ask Ruby to give you a Method object representing the method in question, and then you can simply tell that Method to give you its owner:
Ap::Application.routes.draw do
p method(:resources).owner
end

More enlightening than searching for resources is searching for draw, since that method must do something with the block passed in.
Indeed, we find the source code for draw, which shows that the supplied block is executed in the context of a Mapper, which includes Resources, which (finally!) defines resources

Assume that current_user is an instance of class User, you can call method function to check whether the method_name belong to class User. Example
current_user.method(:method_name).owner
User.method(:method_name).owner
Hope this help you!

Related

How to find the module/class where a method comes from in Rails?

Using Rails, I was originally looking for a way to use the resource path helper methods (e.g. users_path) in models, and this gives me the answer: I can use Rails.application.routes.url_helpers.users_path .
Good, but in general and specifically in Rails, how can one find what module/class a method comes from? Are reading the source code or some official docs the only way to find it? Isn't it possible to, for example, directly check in the debug console to get Rails.application.routes.url_helpers from users_path ?
I think what you are looking for is similar to this question How to find where a method is defined at runtime?.
In short, in Ruby 2+, (either of) the following would return an 2-element Array of the filename and line-number:
method(:users_path).source_location
my_object.method(:my_method).source_location
# => ["/My/Ruby/Code/some-module.rb", 123]
You can then work out the Module or Class name for the method.
[Added in EDIT]
To get the module name, you can use method(:users_path).owner instead: cf., Answer1 and answer2.
However, Rails uses a lot of meta programming and dynamic assignments. The url-helper like users_path in the question is one of them.
Quote of #spickermann's comment to the question
users_path is defined by meta programming and therefore you will not find a method definition with that method name at all in the code.
Quote of #Stefan's comment to the question
there might multiple such objects. You have to identify the one "closest" to the current self.
Specifically, url_helpers are defined in actionpack-6.*/lib/action_dispatch/routing/route_set.rb for Rails 6.0 and you see the method generate_url_helpers is responsible to (dynamically) generate it. That is why method(:users_path).owner returns something like #<Module:0x0000000117346e18>, which is not really helpful. Even method(:users_path).source_location simply points to the line of
mod.define_method(name) do |*args|
(or something like that, depending on the Rails version), which indicates that the object is dynamically generated.
In consequence, I doubt if there is any easy way to do-all to derive a Rails object (class/module), say, Rails.application.routes.url_helpers from the given helper function like users_path. But an analysis using a combination of methods like owner and source_location would be of great help to pinpoint it and might, in some cases, give you an answer you are looking for.
I note that, as far as this specific case is concerned, the error message written in actionpack-6*.*/lib/abstract_controller/url_for.rb would be of help – quote:
In order to use #url_for, you must include routing helpers explicitly.
For instance, include Rails.application.routes.url_helpers.

before and after method call on models in ruby on rails, do "thing"

I'm pondering a way to wrap method calls on models in RoR. (The reason for this being a custom model caching system that would allow me to do a lot of work behind the scenes on data being created by some large models that my clients are using without having to constantly load those models and parse ALL the very fat data to get the output. I could just send the output already calculated and stored in a different place and a delayed job behind the scenes that does the calculation and stores it isn't really an option due to how the data is collected or the egregious volume in question.. Its hard to explain.)
So given that I have an instance of this extremely simple class;
class Person < ApplicationRecord
attr_accessor: :name
has_many :books
has_many :friends
end
How would I go about writing something that allows me to programmatically "intercept" ALL (or all except those I specifically say not to) method calls to a given class.
So if someone does this;
bob = Person.find 1
puts bob.name
puts bob.friends.count
I could have this system know to do something before .name is called or before .friends is called. Something like checking to see if we already have an answer to this question somewhere else..
I was looking at using a before_hook and override the method_added hook to prepend my code per this question: call before methods in model on ruby but the issue was it works for .name but not for .friends. I assume this is due to some rails magic as friends just gives you the active record call per normal without actually executing the hook..
I'd love to be able to do something like;
class Person < ApplicationRecord
include CustomCachableThingy
before_hook :friends, :name, except: :books
attr_accessor: :name
has_many :books
has_many :friends
end
Again this is a very simple example. The models in question are way too big and have way too much data. So trying to find something I can make work for my client.
Thoughts?
If you really want to wrap every method call (or even the ones defined by the target class itself), you can define a module that does 2 things,
Get all the instance_methods and wraps them with your custom code
Override the method_added method call and wrap every new method that is added with the same custom code
A good example using this strategy is answered here. You can customize this to take additional except configuration and exclude those methods.
The meta-programming going on here is to rewrite each method as it is injected into the instance.
Another option is to wrap only specific method calls with your custom code, if you know which ones you'll need to cache. It will be less overhead and cleaner implementation.
For implementation, you can use the same meta-programming approach as described in the first example. One more approach can be to add an alias to the original method and rewrite the method to include your hook. Something like,
def add_before_hook(method_name)
class_eval do
without = :"#{method_name}_without_before_each_method"
alias_method without, method_name
define_method method_name do |*args, &block|
puts 'called before'
send without, *args, &block
end
end
end
The problem with the second approach is that it pollutes your method namespace by adding a duplicate method for each of your instance methods.

Why does Active Record use module_eval internally for certain features?

I've noticed a few places in the Rails source code where module_eval is used. One place is in ActiveRecord::Enum and another is in ActiveRecord::Store. I'm familiar with class_eval and instance_eval and have used them for extending the functionality of existing classes or objects, but in the case of module_eval, it seems like it's serving a different purpose.
In both cases they are using a similar pattern to define the module:
def _store_accessors_module
#_store_accessors_module ||= begin
mod = Module.new
include mod
mod
end
end
If the module is being included in the class it's defined in, what benefit is there to defining related methods in a nested module like this? Is it better isolation of code? The reason I'm asking is because I have a gem that adds functionality to Active Record, and am wondering if this approach is more of a "best practices" way of doing the same thing. Here's the relevant source code of my gem for reference.
The reason the methods are being defined in a nested module is so that users may override the methods and still have access to super to get at the original functionality. Recall that when you include modules in Ruby they are inserted into the ancestors list for the current class and super works by simply iterating through the ancestors array, looking for the first object that responds to the current method. To this end, the name of the module is not important as it is simply an inheritance-chain-like delivery mechanism. So that's why they define just an anonymous new module and include it on the fly.
If you look at the blame view for the 2 examples you listed, you can see the reasoning behind the changes. The commit message in the ActiveRecord::Store example makes the case pretty well. As you can see, they're adding the ability to override the accessor definition color and tack on to the results of the original method via super || 'red'. Whereas, in the original implementation, one would have to both override the color accessor method and then do the same work as the original accessor method, i.e. call read_store_attribute(:settings, :color) || 'red'. So it's all about not being forced to reproduce the internals or using alias method chains to augment the functionality of the dynamically defined methods.
I'm not sure whether this is a useful feature in your gem, but I'm guessing maybe not as your accessors seem to be returning well-defined object enum-related objects. But, of course, that's up to you and the gem's users :).

Rails methods that can work with multiple tables and column names

hope you are all well!
I have a general enquiry that I was wondering if some kind soul could help with? it's really a matter of curiosity at the minute but I feel like it could be quite a useful snippet of information in the future.
Is it possible to write a method that can be passed the name of a table and the name of an attribute (column) and perform operations on these? I suppose the main use for such methods would be for keeping code dry when doing repetitive operations on tables.
as an example (though entirely a toy example) suppose I had a method:
def switch(table_name, column_name)
#do some operation on table_name.column_name
end
I have figured out how to access a table by doing something like this:
def model_for_table(table_name)
table_name.to_s.classify.constantize
end
this will take an underscored_lowercase_string and return the table name so that something like model_for_table("registered_user").find(1) though this is unnecessary in situations where the table name can be hard coded
But it does not like model_for_table("registered_user").column_name as used in the example above. is there something analogous to the model_for_table method supplied above to turn a string into an attribute name?
Does anybody know how I could implement this? is it even possible?
Thanks in advance
The problem is that you need an instance of the model you are working on in order to access a column. If you have a RegisteredUser model try doing (in a Rails console) RegisteredUser.id (or any attribute name). It won't work. However, if you did RegisteredUser.first.id (assuming you have one saved) it will work.
So it depends on what you want to accomplish. If your switch method is meant to do something with instances of your model, then this can still work.
def switch(table_name, column_name)
model = model_for_table(table_name)
model.all.each do |model_instance|
puts "model_instance #{column_name} is #{model_instance.send(column_name)}"
end
end
Note: The send method takes in a symbol or a String and executes the method with that name on the instance it was called on. This is a normal Ruby thing, not a Rails thing.
Remember, your model_for_table method is returning back the class, not an instance.

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.

Resources