Initializing Instance Variable as an Array - Ruby
You are overriding ActiveRecord's initialize
method. Try using super
:
def initialize(*args, &block)
super
@name1 = []
end
How to Initialize Class Arrays in Ruby
You need to use initialize as a constructor as below code and is there any reason why not to use initialize/constructor. And please fix a typo error in class definition Class Something
to class Something
no camel case or first letter capitalize while in class
class Something
def initialize
@something = Array.new
end
def dosomething
s = 5
@something << s
end
end
class variable @@
are available to the whole class scope. so they are working in the code and if you want to use instance variable @ you need to initialize it as above. The instance variable is share with instance/objects of a class
for more details visit the link Ruby initialize method
Instance variable initialization in Ruby
What you are doing is defining an instance variable on the class level (Since classes are instances of the Class class, this works just fine).
And no, there is no way around initialize.
Edit: You have a little misconception in your edit. attr_accessor
doesn't add an instance variable to the class. What it does, literally, is this (using your example of my
):
def my; @my; end
def my=(value); @my = value; end
It doesn't actively create/initialize any instance variable, it just defines two methods. And you could very well write your own class method that does similar things, by using define_method
.
Edit 2:
To further illustrate how one would write such a method:
class Module
def array_attr_accessor(name)
define_method(name) do
if instance_variable_defined?("@#{name}")
instance_variable_get("@#{name}")
else
instance_variable_set("@#{name}", [])
end
end
define_method("#{name}=") do |val|
instance_variable_set("@#{name}", val)
end
end
end
class Test
array_attr_accessor :my
end
t = Test.new
t.my # => []
t.my = [1,2,3]
t.my # => [1, 2, 3]
How to initialise an instance variable dynamically in ruby?
Mocking @sites data:
@sites = [OpenStruct.new(
site_1_location: 'Japan',
site_2_location: 'India',
site_3_location: 'Chile',
site_4_location: 'Singapore'
)]
You can use instance_variable_set
to set the instance variable
@sites.each do |site|
1.upto(4) do |i|
instance_variable_set("@var#{i}", site.send("site_#{i}_location"))
end
end
Now you can access the variables:
@var1 # returns "Japan"
@var2 # returns "India"
@var3 # returns "Chile"
@var4 # returns "Singapore"
How can I initialize instance variable?
If you want to persist anything between requests you need to store it somewhere:
- Database
- Memory based storage (Redis, Memcached)
- File system
You can also pass state back and forth between the client and server without actually storing it with:
- HTTP cookies
- Query string parameters
Using a class variable is not really going to solve anything. It will only hold the variable as long as the class is held in memory. Every time the class is reloaded it will be reset.
Multi-threading is another huge issue here as Rails servers are commonly multi-threaded and class variables are not thread safe.
Declaring an instance variable outside of `initialize` method
I have been taught to declare my instance variables with def initialize
Since initialize
is the first instance method call in an object's life cycle, you typically declare your instance variables right there in order to ensure properly initialized variables. It's also the first place I'd expect instance variables to be defined when reading code.
I have been under the impression that I could declare instance variables only within my initialize methods.
There's no such restriction. You can declare instance variable anywhere within your instance.
A common use is memoization:
class FooBar
def foo
@foo ||= expensive_operation
end
end
On the first call, this would evaluate expensive_operation
and assign the result to @foo
. On subsequent calls, @foo
is returned.
Another popular example is Rails which uses instance variables to pass data from the controller to its view:
class FooController < ApplicationController
def index
@foos = Foo.all
end
end
is there a best practices rule I should follow, regarding where to declare instance variables
It depends on their purpose (see above examples). As a general rule, declare them in a way that avoids undefined variables (nil
errors) and structure your code so it is easy to read / follow.
Ruby - automatically initialize class instance variables of child classes without inheriting the value
You don't have to initialize the class variable when it is being inherited. The Ruby style is to return and assign default value when the variable has not been set and is being accessed for the first time.
Just create another class method for that:
class AbstractClass
def self.metadata
@metadata ||= []
end
def self.add_metadata(metadata)
self.metadata << metadata
end
end
class ChildClass1 < AbstractClass
add_metadata(:child_class1)
end
class ChildClass2 < AbstractClass
add_metadata(:child_class2)
end
AbstractClass.metadata # => []
ChildClass1.metadata # => [:child_class1]
ChildClass2.metadata # => [:child_class2]
Initializing class instance variables in Ruby
Short answer: instance variables don't get inherited by subclasses
Longer answer: the problem is that you wrote @bar = []
in the body of the class (outside any method). When you set an instance variable, it is stored on whatever is currently self
. When you're in a class body, self
is the class object Foo. So, in your example, @foo
gets defined on the class object Foo.
Later, when you try to look up an instance variable, Ruby looks in whatever is currently self
. When you call add_bar from Baz, self
is Baz. Also self
is STILL Baz in the body of add_bar (even though that method is in Foo). So, Ruby looks for @bar
in Baz and can't find it (because you defined it in Foo).
Here's an example that might make this clearer
class Foo
@bar = "I'm defined on the class object Foo. self is #{self}"
def self.get_bar
puts "In the class method. self is #{self}"
@bar
end
def get_bar
puts "In the instance method. self is #{self} (can't see @bar!)"
@bar
end
end
>> Foo.get_bar
In the class method. self is Foo
=> "I'm defined on the class object Foo. self is Foo"
>> Foo.new.get_bar
In the instance method. self is #<Foo:0x1056eaea0> (can't see @bar!)
=> nil
This is admittedly a bit confusing, and a common stumbling point for people new to Ruby, so don't feel bad. This concept finally clicked for me when I read the 'Metaprogramming' chapter in Programming Ruby (aka "The Pickaxe").
How I'd solve your problem: Look at Rails' class_attribute
method. It allows for the sort of thing you're trying to do (defining an attribute on a parent class that can get inherited (and overidden) in its subclasses).
Related Topics
Approach for Installing System Service Implemented as Ruby Gem
How to Get Ruby-Debug-Ide to Work
Error When Installing Ruby 2.1.3 with Rvm
How to Associate a CSS/Sass Stylesheet to a View in Rails
Ruby Method, Proc, and Block Confusion
Error Installing JSON 1.8.3 with Ruby 2.4
Setting Up .Emacs File for MAC Ruby Development
In Ruby, How to Remove Only 1 Match in an Array Easily
How to Download a File Over Http Using Ruby
How to Properly Test Cancan Abilities with Rspec
Ruby Inserting Key, Value Elements in Hash
Using Ruby CSV to Extract One Column
Get All Local Variables or Available Methods from Irb