The send method allows you to send a message (call a method) when you won't know the name of that method until runtime. In this particular example you're getting a list of attributes, printing each attribute name as well as its value. The only way to get the value is to actually call the method.
Use the public_send method when you want to call methods and properties dynamically on other objects. This ensures that you are not calling any private methods or properties.
In the code you posted, *args simply indicates that the method accepts a variable number of arguments in an array called args . It could have been called anything you want (following the Ruby naming rules, of course).
respond_to is a Rails method for responding to particular request types.
send
sends a message to an object instance and its ancestors in class hierarchy until some method reacts (because its name matches the first argument).
Practically speaking, those lines are equivalent:
1.send '+', 2
1.+(2)
1 + 2
Note that send
bypasses visibility checks, so that you can call private methods, too (useful for unit testing).
If there is really no variable before send, that means that the global Object is used:
send :to_s # "main"
send :class # Object
send is a ruby (without rails) method allowing to invoke another method by name.
From documentation
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
http://corelib.rubyonrails.org/classes/Object.html#M001077
One of the most useful feature I think with .send method is that it can dynamically call on method. This can save you a lot of typing. One of the most popular use of .send method is to assign attributes dynamically. For example:
class Car
attr_accessor :make, :model, :year
end
To assign attributes regularly one would need to
c = Car.new
c.make="Honda"
c.model="CRV"
c.year="2014"
Or using .send method:
c.send("make=", "Honda")
c.send("model=", "CRV")
c.send("year=","2014")
But it can all be replaced with the following:
Assuming your Rails app needs to assign attributes to your car class from user input, you can do
c = Car.new()
params.each do |key, value|
c.send("#{key}=", value)
end
Another example, similar to Antonio Jha's https://stackoverflow.com/a/26193804/1897857
is if you need to read attributes on an object.
For example, if you have an array of strings, if you try to iterate through them and call them on your object, it won't work.
atts = ['name', 'description']
@project = Project.first
atts.each do |a|
puts @project.a
end
# => NoMethodError: undefined method `a'
However, you can send
the strings to the object:
atts = ['name', 'description']
@project = Project.first
atts.each do |a|
puts @project.send(a)
end
# => Vandalay Project
# => A very important project
send
is another way of "calling a method". Example:
o = Object.new
o.send(:to_s) # => "#<Object:0x00005614d7a24fa3>"
# is equivalent to:
o.to_s # => "#<Object:0x00005614d7a24fa3>"
Send lives in the Object class.
The benefit of this approach is that you can pass in the method you want to call as a parameter. Here is a simple example:
def dynamically_call_a_method(method_name)
o = Object.new
o.send method_name
end
dynamically_call_a_method(:to_s) # => "#<Object:0x00005614d7a24fa3>"
You can pass in the method you want to be called. In this case we passed in :to_s
. This can be very handy when doing ruby metaprogramming, because this allows us to call different methods according to our different requirements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With