Reputation: 3501
I am having a strange problem in Rails. I want to set the value of a field in an model in Rails, but I can't do it, even in the rails console. Observe:
1.9.3p393 :008 > campy = Campaign.last
Campaign Load (0.8ms) SELECT `campaigns`.* FROM `campaigns` ORDER BY `campaigns`.`id` DESC LIMIT 1
=> #<Campaign id: 3, name: "Stuff", ..., approved_at: nil, approval_requested_at: nil>
1.9.3p393 :009 > campy.approved_at = Time.now
=> 2013-07-01 00:54:38 +0200
1.9.3p393 :010 > campy.save
(0.2ms) BEGIN
(0.2ms) COMMIT
=> true
1.9.3p393 :011 > campy.approved_at
=> 2013-07-01 00:54:38 +0200
1.9.3p393 :012 > Campaign.last.approved_at
Campaign Load (0.7ms) SELECT `campaigns`.* FROM `campaigns` ORDER BY `campaigns`.`id` DESC LIMIT 1
=> nil
1.9.3p393 :013 > campy = Campaign.last
Campaign Load (0.6ms) SELECT `campaigns`.* FROM `campaigns` ORDER BY `campaigns`.`id` DESC LIMIT 1
=> #<Campaign id: 3, name: "Stuff", ..., approved_at: nil, approval_requested_at: nil>
1.9.3p393 :014 > campy.approved_at = Time.now
=> 2013-07-01 00:55:11 +0200
1.9.3p393 :015 > campy.save
(0.3ms) BEGIN
(0.2ms) COMMIT
=> true
1.9.3p393 :016 > Campaign.last.approved_at
Campaign Load (0.7ms) SELECT `campaigns`.* FROM `campaigns` ORDER BY `campaigns`.`id` DESC LIMIT 1
=> nil
I am trying to set the value of the last Campaign's approved_at attribute to Time.now, but it remains nil, even after I save it. approved_at is made available via the attr_accessor function in the top of Campaign's model. Why can't I change the value of this attribute?
Edit:
Another interesting aspect of the problem is that when I set campy.approved_at and then look up the value explicitly, I get the correct value. However, when I look at campy as a variable, Rails still shows the value as nil
1.9.3p393 :027 > campy.approved_at = Time.now
=> 2013-07-01 01:19:05 +0200
1.9.3p393 :028 > campy.save
(0.2ms) BEGIN
(0.2ms) COMMIT
=> true
1.9.3p393 :029 > campy.approved_at
=> 2013-07-01 01:19:05 +0200
1.9.3p393 :030 > campy
=> #<Campaign id: 3, name: "Stuff", ... , approved_at: nil, approval_requested_at: nil>
Upvotes: 0
Views: 716
Reputation: 7978
This is because you've created approved_at
as a virtual attribute with attr_accessor
. I suggest you do some reading into attr_accessor
and attr_accessible
, but in this instance you need neither.
By specifying it as a virtual attribute it's not persisting to the database. Remove the attr_accessor
line and you won't have any problems.
Explanation:
attr_accessor
creates getter an setter methods for an in-memory attribute on that model. This will take precedence over the getter and setter method that are automatically generated by ActiveRecord
for your underlying database attribute, so when you call save
, AR doesn't think that you've updated approved_at
because really you haven't, you've updated the virtual attribute only.
attr_accessible
is used to allow mass assignment of particular attributes, for instance if you were passing the value as part of a hash of attributes to create
or new
.
Upvotes: 4