Attribute available before_type_cast but nil when accessed directly

谁说胖子不能爱 提交于 2019-12-13 07:13:26

问题


I have an ActiveRecord object that has a before_create hook that generates a SHA hash and stores the result in an attribute of the object:

before_create :store_api_id

attr_reader :api_id

def store_api_id
  self.api_id = generate_api_id
end

private
def generate_api_id                                                                                                                     
  Digest::SHA1.hexdigest([Time.now.nsec, rand].join).encode('UTF-8')                                                                    
end

This works in that the api_id attribute is created and stored in the database as text (which is forced by the call to .encode('UTF-8') otherwise SQLite will try to store the result as binary data.

However the following specs are failing:

it "should be available as ad.api_id" do                                                                                                  
  @ad.save!                                                                                                                               
  @ad.api_id.should_not be_nil                                                                                                            
end                                                                                                                                       

it "should match the directly accessed attribute" do                                                                                      
  @ad.save!                                                                                                                               
  @ad.api_id.should == @ad.attributes['api_id']                                                                                           
end

I can get the correct hash by using ad.api_id_before_type_cast and ad.attributes['api_id'] but not when using ad.api_id.

Ad.find_by_api_id('string api id') also works as expected, but still returns null when calling .api_id on the returned object.

I have double-checked the type in the database as follows:

sqlite> select typeof(api_id) from ads;
text

Here is an example rails console session on a fresh Rails 3.2.2 / ruby 1.9.3-p125 app:

Loading development environment (Rails 3.2.2)
irb(main):001:0> ex = Example.new
=> #<Example id: nil, api_id: nil, created_at: nil, updated_at: nil>
irb(main):002:0> ex.save!   (0.1ms)  begin transaction
SQL (7.3ms)  INSERT INTO "examples" ("api_id", "created_at", "updated_at") 
             VALUES (?, ?, ?)  [["api_id", "fc83bb94420cf8fb689b9b33195318778d771c4e"],
                               ["created_at", Fri, 23 Mar 2012 10:17:24 UTC +00:00], 
                               ["updated_at", Fri, 23 Mar 2012 10:17:24 UTC +00:00]]
(1.0ms)  commit transaction
=> true
irb(main):003:0> ex.api_id
=> nil
irb(main):004:0> ex.api_id_before_type_cast
=> "fc83bb94420cf8fb689b9b33195318778d771c4e"
irb(main):005:0> ex.attributes['api_id']
=> "fc83bb94420cf8fb689b9b33195318778d771c4e"
irb(main):006:0> 

回答1:


As I wrote above, using attr_readonly instead of attr_reader to protect the attribute fixed this issue for me, and in this case is actually closer to what I want.

As the API docs note:

Attributes listed as readonly will be used to create a new record but update operations will ignore these fields.



来源:https://stackoverflow.com/questions/9837126/attribute-available-before-type-cast-but-nil-when-accessed-directly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!