2011-07-08 42 views
1

在rails 3.0.9/ruby​​ 1.9.2當我嘗試更新模型外鍵時,出現意外的行爲。Rails3 activerecord update_attributes無法保存foreign_key

我開始一個新的安裝在app /型號

$ rails new mytest 
$ rails g model User 
$ rails g model Ad user_id:integer 
$ rake db_migrate 

添加關聯/ Ad.rb

Class User < ActiveRecord::Base 
    belongs_to :user 
end 

現在到了有趣的部分。我想直接更改對象上的外鍵。我進入軌道控制檯軌道ç

$ u = User.create 
$ a=Ad.create(:user=>u) 
$ a.update_attributes(:user_id => 9999) 
$ a.user_id 
=> 4 

所以這是行不通的。我嘗試直接設置對象而不是傳遞它來創建:

$ u = User.create 
$ a=Ad.create 
$ a.user = u 
$ a.save 
$ a.update_attributes(:user_id => 9999) 
$ a.user_id 
=> 5 

不起作用。

的作品的唯一事情是這樣的:

$ u = User.create 
$ a=Ad.create 
$ a.user_id = u.id 
$ a.save 
$ a.update_attributes(:user_id => 9999) 
$ a.user_id 
=> 9999 

能有人請解釋是怎麼回事,我怎麼可以改變我的對象的外鍵?我假設當對象關聯被實例化並且存在衝突時發生「阻塞」行爲,所以一個答案是這樣做的:

$ Ad.find(a.id).update_attributes(:user_id => xxxx) 

這是有效的。但是,在一個對象上更改外鍵看起來還有很長的路要走。它還需要額外的數據庫命中,最後如果對象內部需要自行更新,則代碼非常混亂。該怎麼辦?

+0

順便說一下之前就卸載加載的對象:我就遇到了這個問題的原因是,我從機械師切換到FactoryGirl。機械師不會在創建時加載關聯的對象,但FactoryGirl會這樣做。 – user681814

回答

0

做更新

a = Ad.create(:user=>User.create) 
a.user.reset # Unload association object, the foreign key is untouched 
a.update_attributes(:user_id=>9999) 
a.user_id 
    => 9999 

可以使工廠的女孩創建卸載關聯對象這樣

def Factory.lazy(model) 
    obj = Factory(model) 
    obj.attributes.each{ |k,v| 
    if assoc = k[/(.*)_id$/,1] 
     eager = obj.send(assoc) 
     eager.send("reset") unless eager.nil? 
    end 
    obj 
} 
0

嗯,我認爲正確的解釋要求我檢查Rails的源代碼,並檢查它在update_attributes中發生的情況。我會在稍後檢查。

但我想正確的事情不只是更新屬性,而是整個用戶對象。喜歡的東西:

u = User.create; a = Ad.create; a.user = u; a.save; a.user = User.find(9999); a.save 

或者只是操縱你的對象的ID,如你注意到它的工作:

u = User.create; a = Ad.create; a.user_id = u.id; a.save; a.user_id = 9999; a.save 
0

它看起來像您遇到的問題是因爲你試圖改變USER_ID直接屬性。由於您已將belongs_to :user添加到Ad模型中,因此Rails還提供了許多其他方法來幫助處理關聯。下面是來自軌道引導頁面上的belongs_to方法:http://edgeguides.rubyonrails.org/association_basics.html#belongs_to-association-reference

在這種情況下,你可以使用這樣的事情:

u1 = User.create 
u2 = User.create 
a=Ad.create(:user=>u) 

a.user_id將等於u1.id

要更新的關聯,你可以做這個:

a.user = u2 
a.save! 

現在a.user_id應該等於u2.id

Rails這樣做是因爲它假定關聯不僅僅是一個外鍵,因爲User對象比後端外鍵更重要。

+0

感謝您的詳細解釋。我發現了第三種解決方法,我認爲這是最好的,因爲我不想讓額外的數據庫命中,並更改代碼以適應測試套件使用 - 它應該是相反的方式。情況是我有一個關聯對象,我想通過JSON將它複製到另一個對象。這在軌道上完美地工作,但Factory Girl(測試夾具生成器)創建加載的對象關聯。看下一個答案。 – user681814

+0

你可以讓Factory Girl建立對象而不碰到數據庫。因此,在你的情況Factory.build(:對象),而不是Factory.create(:對象) –

+0

好吧,沒有深入解釋Factory.build(:對象)不適合我的目的,我需要的對象在數據庫中持久化,但沒有加載的關聯(build()不會這樣做),而純粹的Factory()將所有東西加載到對象中。看到我的答案做什麼 - 無法回答我自己的問題8小時:-) – user681814

相關問題