Reputation: 8504
My setup: Rails 3.0.9, Ruby 1.9.2
I have my reasons for doing this but what I need is a way to add a virtual attribute to an activerecord resultset dynamically. That means I am not using attr_accessor
in the model and instead wish to dynamically add virtual attributes to a resultset.
For example,
users = User.all
#a user has following attributes: name, email, password
What I like to do is say add (without using attr_accessor
) a virtual attribute status
to users
, is that possible?
Upvotes: 10
Views: 6333
Reputation: 2923
You could simply do:
users.each { |user| user.class_eval { attr_accessor :status } }
All users
will have user.status
and user.status = :new_status
available.
Upvotes: 1
Reputation: 72544
If your attributes are read-only, you can also add them by selecting them in your database query. Fields which appear in the SQL result result will automatically be add as attributes.
Examples:
User.find_by_sql('users.*, (...) AS status')
User.select('users.*, joined_table.status').join(...)
With these examples you'll have all User
attributes and an additional status
attribute.
Upvotes: 1
Reputation: 33752
you can do the following:
add an attribute "extras" which will be accessed as a Hash, and which will store any additional / dynamic attributes -- and then tell Rails to persist that Hash via JSON in ActiveRecord or Mongo or whatever you use
e.g.:
class AddExtrasToUsers < ActiveRecord::Migration
def self.up
add_column :users, :extras, :text # do not use a binary type here! (rails bug)
end
...
end
then in the model add a statement to "serialize" that new attribute -- e.g. that means it's persisted as JSON
class User < ActiveRecord::Base
...
serialize :extras
...
end
You can now do this:
u = User.find 3
u.extras[:status] = 'valid'
u.save
You can also add a bit of magic to the User model, to look at the extras Hash if it gets a method_missing() call
See also: Google "Rails 3 serialize"
Upvotes: 2
Reputation: 115541
You should do this:
users.each do |user|
user.instance_eval do
def status
instance_variable_get("@status")
end
def status=(val)
instance_variable_set("@status",val)
end
end
end
Upvotes: 16