简体   繁体   中英

Looping over attributes of object of a Non-Active-Record-Model

The simple way to loop over all attributes of an object when using Active Record is

order_item_object.attributes.each do |key,value|
....
end

But this doesn't work, when we are not using Active Record. How can I iterate over all the attributes of an object then?

For eg -: I have a model in Rails which does not use active record. The object from model order_item can be used in the controller like order_item_object.product_id, order_item_object.quantity, order_item_object.quoted_price. But when I try to order_item_object.attributes.each do |k,v| ...., I get undefined method "attributes" for #<Order:0x00000005aa81b0>

How should I go about this?

try this:

class Parent
  def self.attr_accessor(*vars)
    @attributes ||= []
    @attributes.concat vars
    super(*vars)
  end

  def self.attributes
    @attributes
  end

  def attributes
    self.class.attributes
  end
end

class ChildClass < Parent
  attr_accessor :id, :title, :body
end

p ChildClass.new.attributes.inspect #=> [:id, :title, :body]

attr_accessor is simply a macro that creates some methods to set an instance variable. SO perhaps what you want is the instance_variables method, which returns an array of instance variables that you can iterate through

class Foo
  attr_accessor :bar
  attr_accessor :baz
end

foo = Foo.new
foo.bar = 123
foo.baz
foo.instance_variables.each do |ivar_name|
  ivar_value = foo.instance_variable_get ivar_name
  # do something with ivar_name and ivar_value
end

But I wouldn't really recommend this. ActiveRecord keeps model data separate for a reason. Your instance may have lots of uses for instance variables. For instance, perhaps you want to track if the record is saved yet or not. This may be kept in @saved variable, which reflects the state of the instance but not the data of the model.

Perhaps you want to keep a hash of attributes instead?

This is the best way I found

item=self.instance_values.symbolize_keys
item.each do |k,v|
  ...
  ..
end

There is a code to show it's usage here (look at the update in the question itself) - Grouping via an element in hash

If you want the string representations of your instance variables, you can do:

self.instance_values.keys.each do |k|
 ..
end

That should loop over all the keys (instance variable names as strings) that are defined for your class.

The attributes you are referencing is an instance variable on ActiveRecord models which returns a hash of the models db attributes.

A non-ActiveRecord model won't have the attributes method you are calling unless you defined it explicitly. All objects have a method called instance_variables which you can use to get a list of attribute names and then reflectively find the attribute values.

A not very elegant way of doing it:

class Test
  attr_accessor :firstname,:lastname
  def initialize(fn,ln); @firstname = fn; @lastname = ln; end
end

o = Test.new("Fernando", "Mendez")
o.instance_variables.each {|e| p o.send e.to_s.sub("@","").to_sym}
output:
"Fernando"
"Mendez"

If you want to keep a track of the key-value pair:

r = o.instance_variables.map {|e| Hash[e,(o.send e.to_s.sub("@","").to_sym)]}

#[{:@firstname=>"Fernando"}, {:@lastname=>"Mendez"}]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM