2010-09-18 27 views
2

我有這樣的事情:如何在ActiveRecord中設置has_one默認值?

class User < ActiveRecord::Base 
    has_one :profile 
end 

class Profile < ActiveRecord::Base 
    belongs_to :user 
end 

user = User.new 
user.profile.something #=> ERROR 

什麼是設置在這種情況下,默認的配置文件對象有道?我試過這個:

class User < ActiveRecord::Base 
    default_scope :include => :profile 
    has_one :profile 

    def after_initialize 
    self.profile ||= Profile.new(:user => self) 
    end 
end 

...但是創建N + 1個查詢。有任何想法嗎?

更新

這是我現在工作好,還在尋找更好的東西:

class User < ActiveRecord::Base 
    default_scope :include => :profile 
    has_one :profile, :autosave => true 

    def after_initialize 
    self.profile = Profile.new(:user => self) if new_record? 
    end 
end 

這樣,你將有一個配置文件,只要你終於create您用戶。否則,唯一的情況是new_record?

回答

0

正確的答案取決於你的意圖是什麼,因爲這種問題沒有直接的解決方案。

after_initialize回調是在對象被實例化後調用的,所以對於這種邏輯來說它並不是一個好地方。

也許你應該嘗試使用before_create/after_create來代替?這些回調僅在創建對象時調用。

另外,不要使用Profile.new,請使用以下替代方法之一:

self.build_profile(...) 
self.create_profile(...) 

在該模型被保存在第二種情況。您可以將模型屬性的散列傳遞給這兩種方法(不要傳遞:user,因爲它是自動設置的)。

+0

我正想着這些,但實際上我specifi c的情況下,profile類取決於子類:'class Admin 2010-09-19 01:05:41

1

我認爲你的答案很好。我有一個稍微不同的解決方案:

class User < ActiveRecord::Base 
    default_scope :include => :profile 
    has_one :profile 
    alias_method :my_profile, :profile 

    def my_profile 
    self.profile = Profile.create(:user => self) unless self.profile 
    self.profile 
    end 
end 

  • 要求時,不實例化

不太好創建個人資料

  • 你有使用my_profile(或無論你想稱呼它)
  • unless self.profile檢查,必須對每個配置文件調用
+0

謝謝,但我不喜歡這樣的別名方法,它使子類化和包括模塊更難以管理。 – 2010-09-19 01:03:10

3

你可以寫你自己的用戶#配置文件,將建立一個爲你做,如果它不「T存在:

class User < ActiveRecord::Base 
    has_one :profile 

    def profile_with_default 
    profile_without_default || build_profile 
    end 
    alias_method_chain :profile, :default 
end 
0

This是一個很好的答案:

class User < ActiveRecord::Base 
has_one :preference_set 

def preference_set 
    super || build_preference_set 
    end 
end