Rails - How to use variable as part of method name - ruby-on-rails

I am trying to add variable name into method_name in rails. I am getting error.
**Controller ACTION**
=====================
def my_action(state)
method_#{state}
end
**Model methods**
====================
def method_start
end
def method_end
end
how to call method with variable name i am not getting.

Use Object.send to call method by name. For example,
def my_action(state)
if [:start, :end].include?(state)
model.send("method_#{state}")
end
end
Make sure to validate state variable for security. Object.send can call any method including private ones.

Related

Ruby - How to create a class variables to access in function

I want to create a function to set the instance variable like attr_reader
class Base
def exec
# get all functions to check
# if all functions return true
# I will do something here
end
end
And then I have a class inherit Base.
class SomeClass < Base
check :check_1
check :check_2
def check_1
# checking
end
def check_2
# checking
end
end
class Some2Class < Base
check :check_3
check :check_4
def check_3
# checking
end
def check_4
# checking
end
end
Because I only need 1 logic for executing in all classes but I have a lot the different checks for each class, I need to do it flexibly.
Please, give me a keyword for it.
Many thanks.
In order to have check :check_1 you need to define check as a class method:
class Base
def self.check(name)
# ...
end
end
Since you want to call the passed method names later on, I'd store them in an array: (provided by another class method checks)
class Base
def self.checks
#checks ||= []
end
def self.check(name)
checks << name
end
end
This already gives you:
SomeClass.checks
#=> [:check_1, :check_2]
Some2Class.checks
#=> [:check_3, :check_4]
Now you can traverse this array from within exec and invoke each method via send. You can use all? to check whether all of them return a truthy result:
class Base
# ...
def exec
if self.class.checks.all? { |name| send(name) }
# do something
end
end
end
SomeClass.new.exec # doesn't do anything yet
The self.class part is needed because you are calling the class method checks from the instance method exec.

Undefined local variable or method for module

I have module CurrencyExchange with following methods
CURRENCIES = %w(uah rub eur usd)
def available_currencies
CURRENCIES.join(' ').downcase.split.permutation(2)
end
and when i want to use available_currencies with
define_method
available_currencies.each do |(c1, c2)|
define_method(:"#{c1}_to_#{c2}") do |cr| ... end end
i have got an error
undefined local variable or method `available_currencies'
for CurrencyExchange:Module (NameError)
but when i use it like
CURRENCIES.join(' ').downcase.split.permutation(2).each do |(c1, c2)|
define_method(:"#{c1}_to_#{c2}") .... end end
it works fine
Why it happens?
I think you need to write def self.available_currencies
You try to create other method in the class and Ruby searches in the loop for a class method .available_currencies.
You have to change your class method .available_currencies into a instance method #available_currencies or create the methods in your initializer.
Method 1:
class MyClass
def self.available_currencies
# Your logic...
end
# Your logic...
end
Method 2:
class MyClass
def init
available_currencies.each do |c|
define_method(c) do
# Whatever you want to do ...
end
end
end
def available_currencies
# Your logic...
end
end
I would recommend you the first way since you maybe want to use the currencies in classes. I would recommend you the second way, if you want for example different currencies for different instances.
Happy coding :)

Calling a method inside model

I am trying to trigger a method from inside the model where it is defined. But I am getting an "undefined method `completed_mission_names'" when I try to start my server. Can anybody help me find what I'm doing wrong ?
class MenteeProfile < ActiveRecord::Base
# Update trackable attributes with succeeded missions
MenteeProfile.completed_mission_names
protected
def last_completed_mission_action
end
def self.completed_mission_names
end
end
Simplified to the max, you are trying to do this:
class A
A.foo
def self.foo
puts 'Calling foo!'
end
end
This does not work because the method foo is not defined when you try to invoke it. You must define it first, then you can call it. Like so:
class B
def self.foo
puts 'Calling foo!'
end
B.foo
end
You could also call just foo instead of B.foo from within the class definition. You can add the protected keyword anywhere you like, it will not have any impact on class methods whatsoever.

Ruby Converting a variable into a constant at runtime

I'm trying to create a module that will be included in many different classes. It needs to record the caller's path to the class file
so I can reference the path in later code. This code tries to add a method to the calling class, but fails because it just returns the current value of ##x.
# /home/eric/FindMe.rb
class FindMe
include GladeGUI
end
# /home/eric/GladeGUI.rb
module GladeGUI
def self.included(obj)
##x, = caller[0].partition(":") # this works ##x = "/home/eric/FindMe.rb"
obj.class_eval do
def my_class_file_path
return ????? # I want to return "/home/eric/FindMe.rb"
end
end
end
end
The GladeGUI module will be "included" in many different classes, so I can't just add code to the calling class. I need a way to make ##x compile into a constant value, so the method stored in the class looks like this:
def my_class_file_path
return "/home/eric/FindMe.rb"
end
How do I convert a variable to a constant in code?
Thanks.
It seems like you don't actually need it to be a "constant" - you just need some way to make the method return the correct value all the time and not allow other code to come along and change the value (with the current ##x solution, someone can just modify ##x and it will break)
The solution is to store the data in a local variable instead of a class or instance variable, and then access that local variable via a closure.
No other code will have scope to 'see' the local variable and thus it cannot be changed.
But then the problem becomes that when you use def inside a class_eval, the scope of the caller isn't captured, so the code can't see your local variable. You can use define_method instead
Here's an example
# /home/eric/GladeGUI.rb
module GladeGUI
def self.included(obj)
caller_file_path = caller[0].split(":").first
obj.class_eval do
define_method :my_class_file_path do
return caller_file_path
end
end
end
end
# /home/eric/FindMe.rb
class FindMe
include GladeGUI
end
puts FindMe.new.my_class_file_path # prints the correct path
But - what if you want my_class_file_path to be a class method rather than an instance method - use define_singleton_method instead:
module GladeGUI
def self.included(obj)
caller_file_path = caller[0].split(":").first
obj.class_eval do
define_singleton_method :my_class_file_path do
return caller_file_path
end
end
end
end
...
puts FindMe.my_class_file_path
Interesting side note: This is how you can fake "private variables" in javascript :-)

Unable to access library files from controller in rails

I have created a new library file sampler.rb inside the lib folder. Consider this as the content of the file
module Sampler
def sample_tester
"test"
end
end
I have included it in the application_controller and added a require statement in the config\initializers. When I try to access the method sample_tester from my controllers, I get the following error
undefined local variable or method `sample_tester` for #<BlogsController:0xb8fbac8>
Am I missing something?
Since it doesn't look like you are creating an instance of this, my first guess is that you need to define it as a class method so that it can be called like this: Sampler.sample_tester.
In your file you could do it one of two ways:
# first way
module Sampler
def self.sample_tester
"test"
end
end
# second way
module Sampler
class << self
def sample_tester
"test"
end
end
The second way is nicer if you want to define a number of class methods.
if you want to have your module method defined as a class method you need to use extend instead of include:
module Mod
def bla
puts "bla"
end
end
class String
include Mod
end
String.bla rescue puts $! # => undefined method `bla' for String:Class
class String
extend Mod
end
puts String.bla # => bla

Resources