class inheritance in ruby / rails - ruby-on-rails

so this is what i want to do:
class A
ATTRS = []
def list_attrs
puts ATTRS.inspect
end
end
class B < A
ATTRS = [1,2]
end
a = A.new
b = B.new
a.list_attrs
b.list_attrs
i want to create a base class with a method that plays with the ATTRS attribute of the class. in each inherited class there will be a different ATTRS array
so when i call a.list_attrs it should print an empty array and if i call b.attrs should put [1,2].
how can this be done in ruby / ruby on rails?

It is typically done with methods:
class A
def attrs
[]
end
def list_attrs
puts attrs.inspect
end
end
class B < A
def attrs
[1,2]
end
end

modf's answer works... here's another way with variables. (ATTRS is a constant in your example)
class A
def initialize
#attributes = []
end
def list_attrs
puts #attributes.inspect
end
end
class B < A
def initialize
#attributes = [1,2]
end
end

I don't think it's a good idea to create the same array each time a method is called. It's more natural to use class instance variables.
class A
def list_attrs; p self.class.attrs end
end
class << A
attr_accessor :attrs
end
class A
#attrs = []
end
class B < A
#attrs = [1, 2]
end
A.new.list_attrs # => []
B.new.list_attrs # => [1, 2]
You can also use constants along the line suggested in the question:
class A
def list_attrs; p self.class.const_get :ATTRS end
ATTRS = []
end
class B < A
ATTRS = [1, 2]
end
A.new.list_attrs # => []
B.new.list_attrs # => [1, 2]

Related

Passing variables between classes in Ruby on Rails

So I have two files, one called a.rb and one called b.rb. Here's the contents in both:
# a.rb
class A
def initialize
#variable = ""
#module_b = B.new(self)
end
def pass_to_b(self)
#module_b.do_something(#variable)
end
def set_variable(var)
# var = empty
#variable = var
end
end
and
# b.rb
class B
def initialize(module_a)
#module_a = module_a
end
def set_variable_in_a(data)
#module_a.set_variable(data)
end
def do_something(variable)
# variable = empty
set_variable_in_a("hello world")
end
end
This is just an example of what I'm dealing with. If I'm trying to start a function in Class A, which is supposed to do something in ClassB and then change an instance variable in Class A, I'm not sure how to do this properly. This is what I've tried, however:
a = A.new
a.pass_to_b
Class B cannot see the instance variable #variable, and if it tries to set_variable_in_a, that doesn't work either. It's like the do_something function in Class A successfully calls the do_something function in Class B, but the instance variable information is not available. I thought by passing self to Class B, we'd be able to at least call the function
My MRI throws exeption about
def pass_to_b(self)
because you can't pass self to method as argument.
You need delete 'self' how argument
Run code below and you will see that #variable of instance of Class A has '123hello world' string
class A
def initialize
#variable = "123"
#module_b = B.new(self)
end
def pass_to_b
#module_b.do_something(#variable)
end
def set_variable(var)
# var = empty
#variable = var
end
end
# b.rb
class B
def initialize(module_a)
#module_a = module_a
end
def set_variable_in_a(data)
#module_a.set_variable(data)
end
def do_something(variable)
set_variable_in_a(variable + "hello world")
end
end
a = A.new
a.pass_to_b
display variable 'a' and you will see something like this
#<A:0x00007fdaba0f3c90 #variable="123hello world", #module_b=#<B:0x00007fdaba0f3c40 #module_a=#<A:0x00007fdaba0f3c90 ...>>>

Rails to_json(methods: => [...]) for different ActiveRecords

