2014-02-25 54 views
0

假設我有以下型號的現有應用:的Rails:轉換的has_many到HAS_ONE協會

class User < ActiveRecord::Base 
    has_many :locations, :through => :location_users 
end 

class Location < ActiveRecord::Base 
    has_many :users, :through => :location_users 
end 

我如何去了解這個的has_many轉換爲HAS_ONE協會像下面,就遷移,修剪記錄有多個地點的人,還有我錯過的其他東西?有沒有任何捷徑來做這種轉換?

class User < ActiveRecord::Base 
    belongs_to :location 
end 

class Location < ActiveRecord::Base 
    has_many :users 
end 

編輯:用戶屬於一個且只有一個位置

+1

你確定你想讓位置表存儲'user_id'的主鍵嗎?或者應該是'users'表存儲一個'location_id'(即用戶將只屬於一個位置)? –

+1

讓用戶belongs_to更合理:位置和位置has_many:用戶? ...是的,carlosramireziii說了些什麼。 – Coenwulf

+0

你們都對,這是我的邏輯錯誤。我現在編輯它。 – konyak

回答

1

沒有捷徑可走。

寫遷移添加location_idusers

class AddLocationIdToUsers < ActiveRecord::Migration 
    def change 
    add_column :users, :location_id, :integer 
    end 
end 

,你可以寫另一個遷移來填充現有用戶LOCATION_ID。 對於例如,如果你想填充在locations_users表

class PopulateLocationIdOnUser < ActiveRecord::Migration 
    def up 
    #executing direct query to speed up the operation 
    execute("update users set location_id = (select location_id from locations_users where locations_users.user_id = users.id limit 1)") 
    end 

    def down 
    execute("update users set location_id = null") 
    end 
end 

而另一遷移用戶第一LOCATION_ID下降locations_users表

class DropLocationsUsersTable < ActiveRecord::Migration 
    def up 
    drop_table :locations_users 
    end 

    def down 
    create_table :locations_users do |t| 
    #columns 
    end 
    end 
end 

你也可以有一個單一的遷移做所有這三個步驟。

+0

對不起,你能修改你的答案嗎?我只是做了一個編輯,其中用戶只屬於一個位置 – konyak

+0

@ChaseT .:修改了答案 – usha

+0

謝謝,我剛剛意識到最後一次遷移是不可逆的。可能想要在DropLocationsUsersTable遷移的down方法結束時添加'raise ActiveRecord :: IrreversibleMigration,「無法恢復已刪除的數據」。 – konyak

1

這並不是一個簡單的方法。根據我的經驗,您將不得不做大量的手動工作。這是我如何去做的:

  1. 編寫遷移以將user_id添加到位置表。

  2. 運行遷移

  3. 添加HAS_ONE關係代碼。 (就像你有以上)

    class User < ActiveRecord::Base 
        has_one :location 
    end 
    
    class Location < ActiveRecord::Base 
    belongs_to :user 
    end 
    
  4. 要麼寫遷移到所有現有的數據在轉換。 (例如,location.user = location.users.first)。但是在這種情況下寫一個rake任務可能會更好,因爲這隻會發生一次,並且它需要在您的關係代碼上繼續存在。因此,一旦刪除has_many代碼,您的遷移將無效。

  5. 運行您的耙子任務

  6. 取出has_many碼和連接表。

做完這一切後,它應該都工作。其他人可能有更好的方法,但這是我做到的。