2013-02-08 137 views
0

如何根據關聯對象是否已添加或刪除來執行操作?觀察對象和關聯對象

我係統中的每個用戶都有一個關於外部服務的配置文件。該配置文件跟蹤一些用戶的字段。當我的系統中更新了一個或多個這些字段時,我打電話給該服務以更新配置文件。這個電話很貴,所以我只想在必要時做出來。

每個用戶可以有一個寵物,在用戶中表示爲一個字段。用戶的服務配置文件具有表示用戶是否擁有寵物的標誌。

class User < ActiveRecord::Base 
    attr_accessible :name, :shoe_size 
    attr_accessible :unimportant_field1, :unimportant_field2 
    has_one :pet 
end 

class Pet < ActiveRecord::Base 
    belongs_to :user 
end 

class UserObserver < ActiveRecord::Observer 
    observe User 

    def after_create(user) 
    Service.post_user(user) 
    end 

    def after_update(user) 
    if changed(user) 
     Service.put_user(user) 
    end 
    end 

    def changed(user) 
    user.name_changed? || user.shoe_size_changed? || user.pet_changed? 
    # But there is no pet_changed? method! 
    end 
end 

用戶可能獲得這樣的寵物:

user.build_pet 
    # or 
user.pet = Pet.new 
user.save! 

或這樣的:

pet = Pet.create :user => user 

問題:

  • 沒有user.pet_changed?方法; ActiveRecord::Dirty不會跟蹤關聯。
  • 如果用戶像上面的第二個代碼片段一樣獲取寵物,則用戶的觀察者不會被觸發。我可以單獨觀察寵物,只需更新用戶個人資料的寵物字段。但是,如果我在寵物和用戶身上都有觀察者,那麼在第一個代碼片段中,它將首先啓動?如果寵物先發火,我會做POST還是PUT?

我在尋找一個好的模式。也許我必須自己創造它。

+0

試試這個:http://anti-pattern.com/dirty-associations-with-activerecord ...有什麼好處? – micapam

+0

@micapam這是一個不同的場景。這裏的正確答案是使用寵物上的'changed?'方法。而不是'user.pet_changed?'使用'user.pet.changed?'。 – Max

回答

0

而不是使用user.pet_changed?,請使用user.pet.changed?

+0

我試圖捕捉的是當寵物出現或消失時。對象本身的改變可能是另一個問題,但大多數情況下我需要知道user.pet從nil到non-nil的時間,反之亦然。思考? – Ladlestein

+0

是的。你可以做的一件事就是觀察寵物模型。如果你只關心用戶修改寵物的情況,那麼你可以使用'new_record?'方法來檢查寵物是否是新的。所以你可以做'user.pet.new_record?'。同樣,你可以使用'destroy?'來檢查一個對象是否被銷燬。我從來沒有使用破壞,所以你的里程可能會有所不同。查看ActiveRecord :: Persistence的API:http://apidock.com/rails/ActiveRecord/Persistence – Max