In Rails, i have an object called values that could be 1 of 20 kinds of ActiveRecord, and in only 1 of them there's a method(may be the wrong term, rails newbie) that can add a customized field in returned JSON object where the method name is the field name and method returned value is the field value. For example
class XXXController < ApplicationController
..
if a
values = A
elsif b
values = B
elseif c
values = C
..
end
render :json => values.to_json(:methods => :type_needed)
and you will see response like
{
..
"type_needed": true,
..
}
I only have type_needed defined in A which will return true in some cases. For others like B, C, D... which in total 19, i want them to all have type_needed returned as false, is there a way i can do that in one place instead of add type_needed method in the rest 19?
I will do it as follows:
json = values.to_json(:methods => :type_needed)
# => "[{\"id\":1,\"name\":\"Aaa\"},{\"id\":\"2\",\"name\":\"Bbb\"}]" # => Representational value only
ary = JSON.parse(json)
# => [{"id"=>1, "name"=>"Aaa"}, {"id"=>2, "name"=>"Bbb"}]
ary.map! { |hash| hash[:type_needed] = false unless hash.key?(:type_needed); hash }
# => [{"id"=>1, "name"=>"Aaa", :type_needed=>false}, {"id"=>2, "name"=>"Bbb", :type_needed=>false}]
ary.to_json
# => "[{\"id\":1,\"name\":\"Aaa\",\"type_needed\":false},{\"id\":\"2\",\"name\":\"Bbb\",\"type_needed\":false}]"
If I am understanding your question correctly then you want to define type_needed method once and have it included on all your 20 models. If yes, then you can define a concern and include it in all your 20 models.
app/models/concerns/my_model_concern.rb
module MyModelConcern
extend ActiveSupport::Concern
def type_needed?
self.respond_to?(:some_method)
end
end
app/models/a.rb
class A < ApplicationRecord
include MyModelConcern
def some_method
end
end
app/models/b.rb
class B < ApplicationRecord
include MyModelConcern
end
app/models/c.rb
class C < ApplicationRecord
include MyModelConcern
end
With the above
a = A.new
a.type_needed?
=> true
b = B.new
b.type_needed?
=> false
c = C.new
c.type_needed?
=> false
See if this helps.

Access varible in ruby after initialize

I am trying to access variable in ruby after initialize, but i didn't get that variable , anything wrong in that?
class Test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
def self.method1(params)
Test.new(params)
#can i get that two instance variable
end
end
You should probably set up attribute accessors, then use them this way:
class Test
attr_accessor :has_test
attr_accessor :limit_test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
def self.method1(params)
t = Test.new(params)
// can i get that two instance variable
// Yes:
// use t.has_test and t.limit_test
end
end
You are mixing an instance and a class method in your example.
If this is really what you want, then you have to define an accessor with attr_reader:
class Test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
attr_reader :has_test
attr_reader :limit_test
def self.method1(params)
obj = Test.new(params)
p obj.has_test
p obj.limit_test
end
end
Test.method1(has_test: 1, limit_test: 3)
It the instance/class-method is a mistake, then this example may help you:
class Test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
def method1()
p #has_test
p #limit_test
end
end
obj = Test.new(has_test: 1, limit_test: 3)
obj.method1
If you define also the accessors like in the first code, then you have again access from outside the class.
Just in case you don't want a reader, see also Access instance variable from outside the class

ruby on rails accessing custom class attributes from its object

I have a custom class in my application controller. Like below:
class Defaults
def initialize
#value_1 = "1234"
#value_2 = nil
#data = Data.new
end
end
class Data
def initialize
#data_1 = nil
end
end
Now in my controller method i have created an object of type Defaults
def updateDefaultValues
defaults = Defaults.new
# i am unable to update the value, it says undefined method
defaults.value_2 = Table.maximum("price")
defaults.data.data_1 = defaults.value_2 * 0.3
end
How to access value_2 from defaults object?
defaults.value_2
Also, how to access data_1 attribute from data object within defaults object?
defaults.data.data_1
You should use attr_accessor:
class Defaults
attr_accessor :value_1, :value_2, :data
# ...
end
defaults = Defaults.new
defaults.value_1 = 1
# => 1
defaults.value_1
# => 1
As you are using def as a keyword to define the method, that means def is a reserved keyword. You can't use reserved keywords as a variable.
You just need to rename your variable name from def to something_else and it should work! Your code will look like this:
def updateDefaultValues
obj = Defaults.new
obj.value_2 = Table.maximum("price")
obj.data.data_1
end
EDIT:
As per OP's comment & updated question, he had used def just as an example, here is the updated answer:
You may need attr_accessor to make attrs accessible:
class Defaults
attr_accessor :value_1, :value_2, :data
...
...
end
class Data
attr_accessor :data_1
...
...
end
Add value_2 method in Defaults class
class Defaults
def initialize
#value_1 = "1234"
#value_2 = nil
#data = Data.new
end
def value_2
#value_2
end
end
class Data
def initialize
#data_1 = nil
end
end

Need to find source_location of class method

I have a model with a class method.
Like:
class School < ActiveRecord::Base
def self.mymethod
end
def instance_something
end
end
How can I find the source_location of a class method in Ruby?
If I want the source location of "instance_something" I do
School.new.method(:instance_something).source_location
But I can't do that with class method.
Any help?
I just did this in irb, and it works.
class Foo
def foo
end
def self.bar
end
end
f = Foo.new
m1 = f.method(:foo)
m1.source_location
=> ["(irb)", 2]
Foo.method(:bar)
m2 = Foo.method(:bar)
m2.source_location
=> ["(irb)", 4]

Resources