Referencing a non-ActiveRecord attribute

I am trying to access a model’s attribute that does not have a column
in the model’s corresponding table. It exists only through an
attr_accessor:

class Widget < ActiveRecord::Base
attr_accessor :attribute_not_in_db
end

I can access the attribute directly:

w = Widget.new(:attribute_not_in_db => “foo”)
w.attribute_not_in_db
=> “foo”

However, I can’t seem to access it other ways:

attr_symbol = :attribute_not_in_db
w[attr_symbol]
=> nil

attr_name = “attribute_not_in_db”
w[attr_name]
=> nil

w.read_attribute(attr_symbol)
=> nil

w.read_attribute(attr_name)
=> nil

This is probably rather basic, but my searching hasn’t turned up the
answer. Any guidance would be apprecited.

thx.

One way to dynamically add attributes to some model object on the fly
is to just directly add the new key(s)/val(s) to the model instance’s
attributes:

$ ./script/console
Loading development environment (Rails 2.2.2)

test = Test.find(:first)
=> #<Test id: 1, name: “Abe”>

test.attributes.keys
=> [“id”, “name”]

test[“favorite_color”] = ‘blue’
=> “blue”

test.attributes.keys
=> [“id”, “favorite_color”, “name”]

test.favorite_color
=> “blue”

Another way, assuming the purpose is to add additional attribs coming
from a db qry, … Note that any additional attribs returned from a
db query will be automatically added to the returned model ob(s):

test2 = Test.find_by_sql(“select *, ‘blue’ as favorite_color from tests order by id limit 1”).first
=> #<Test id: 1, name: “Abe”>

test2.attributes.keys
=> [“id”, “favorite_color”, “name”]

test2.favorite_color
=> “blue”

Note that neither of the above requires any accessor-related code in
your model ob (unless you want/need it for other purposes):

$ cat app/models/test.rb
class Test < ActiveRecord::Base
end

Jeff

Okay, I found a solution. It isn’t very readable, but it works:

user = User.new(:login=> “foo”, :password=>“bar”) # :password is not
a column in the db, but defined in the model using
“attr_accessor :password” (see initial post)
[:login, :password].each do |x|
getter = x # => :password
setter = (x.to_s << “=”).to_sym # => :password=
original_val = user.method(getter).call
user.method(setter).call(some_new_val)
do_some_test(user)
user.method(setter).call(original_val)
end

Any clean up suggestion?

The reason to add extra attributes as shown in my example is to allow
for the accessor goodies provided by ActiveRecord for the model ob:

$ cat app/models/hit.rb
class Test < ActiveRecord::Base
attr_accessor :foo
end

$ ./script/console
Loading development environment (Rails 2.2.2)

test = Test.new
=> #<Test id: nil, name: nil>

test.id = 987
=> 987

test[:id]
=> 987

test[“id”]
=> 987

test.foo = ‘bar’
=> “bar”

test[:foo]
=> nil #huh?

test[“foo”]
=> nil #huh?

test.attributes.keys
=> [“id”, “name”] #huh?

add key/val via model ob’s attributes:

test[‘foo’] = ‘bar’
=> “bar” #cool.

test.foo
=> “bar” #cool.

test[:foo]
=> “bar” #cool.

test.attributes.keys
=> [“id”, “foo”, “name”] #cool.

So, for your User example, if you changed the adding of password
attrib as:


user[“password”] = “bar”

then your orig code should work as you intended.

Hope that helps,

Jeff

On Feb 16, 12:14 am, rapdup [email protected] wrote:

do_some_test(user)
user.method(setter).call(original_val)

end

Any clean up suggestion?

This is marginally cleaner IMO:

[:login, :password].each do |getter|
setter = “#{getter}=”
original_val = user.send(getter)
user.send(setter, some_new_val)
do_some_test(user)
user.send(setter, original_val)
end

Thanks for the response.
I’m afraid my initial post wasn’t clear as it could be. I am trying to
find a specific syntax to access an accessor getter/setter using a
variable, in this example “x”:

user = User.new(:login=> “foo”, :password=>“bar”) # :password is not
a column in the db, but defined in the model using
“attr_accessor :password” (see initial post)

[:login, :password].each do |x|
original_val = user[x]
user[x] = some_new_val
do_some_test(user)
user[x] = original_val
end

It works for :login which is an actual attribute of User. However,
since :password was created as an attribute accessor (def password &
def password=), the syntax “user[e]” doesn’t work. I’m looking for a
way to make this work while keeping “attr_accessor :password”

I hope this is clearer.
Thanks for the assist.