Eric Baldwin
Eric Baldwin

Reputation: 3501

Setting the values of a model in Rails

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

Answers (1)

Mike Campbell
Mike Campbell

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

Related Questions