Determine the Class to Which a Method Belongs in Rails

Determine the class to which a method belongs in rails

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

checking if a method is defined on the class

Use this:

C.instance_methods(false).include?(:a)
C.instance_methods(false).include?(:b)
C.instance_methods(false).include?(:c)

The method instance_methods return an Array of methods that an instance of this class would have. Passing false as first parameter returns only methods of this class, not methods of super classes.

So C.instance_methods(false) returns the list of methods defined by C.

Then you just have to check if that method is in the returned Array (this is what the include? calls do).

See docs

How to find where a method is defined at runtime?

This is really late, but here's how you can find where a method is defined:

http://gist.github.com/76951

# How to find out where a method comes from.
# Learned this from Dave Thomas while teaching Advanced Ruby Studio
# Makes the case for separating method definitions into
# modules, especially when enhancing built-in classes.
module Perpetrator
def crime
end
end

class Fixnum
include Perpetrator
end

p 2.method(:crime) # The "2" here is an instance of Fixnum.
#<Method: Fixnum(Perpetrator)#crime>

If you're on Ruby 1.9+, you can use source_location

require 'csv'

p CSV.new('string').method(:flock)
# => #<Method: CSV#flock>

CSV.new('string').method(:flock).source_location
# => ["/path/to/ruby/1.9.2-p290/lib/ruby/1.9.1/forwardable.rb", 180]

Note that this won't work on everything, like native compiled code. The Method class has some neat functions, too, like Method#owner which returns the file where the method is defined.

EDIT: Also see the __file__ and __line__ and notes for REE in the other answer, they're handy too. -- wg

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

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.

When creating a method without a class in the Rails console, what class is the method under?

Ruby creates a object of Object class when you run your console, so all methods are private instance methods of Object class, you can run this to verify.

        Object.private_instance_methods.include? :test

So when you define your methods in console It is interpreted to this

class Object
def test
puts "hi"
end
end

More explanation

I was wanted to explain this but a detailed article is written on this topic,

https://www.sitepoint.com/rubys-top-self-object/

determine the context on which a method runs

1 & 2) We are defining an instance method of Class which means it will be a class method for other objects.

3) It is run within Class object, so it is a method of Class or one of it's ancestors (it's actually in BasicObject)

4) It is run in context of Class object (or of object extending it)

Given a class, see if instance has method (Ruby)

I don't know why everyone is suggesting you should be using instance_methods and include? when method_defined? does the job.

class Test
def hello; end
end

Test.method_defined? :hello #=> true

NOTE

In case you are coming to Ruby from another OO language OR you think that method_defined means ONLY methods that you defined explicitly with:

def my_method
end

then read this:

In Ruby, a property (attribute) on your model is basically a method also. So method_defined? will also return true for properties, not just methods.

For example:

Given an instance of a class that has a String attribute first_name:

<instance>.first_name.class #=> String

<instance>.class.method_defined?(:first_name) #=> true

since first_name is both an attribute and a method (and a string of type String).

Get list of a class' instance methods

You actually want TestClass.instance_methods, unless you're interested in what TestClass itself can do.

class TestClass
def method1
end

def method2
end

def method3
end
end

TestClass.methods.grep(/method1/) # => []
TestClass.instance_methods.grep(/method1/) # => ["method1"]
TestClass.methods.grep(/new/) # => ["new"]

Or you can call methods (not instance_methods) on the object:

test_object = TestClass.new
test_object.methods.grep(/method1/) # => ["method1"]

Rails: get belongs_to class_name

I think I've found what I'm looking for: ActiveRecord::Reflection class methods (the previous answers are helpful, but don't really answer the question)

I used the reflect_on_association class method to get the details of my :target association. So to get what I was looking for, I did:

UserEntry.reflect_on_association(:target).klass, which returned the User class.



Related Topics



Leave a reply



Submit