2012-03-23 67 views
0

我有具有before_create鉤,其生成SHA散列,並將結果存儲在所述對象的屬性的ActiveRecord的對象:屬性可用before_type_cast但零時直接訪問

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 

這工作,所述api_id創建屬性,並存儲在數據庫中的文本(這是通過調用.encode('UTF-8')用力,否則會的SQLite試圖將結果保存爲二進制數據

但是以下規格的失敗:

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 

通過使用ad.api_id_before_type_castad.attributes['api_id'],我可以得到正確的散列值,但在使用ad.api_id時不能。

Ad.find_by_api_id('string api id')也按預期工作,但在返回的對象上調用.api_id時仍然返回null。

我已經雙重檢查在數據庫中的類型,如下所示:

sqlite> select typeof(api_id) from ads; 
text 

下面是一個例子rails console會話上的新鮮的Rails 3.2.2 /紅寶石1.9.3-P125應用程式:

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> 
+0

看來,使用'attr_readonly:api_id'而不是'attr_reader:api_id'按預期工作。 – 2012-03-23 14:06:54

回答

0

正如我上面寫的,使用attr_readonly而不是attr_reader來保護這個屬性,爲我解決了這個問題,在這種情況下實際上更接近我想要的。

由於API docs注:爲只讀上市

屬性將被用來創建一個新的記錄,但更新操作會忽略這些字段。