I have a feeling I'm missing something very simple here. I have a class that is linked to an external service. I want to instantiate it by either calling a create method or a find method. Both methods will populate an instance variable "#node" with a hash, either by creating a node or finding it.
I have
class GenreInfluence
##neo ||= Neography::Rest.new()
attr_accessor :node
def initialize
end
def self.create
#node = ##neo.create_node
self.new
end
def self.find(node_id)
#node = ##neo.get_node(node_id)
self.new
end
def get_hash
#node
end
If I comment out what's going on, I can see it's creating the class and getting the correct hash back however:
theInstance = GenreInfluence.find(20)
theInstance.get_hash
Just returns nil. Why is the hash not being stored in the instance variable!?
You can't set instance variables in a non-instance (static, or class) method. Furthermore, both your methods are returning self.new, which effectively returns a new instance of the class with no instance variables set.
How about the following, that creates a new instance of the class in the static class methods, sets the variable on that instance, and then returns it (instead of returning self.new):
class GenreInfluence
##neo ||= Neography::Rest.new()
attr_accessor :node
def initialize
end
def self.create
influence = self.new
influence.node = ##neo.create_node
influence
end
def self.find(node_id)
influence = self.new
influence.node = ##neo.get_node(node_id)
influence
end
def get_hash
#node
end
end
You are returning self.new from your find method. That's a new instance of GenreInfluence with a fresh set of instance variables.
How about
class GenreInfluence
##neo ||= Neography::Rest.new()
attr_accessor :node
def initialize(node_id = nil)
if (node_id.nil?) then
#node = ##neo.create_node
else
#node = ##neo.get_node(node_id)
end
end
def find(node_id)
#node = ##neo.get_node(node_id)
end
def get_hash
#node
end
end
and then
theInstance = GenreInfluence.new()
theInstance.get_hash
theInstance1 = GenreInfluence.new(20)
theInstance1.get_hash
theInstance2 = GenreInfluence.new()
theInstance2.get_hash
theInstance2.find(20)
theInstance2.get_hash
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
How can I read a class variable? In my case I can't get value from variable.
class MediaContentsController < ApplicationController
#randomUsrId = rand(100)
def create
puts #randomUsrId
end
end
First of all, #randomUsrId refers to an instance variable, not a class variable. You can access it through an instance of the class, not direct on the class. For a class variable, you should use ##randomUsrId.
What you are actually looking for is attr_accessor :randomUsrId, through this, you can read it on an instance method, and even can set it through an instance of the class.
Here's how:
class MediaContentsController < ApplicationController
attr_accessor :randomUsrId
#randomUsrId = rand(100)
def create
puts #randomUsrId
end
end
But #randomUsrId = rand(100) won't set #randomUsrId to a random number, at least it is not the recommend way. You should use before_action here.
class MediaContentsController < ApplicationController
attr_accessor :randomUsrId
before_action :set_user_id_to_a_random_number, only: :create
def create
puts #randomUsrId
end
private
def set_user_id_to_a_random_number
#randomUsrId = rand(100)
end
end
Edit:
Each time you call the set_user_id_to_a_random_number function, it will generate a different number based on rand(100) and store it inside #randomUsrId. If that's what you do not want, and you want to persist the same value, you can do something like following:
def set_user_id_to_a_random_number
#randomUsrId = rand(100) unless defined? #randomUsrId
end
Edit:
What I have stated works only for one request, if you have multiple request, it won't work. As Ryan Bates says here:
An instance variable only sticks around for a single request, so using the technique described will only benefit you if you need to call a method multiple times per request.
That leaves you with two options if you want to store something between multiple requests. Either you can go with Databases, or you can use something called memcached.
You probably doing something wrong in your code, since this isn't how Rails controller logic should be usually implemented, but let's get down to your question anyway. As I mentioned it isn't class variable, it's instance variable in class scope, so in order to access it, you should first get it from that scope:
class MediaContentsController
#randomUsrId = rand(100)
def create
puts self.class.get_random_usr_id
end
def self.get_random_usr_id
#randomUsrId
end
end
MediaContentsController.new.create
# => 44
Is this the right way of calling an Instance method from a class method? Here the instance_var is passed with the Name object. I want to invoke func1 from the instance_var object passed to the class method.
I wrote this :
Class Name
def initialize
#name
end
def func1(value)
puts value
end
def self.func2(instance_var,val)
instance_var.func1(val)
end
end
How do you call func2?
Your code has a small error. You wrote Class instead class. With Class you get a syntax error.
This code works:
class Name
def func1(value)
puts value
end
def self.func2(instance_var,val)
instance_var.func1(val)
end
end
x = Name.new
Name.func2(x, 12) #12
#or
Name.func2(Name.new, 12) #12
Your
def initialize
#name
end
will create an empty variable #name. It will never get a value. To assign a value you need:
class Name
def initialize (var)
#name = var
end
end
x = Name.new(:x)
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 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])