Symbol to method call
You could use Object#public_send
method:
def conveyqnces_nb(symb)
User.public_send(symb).length
end
or, if you would like, Object#send might be suitable. The difference is that send
allows to call private and protected methods, while public_send
acts as typical method call - it raises an error if method is private or protected and the caller object isn't allowed to call it.
Ruby on Rails using Symbols in calling methods
For the first example, that's right. The before_action
filter allows passing a method name as Symbol or String as its argument. But to create an instance of Event
you need several different values, and for that, hashes are commonly used.
If you debug your code and check what event_params
is, you're more likely to see it's an ActionController::Parameter
object, which responds to a method to_h
(and/or to_unsafe_h
), and that's enough to create an instance of an ApplicationRecord inherited class.
So, for the first case you're invoking before_action
with a Symbol, but in the second case Event.new
is receiving the value event_params
holds, which is a method accessible in your controller, but that evaluates to an ActionController::Parameter
instance.
:event_params
is a Symbol, because you constructed it that way by prefixing the identifier (name) with a :
, in the other hand event_params
should be a method and/or local variable, since it does not have any other way to identify as it's.
Depending on the value of event_params
, they could be the same, for instance;
event_params = :event_params
# => :event_params
event_params == :event_params
# => true
In that sense, they do are the same because they point to the very same object;
event_params.object_id
# => 2155228
:event_params.object_id
# => 2155228
But what you need to understand is :
makes a Hash (when valid) and event_params
makes a local variable and/or method.
How method name is converted into a symbol in Ruby?
it's not clear for me, how Ruby converts name of method into :symbol?
That's the way Method#name
works, it returns the name of the method as a symbol:
m = "foo".method(:size) #=> #<Method: String#size>
m.name #=> :size
m.call #=> 3
All methods referencing other methods usually work this way. For example, Object#methods
returns a array of method names:
"foo".methods
#=> [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, ...]
In method definition we give it name
meth
... but if we want check, does any method exist, we give intomethod_defined
symbol:meth
meth
would be a reference to a variable or another method, whereas :meth
is just a symbol:
meth = :foo
Mod.method_defined? meth #=> false, equivalent to Mod.method_defined? :foo
Mod.method_defined? :meth #=> true
Ruby - Call method from a symbol
you should explicitly convert String to Symbol
extract_locale_from_country(deal.country).to_sym
How are symbols used to identify arguments in ruby methods
Symbols and hashes are values like any other, and can be passed like any other value type.
Recall that ActiveRecord models accept a hash as an argument; it ends up being similar to this (it's not this simple, but it's the same idea in the end):
class User
attr_accessor :fname, :lname
def initialize(args)
@fname = args[:fname] if args[:fname]
@lname = args[:lname] if args[:lname]
end
end
u = User.new(:fname => 'Joe', :lname => 'Hacker')
This takes advantage of not having to put the hash in curly-brackets {}
unless you need to disambiguate parameters (and there's a block parsing issue as well when you skip the parens).
Similarly:
class TestItOut
attr_accessor :field_name, :validations
def initialize(field_name, validations)
@field_name = field_name
@validations = validations
end
def show_validations
puts "Validating field '#{field_name}' with:"
validations.each do |type, args|
puts " validator '#{type}' with args '#{args}'"
end
end
end
t = TestItOut.new(:name, presence: true, length: { min: 2, max: 10 })
t.show_validations
This outputs:
Validating field 'name' with:
validator 'presence' with args 'true'
validator 'length' with args '{min: 2, max: 10}'
From there you can start to see how things like this work.
Calling private methods by symbol name in Ruby
After a fair amount of searching, I found an alternative answer than Object#send
, that has an unanticipated feature benefit. The solution is to use the Object#method
to return a Method
object for the symbol name.
A Method
object is a Proc
-like callable object, so it implements the #call
interface, which fits the bill nicely. Object
has many such useful helpers defined in its interface.
In context of the original question, this is how it works:
#tests
[:test_value_1, :test_value_2, :test_value_3].each do |method|
data.each do |test|
value = test[0]
expected_result = test[1]
puts "#{method}: #{self.method(method).call(value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'"
end
end
The important bits are:
self.method(method).call(value)
This will convert the symbol name to a Method
object, and then invoke the method with value
supplied as the parameter. This works roughly equivalently to the send
method solution, in functional terms. However, there are some differences to note.
send
is going to be somewhat more efficient, as there's no overhead in the conversion to a Method
. Method#call
and send
use different internal calling mechanisms, and it appears that send
has less call overhead, as well.
The unanticipated feature of using Object#method
is that the Method
object is easily converted to a Proc
object (using Method#to_proc
). As such, it can be stored and passed as a first-class object. This means that it can be supplied in place of a block or provided as a callback, making it useful for implementing flexible dispatch solutions.
Related Topics
Rake Assets:Precompile Gets Killed When There Is a Console Session Open in Production
Circular Dependency Detected While Autoloading Constant When Loading Constant
Rails: How to Get a File Extension/Postfix Based on the Mime Type
Deploy with Capistrano Failing
Removing Child Root Nodes in Rabl
Deleting While Iterating in Ruby
Rails 4 - Syntax Error, Unexpected Tidentifier, Expecting End-Of-Input
How to Change the Zone Offset for a Time in Ruby on Rails
Cannot Load Such File -- 1.9/Bcrypt_Ext (Loaderror)
How to Create a List of Months Between Two Dates in Rails
How to Validate the Presence of a Belongs to Association with Rails
Creating a Hash with Values as Arrays and Default Value as Empty Array
<Rubygems> How to Change Gem Environment Settings
How to Add Child Nodes in Nodeset Using Nokogiri
Ruby Split String by Repeating Characters or a Space
How to Parse Consecutive Tags with Nokogiri
Rails: Pg::Insufficientprivilege: Error: Permission Denied for Relation Schema_Migrations