I am new to ruby and rails and sometimes I still get confused between these two. I have tried to call an instance variable by adding a name of the instance variable after an object(john.name), and I hope that the result would be John. Unfortunately NoMethodError appears. So I searched for an answer and found out that you can use instance_variable_get method to do this. However, I believe that it is possible to do this in RAILS when you want to access the instance variable of an object in VIEWS.
class Person
def initialize(name)
#name = name
end
end
john = Person.new("John")
puts john.instance_variable_get(:#name)
=> John
puts john.name
=> NoMethodError
Use attr_reader to read the value of an instance variable
class Person
attr_reader :name
def initialize(name)
#name = name
end
end
john = Person.new("John")
john.name #=> "John"
attr_reader adds a getter method to the class, in this case
def name
#name
end
Hope that helps!
You need to define the method to access your instance variable.
class Person
def initialize(name)
#name = name
end
def name
#name
end
end
Or you can simply add attr_accessor which will set getter and setter methods
class Person
attr_accessor :name
def initialize(name)
#name = name
end
end
Related
I have a non activerecord rails model:
class Document
attr_accessor :a, :b
include ActiveModel::Model
def find(id)
initialize_parameters(id)
end
def save
...
end
def update
...
end
private
def initialize_parameters(id)
#a = 1
#b = 2
end
end
In order to find the Document, I can use:
Document.new.find(3)
So, to get it directly I changed the find method to
def self.find(id)
initialize_parameters(id)
end
And I get the following error when I run
Document.find(3)
undefined method `initialize_parameters' for Document:Class
How can I make this work?
You can't access an instance method from a class method that way, to do it you should instantiate the class you're working in (self) and access that method, like:
def self.find(id)
self.new.initialize_parameters(id)
end
But as you're defining initialize_parameters as a private method, then the way to access to it is by using send, to reach that method and pass the id argument:
def self.find(id)
self.new.send(:initialize_parameters, id)
end
private
def initialize_parameters(id)
#a = 1
#b = 2
end
Or just by updating initialize_parameters as a class method, and removing the private keyword, that wouldn't be needed anymore.
This:
class Document
attr_accessor :a, :b
def self.find(id)
initialize_parameters(id)
end
end
Is not trying to "access class method from instance method" as your title states. It is trying to access a (non-existent) class method from a class method.
Everything Sebastian said is spot on.
However, I guess I would ask: 'What are you really trying to do?' Why do you have initialize_parameters when ruby already gives you initialize that you can override to your heart's content? IMO, it should look something more like:
class Document
attr_accessor :a, :b, :id
class << self
def find(id)
new(id).find
end
end
def initialize(id)
#a = 1
#b = 2
#id = id
end
def find
# if you want you can:
call_a_private_method
end
private
def call_a_private_method
puts id
end
end
Following is my Module in which I am serializing an attribute in n_attribute method.
n_attrib_key is a method that is calling an Object class method n_attrib to create dynamic methods,
The Object class is given below too.
What I actually want to do is pass the field from User to Module HashDemo, to serialize that field, once the field is serialized, now pass the keys in n_attrib_keys and create the dynamic methods of these keys in the Object class.
Once the methods are created, now called these methods by the attribute of object,
Now the main problem that i am facing is
As i called the method and let bnow i am in that method. Now I want to store dynamic method's name ( as a "key" of hash) and "value" to the attribute of model just like that
called
#user.address.home = "value"
what I want in the define_method
#user.address = {home: "value"}
is there any way to get the caller object and attribute in the define_method, i.e who called this method, in this case ?
Module
module HashDemo
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def n_attributes(*args)
args.each do |arg|
serialize %(:#{arg})
end
end
def n_attrib_keys(*names)
Object.n_attrib(*names)
end
end
end
Object class for monkey patching
class Object
def n_attrib(*names)
names.each do |name|
define_method("#{name}=") do |value|
puts "setter"
# #user.address = {"#{name}": value}
# i.e. #model.field = {key: value}
end
define_method("#{name}") do
puts "getter"
end
end
end
end
My active recode class is this
class User < ActiveRecord::Base
attr_accessible :address, :name
include HashDemo
n_attributes :address
n_attrib_keys :home, :location
u = User.new
u.address.home = value # this will go to the setter define_method in the Object class
u.address.home # this will go to the getter define_method in Object class
end
How to access attr_accessor's instance variable from a subclass?
class A
attr_accessor :somevar
#somevar = 123
puts #somevar
end
class B < A
def meth
puts #somevar
end
end
B.new.meth
puts nil...
P.S. I can use ActiveSupport.
You need to set the instance variable in an initialize method -- this gets called whenever a new class instance is created:
class A
attr_accessor :somevar
def initialize
#somevar = 123
end
end
First, you do not have a instance of A to assign a value. Put an initialize method on A so while creating an instance of B, you can pass somevar value as a parameter to the new function:
class A
attr_accessor :somevar
def initialize(somevar)
#somevar = somevar
end
end
class B < A
def meth
puts #somevar
end
end
B.new('LOL').meth
I'm adding ":foo" attribute to my user model as:
attr_accessor :foo
attr_accessible :foo
But when I set this attribute from a session controller or any other controller as:
User.foo = "my attributre"
and I get this attribute as:
User.foo
so these are not recognize and gives me an error, which is:
undefined method `foo=' for #<Class:0xb75366fc>
So please help here. I AM USING RAILS 2.3.5
attr_accessor does not create a class method, it creates instance methods. So given your code, it should work to use:
#user = User.new
#user.foo = "bar"
Edit:
However, if you do want to create custom methods, then you could do something like this:
class User < ActiveRecord::Base
def self.add_accessor(attr)
define_method(attr) do
instance_variable_get("##{attr}")
end
define_method("#{attr}=") do |val|
instance_variable_set("##{attr}",val)
end
end
And then you call it from your Controller:
User.add_accessor "foo"
#user = User.new
#user.foo = "bar"
Try this if you want to have an attribute accesor at the class level
In the User model , Use this code
class << self
attr_accessor :foo
end
Further reference http://apidock.com/rails/Class/cattr_accessor
I am trying to do a custom active record macro. But it right now seems impossible set an instance variable from within it's block.. here is what i am trying to do.
module ActiveRecord
class Base
def self.included(base)
base.class.send(:define_method, :my_macro) do |args|
# instance_variable_set for the model instance that has called this
# macro using args
end
end
end
end
i have tried class_eval, instance_eval.. but nothing seems to work or i don't how to use them.
Thanks in advance.
Edit: Let me try to explain better. I have a class method. An instance of the class calls this method. Now, this class method should instruct the instance to set an instance variable for itself.
Edit- this is how i want o use the macro
class MyModel < ActiveRecord::Base
my_macro(*args)
def after_initialize
# use the value set in the macro as #instance variable
end
end
Is this what you are thinking of:
class DynamicAdd
def add_method
self.class_eval do
attr_accessor :some_method
end
end
end
You can then do the following:
k = DynamicAdd.new
k.some_method = "hi"
should result in an undefined method error.
But,
k = DynamicAdd.new
k.add_method
k.some_method = "hi"
should work.
You can use this same format to define other types of methods besides attr_accessors as well:
class DynamicAdd
def add_method
self.class_eval do
def some_method
return "hi"
end
end
end
end
Hm.. Isn't included() a Module method? I don't think you can use that in a class like you have written. If you want to create a class method you can do
class Base
def self.my_method
end
or
class Base
class << self
def my_method
end
end
If all you want to do is to add an instance variable to an existing object, then you can use #instance_variable_set
class Base
class << self
def my_method(instance_of_base, value)
instance_of_base.instance_variable_set "#x", value
end
end
end
a = Base.new
a.class.send(:my_method, *[a,4])