2013-05-30 69 views
3

在Rails,ActiveRecord::Base.new用於實例化尚未保存到數據庫中的新記錄:Rails如何實例化從數據庫檢索的對象?

new_user = User.new(name: "Bob") 
new_user.new_record? # => true 

那麼,如何Rails的實例化從數據庫中檢索的記錄?它是否使用相同的新方法,然後在事後更改像@new_record這樣的值?或者它使用某種特殊的實例化方法從數據庫中檢索記錄?

+0

這是一個非常廣泛的問題。要麼Google提供一些合適的指南,要麼潛入源代碼。不適合SO,imo。 – Jesper

+0

我問的原因是因爲我想在自己的應用程序中做類似的事情。所以我猜測這種措辭的另一種方法是「如何在Ruby中創建第二個私有初始化器?」 不幸的是,當時我問這個問題,我不知道我真的在尋找第二個初始化程序,我只知道我有一個問題,Rails已經解決了問題,我想知道如何。顯然答案是「他們使用'allocate'與第二個初始化方法。「 – Ajedi32

回答

4

The new_record?方法可以在active_record/persistence.rb在ActiveRecord的框架內找到,它看起來像這樣:

def new_record? 
    @new_record 
end 

然後,如果你在構造看active_record/core.rb你會看到:

def initialize(attributes = nil, options = {}) 
    @attributes = self.class.initialize_attributes(self.class.column_defaults.deep_dup) 
    @columns_hash = self.class.column_types.dup 

    init_internals # here 

    ensure_proper_type 

    populate_with_current_scope_attributes 

    assign_attributes(attributes, options) if attributes 

    yield self if block_given? 
    run_callbacks :initialize if _initialize_callbacks.any? 
end 

如果我們在代碼中挖得深一點:

def init_internals 
    pk = self.class.primary_key 

    @attributes[pk] = nil unless @attributes.key?(pk) 

    @aggregation_cache  = {} 
    @association_cache  = {} 
    @attributes_cache  = {} 
    @previously_changed  = {} 
    @changed_attributes  = {} 
    @readonly    = false 
    @destroyed    = false 
    @marked_for_destruction = false 
    @new_record    = true # here 
    @mass_assignment_options = nil 
end 

正如您所看到的,@ new_record默認初始化爲true

但是存在其中@new_record屬性設置爲true像某些情況下,當你克隆一個記錄:

user = User.first 
new_user = user.clone 

這將調用initialize_dup方法,看起來像:

def initialize_dup(other) # :nodoc: 
    # Code removed 

    @new_record = true 

    # Code removed 
    super 
end 

或當然,當ActiveRecord從數據庫中拉出記錄。我不知道這部分,但我認爲這種方法被稱爲:

def init_with(coder) 
    @attributes = self.class.initialize_attributes(coder['attributes']) 
    @columns_hash = self.class.column_types.merge(coder['column_types'] || {}) 

    init_internals 

    @new_record = false 

    run_callbacks :find 
    run_callbacks :initialize 

    self 
end 

這可以這樣進行:

post = Post.allocate 
post.init_with('attributes' => { 'title' => 'hello world' }) 

在第一條語句,它在堆上分配內存空間而不用像新的那樣調用構造函數。然後它調用特殊構造函數init_with

+0

啊,好的,它使用了一種不同的初始化方法,這很有道理。 – Ajedi32

2

它與instantiate方法,它使用低級別allocate方法而不是new

你可以找到這個方法here完成。

相關問題