I have a class variable named ##customers which I would like to continually update via a method.
I initialize the variable (as an empty array) at the top of my model. And then update it when the method update_customers is called:
class Customer
##customers = []
def update_customers(new_customer)
##customers << new_customer
end
end
I am concerned about ##customers being re-initialized to [] and losing the data. Could such re-initialization occur? When would it happen?
Nope; ##customers will not be re-initialized to [] when update_customers is called from a new Customer object. That is how class variables work.
See http://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/45-more-classes/lessons/113-class-variables for an in-depth treatment of class variables.
As mentioned there:
There aren't very many cases that you would need to use class variables.`
class Customer
##customers = []
def self.update_customers(new_customer)
##customers << new_customer
end
end
Class variables are static. They are initialized just once.
It would be good if you declared update_customers as class method
You could call the method like
cust1 = Customer.new
Customer.update_customers cust1
Related
I want to define methods dynamically using an array of strings.
Here is a simple piece of code that should achieve that.
class SomeClass
attr_accessor :my_array
def initialize(user, record)
#my_array=[]
end
my_array.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
When I instantiate this class in the console, I get the following error
NoMethodError (undefined method `each' for nil:NilClass)
What is wrong with this code and how to make it work. any help highly appreciated :)
Edit 1:
What I ultimately want to achieve is to inherit from SomeClass and override my_array in the child class to dynamically define methods with its attributes like so
class OtherClass < SomeClass
my_array = %w[method1 method2 method3]
# Some mechanism to over write my_array.
end
And then use self.inherited to dynamically define methods in child class.
Is there a good way to achieve this?
In your code, you use an instance variable (#my_array) and an attr_accessor over it, and then try to access my_array from class level (that is, from the body of the class definition, outside of any methods). But instance variables only exist at instance level, so it is not available in the class scope.
One solution (the natural one, and the one which you would probably use in other languages) is to use a class variable: ##my_array. But class variables in ruby are a little problematic, so the best solution would be to make use of class instance variables, like that:
class SomeClass
class << self
attr_accessor :my_array
end
#my_array=[]
def initialize(user, record)
end
#my_array.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
The syntax is a little tricky, so, if you look that up and it still doesn't makes sense, try just reading about scopes and using a regular class variable with ##.
Edit:
Ok, so, after your edit, it became more clear what you are trying to accomplish. A full working example is like follows:
class SomeClass
class << self
attr_accessor :my_array
end
#my_array=[]
def awesome_method
puts 'awesome'
end
def self.build!
#my_array.each do |element|
self.define_method("#{element}?".to_sym){ awesome_method }
end
end
end
class ChildClass < SomeClass
#my_array = %w[test little_test]
self.build!
end
child_instance = ChildClass.new
child_instance.test?
>> awesome
child_instance.little_test?
>> awesome
So, I've made some tweaks on SomeClass:
It does not need an initialize method
I tried to use the inherited hook for this problem. It won't ever work, because this hook is called as soon as "ChildClass < SomeClass" is written, and this must be before you can define something like #my_array = %w[test little_test]. So, I have added a self.build! method that must be called in the child instances so that they build their methods from my_array. This is inevitable, but I think it is also good, because it makes more explicit in the subclasses that you are doing something interesting there.
I think you want "define_method", not "alias_method".
awesome_method in passed in a block, which is ruby's way of doing functional programming.
With that done, ChildClass inherits from SomeClass, and it's instances have the dynamically created methods 'test?' and 'little_test?'.
You need to change my_array to class level accessible, in my case class constant.
class SomeClass
DYNAMIC_METHOD_NAMES = %w(method_a method_b method_C).freeze
def initialize(user, record)
end
DYNAMIC_METHOD_NAMES.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
Note: This was the best title I could think of that wouldn't make this question seem like a dup. Please feel free to edit if it does not capture the point of the question
So I've been reading Advanced Rails and I had a question that wasn't fully answered by these posts:
When to use `self.foo` instead of `foo` in Ruby methods
In Ruby. How do I refer to the class from within class << self definition?
Why use "self" to access ActiveRecord/Rails model properties?
In my understanding, within a class definition, self refers to the object referenced by the pointer klass, so for the example of an eigenclass:
class A
class << self
def to.s
"Woot"
end
end
end
is the exact same as:
class << A
def to.s
"Woot"
end
end
This is because as you open up the class, ruby is creating a Class:A (virtual) class and assigning A's klass pointer to it. To my understanding this means that within the context of this class definition self == A
My question is (assuming my understanding as I've described it above is accurate) why then in an ActiveRecord::Base subclass in Rails does the use of self seem to be merely a disambiguation of the instance and not the class itself?
For example, if I have a class: A < ActiveRecord::Base with an attribute name, I cannot call A.name = "blah" outside the class definition. However, I CAN use ( and indeed MUST use ) self in assignment within the class definition like so: self.name = "blah".
If the use of self in Ruby refers to the Class object and not the instance, why does this work in ActiveRecord and how does Rails make the distinction?
Everything is a method
Anything you do with an object is a method. When you have a class like this:
class A
attr_accessor :foo
end
obj = A.new
obj.foo = 3
obj.foo #=> 3
It might feel weird, but you didn't make any assignment here. obj.foo = 3 is only a synthatic sugar for obj.send(:foo=, 3) so in fact, it executes foo= method. obj.foo is a method as well, it simply returns a value. This is because all the instance variables are private, and there is no other way to interact with them than inside the method. attr_accessor :foo is just a shortcut for:
def foo=(value)
#foo = value
end
def foo
#foo
end
Now, when ruby see any identifier like foo, it needs to find out what it is. Firstly it assumes it is a local variable, and if not, it tries to execute it as method on current self (see below). This means that:
class A
attr_accessor :foo
def bar
foo = 'bar'
end
end
a = A.new
a.bar #=> 'bar'
a.foo #=> nil
What happened? Interpretor first uses foo as an instance variable, it is not defined. But there is an assignment next to it, so it defines a new instance variable and make an assignment. If we want to use our setter we need to tell interpreter that it is not an instance varible:
class A
attr_accessor :foo
def bar
self.foo = 'bar'
end
end
a = A.new
a.bar #=> 'bar'
a.foo #=> 'bar'
I lied. Everything is an object
about self
self in ruby is very similar to this in javascript - it means different things in different context, and it can be easily changed at any point (obviously, not recommended).
First thing you need to know is that in Ruby every class is an object, namely it is an instance of class Class. When you do
class A
it is (almost, method below uses block and has access to external scope) equivalent to:
A = Class.new
self within a context of a class is always a class itself.
class A
self #=> A
def self.bar #=> this is class method
self #=> A
end
def foo #=> this is instance method
# We are no longer in context of class, but in context of the instance, hence
self #=> instance of A
end
end
Now, for any mutable object you can defined a singleton class. This is sort of weird concept - it is an extra subclass of the original class which only has a single instance. Since all the methods come from the class, this allows you to define extra methods on a particular instance of the method without affecting other object. In most of the cases, instance class is not needed and it is created when you access it for the first time. There are couple of ways to open it:
object.singleton_class do
self #=> instance class
end
class << object
self #=> instance class
end
Any method you defined within instance class is accessible only on that particular instance, hence this:
class A
self #=> A
class << A
# we are now in the instance class of A (which is an instance of Class class)
def foo
# So this is an instance method, however our instance is a class A
self #=> A
end
end
I have a class like so:
Railsapp/lib/five9_providers/record_provider.rb:
class Five9Providers::RecordProvider < Five9Providers::BaseProvider
def add_record_to_list
variable = 'test'
end
end
Then, in a controller I have this:
Railsapp/app/controllers/five9_controller.rb:
class Five9Controller < ApplicationController
def import
record_provider = Five9Providers::RecordProvider.new()
record_provider.add_record_to_list
puts Five9Providers::RecordProvider::variable
end
end
However, calling my controller method import just returns:
NoMethodError (undefined method 'variable' for Five9Providers::RecordProvider:Class)
How can I access variable from the recover_provider.rb class in my five9_controller.rb class?
EDIT:
Even when using ##variable in both my record_provider and my five9_controller, I still can't access that variable. I am calling it like so: puts ##variable.
As written, you cannot. variable is local to the instance method and can't be accessed by any Ruby expression from outside the method.
On a related point, the term "class variable" is typically used to refer to variables of the form ##variable.
Update: In response to your "Edit" statement, if you change variable to ##variable in your class, then there are techniques available to access that variable from outside the class, but a naked reference to ##variable isn't one of them. Carefully read the answers to the question you cited in your comment for more information.
Best way is to set and get the value using methods. Below is a sample code
class Planet
##planets_count = 0
def initialize(name)
#name = name
##planets_count += 1
end
def self.planets_count
##planets_count
end
def self.add_planet
##planets_count += 1
end
def add_planet_from_obj
##planets_count += 1
end
end
Planet.new("uranus")
Plant.add_planet
obj = Planet.new("earth")
obj.add_planet_from_obj
hi i am new ruby on rails i need to know some basic information about
how to call a function from controller to model
for ex:-
controller name : checkings
def create
#data = Checking.check()
end
model name is Checking
def check
#a="xxxxx"
end
how can i call from controller function to model function
check is instance method,you have to make class method to call by class name,def self.check end
Seems you are referring to static function call. In ruby the static functions are defined with self.
def self.check
a="xxxxx"
end
However, in rails, you should not populate instance variable in Model. In that case you can return the value from check function and assign it in controller function like
def self.check
return "xxxxx"
end
#In controller
#data = Checking.check() # "xxxxx" will be stored in #data
However, defining any function without self means its a instance function. So you need to call that function through any object of that class.
We can call the model methods from controller using two formates,
1 . Creating singleton methods.
Singleton methods are created using self keyword. example
class Check < ActiveRecord::Base
def self.check
end
end
we can call this singleton method using following format,
#checks = Check.check
2 . Creating instance methods.
Instance methods are created using without self keyword
class Check < ActiveRecord::Base
def check
end
end
we can call this singleton method using following format,
#check =Check.new
#checks = #check.check
I want to initialize an instance variable within my Rails model that will hold an array and I want to access this variable in other methods within my model. I tried this:
class Participant < ActiveRecord::Base
#possible_statuses = [
'exists',
'paired',
'quiz_finished',
'quiz_results_seen',
'money_sent'
]
def statuses
#possible_statuses
end
But when I tried the following using rails console:
Participant.first.statuses
I am returned nil :(
Why does this happen?
Is there a way to accomplish what I am trying to accomplish?
I would recommend using a constant for this kind of cases:
class Participant < ActiveRecord::Base
STATUSES = [
'exists',
'paired',
'quiz_finished',
'quiz_results_seen',
'money_sent'
]
If you want to access that array from the inside class, just do STATUSES, and from the outside class use Participant::STATUSES
In your example, #possible_statuses is a variable on the class rather than on each instance of the object. Here is a rather verbose example of how you might accomplish this:
class Participant < ActiveRecord::Base
#possible_statuses = [
'exists',
'paired',
'quiz_finished',
'quiz_results_seen',
'money_sent'
]
def self.possible_statuses
#possible_statuses
end
def possible_statuses
self.class.possible_statuses
end
def statuses
possible_statuses
end
end
As mentioned in other answers, if that list of statuses never changes, you should use a constant rather than a variable.
The best answer for me was to create a class variable, not an instance variable:
##possible_statuses = [
'exists',
'paired',
'chat1_ready',
'chat1_complete'
]
I could then freely access it in methods of the class:
def status=(new_status)
self.status_data = ##possible_statuses.index(new_status)
end
The instance variable will only exist when you create the model, since it is not being stored in a database anywhere. You will want to make it a constant as per Nobita's suggestion. Alternatively, you could make it a module like...
module Status
EXISTS = "exists"
PAIRED = "paired"
QUIZ_FINISHED = "quiz_finished"
QUIZ_RESULTS_SEEN = "quiz_results_seen"
MONEY_SENT = "money_sent"
def self.all
[EXISTS, PAIRED, QUIZ_FINISHED, QUIZ_RESULTS_SEEN, MONEY_SENT]
end
end
This gives you a bit more control and flexibility, IMO. You would include this code nested in your model.