2010-02-04 64 views
3

我知道我可以使用:finder_sql來手動定義用於獲取關聯記錄的SQL,但我想知道ActiveRecord是否在關聯上使用:primary_key和:foreign_key選項來生成連接SQL。它似乎沒有,但我只是在這裏失去了一些東西?爲什麼在生成關聯中的SQL時,ActiveRecord不使用primary_key和foreign_key列?


更新:爲了更加明確,我的問題是:有一些辦法讓ID列作爲主鍵,但已經AR使用不同的列中加入時,我指定我的關係?


這裏的例子模型定義和示例控制檯會話...

模型

class Post < ActiveRecord::Base 
    #Columns are: id:integer uuid:string name:string 
    has_many :assignments, :foreign_key => 'post_uuid', :primary_key => 'uuid' 
    has_many :categories, :through => :assignments 
end 

class Category < ActiveRecord::Base 
    #Columns are id:integer uuid:string name:string 
    has_many :assignments, :foreign_key => 'category_uuid', :primary_key => 'uuid' 
end 

class Assignment < ActiveRecord::Base 
    #Columns are post_uuid:string category_uuid:string 
    belongs_to :post, :foreign_key => 'uuid', :primary_key => 'post_uuid' 
    belongs_to :category, :foreign_key => 'uuid', :primary_key => 'category_uuid' 
end 

控制檯會話

#Make a Post 
>> p = Post.create(:uuid => '123', :name => 'The Post') 
    Post Create (0.9ms) INSERT INTO "posts" ("name", "created_at", "uuid", "updated_at") VALUES('The Post', '2010-02-04 00:05:13', '123', '2010-02-04 00:05:13') 
=> #<Post id: 2, uuid: "123", name: "The Post", created_at: "2010-02-04 00:05:13", updated_at: "2010-02-04 00:05:13"> 

#Make a Category 
>> c = Category.create(:uuid => '456', :name => 'The Category') 
    Category Create (0.5ms) INSERT INTO "categories" ("name", "created_at", "uuid", "updated_at") VALUES('The Category', '2010-02-04 00:05:30', '456', '2010-02-04 00:05:30') 
=> #<Category id: 2, name: "The Category", uuid: "456", created_at: "2010-02-04 00:05:30", updated_at: "2010-02-04 00:05:30"> 

#Make an Assignment, associating the post and the category 
>> a = Assignment.create(:post_uuid => p.uuid, :category_uuid => c.uuid) 
    Assignment Create (0.4ms) INSERT INTO "assignments" ("created_at", "updated_at", "post_uuid", "category_uuid") VALUES('2010-02-04 00:05:50', '2010-02-04 00:05:50', '123', '456') 
=> #<Assignment id: 2, post_uuid: "123", category_uuid: "456", created_at: "2010-02-04 00:05:50", updated_at: "2010-02-04 00:05:50"> 

#Try to fetch the category from the post object, which generates the wrong SQL 
>> p.categories 
    Category Load (0.0ms) SQLite3::SQLException: no such column: assignments.uuid: SELECT "categories".* FROM "categories" INNER JOIN "assignments" ON "categories".id = "assignments".uuid WHERE (("assignments".post_uuid = 2)) 
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: assignments.uuid: SELECT "categories".* FROM "categories" INNER JOIN "assignments" ON "categories".id = "assignments".uuid WHERE (("assignments".post_uuid = 2)) 
[...Stack trace edited out...] 

#Also odd: Try to fetch the post from the Association, no SQL generated, we just get nil 
>> a.post 
=> nil 

回答

4

我能得到您的代碼工作通過改變你的模型定義。

class Post < ActiveRecord::Base 
    set_primary_key :uuid # tell the model about the non standard primary key 
    has_many :assignments, :foreign_key => 'post_uuid' 
    has_many :categories, :through => :assignments 
end 

class Category < ActiveRecord::Base 
set_primary_key :uuid # tell the model about the non standard primary key 
has_many :assignments, :foreign_key => 'category_uuid' 
end 

class Assignment < ActiveRecord::Base 
    belongs_to :post, :foreign_key => 'post_uuid' # notice the value for the foreign_key 
    belongs_to :category, :foreign_key => 'category_uuid' # notice the value for the foreign_key 
end 

除此之外,更改遷移文件提名的類別和型號後,非標主鍵(UUID)。

class CreatePosts < ActiveRecord::Migration 
    def self.up 
    create_table :posts, {:id => false} do |t| 
     t.string :uuid, :primary => true, :limit => 20 
     t.string :name 
     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :posts 
    end 
end 

class CreateCategories < ActiveRecord::Migration 
    def self.up 
    create_table :categories, {:id => false} do |t| 
     t.string :uuid, :primary => true, :limit => 20 
     t.string :name 

     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :categories 
    end 
end 

在調用new/create方法時,不能通過質量分配設置uuid的值。您必須顯式設置primary_key的值。

# this will not work. uuid will be set to 0 
p = Post.create(:uuid => '123', :name => 'The Post') 

# this will work 
p = Post.new(:name => 'The Post') 
p.uuid = '123' 
p.save 
+0

感謝您的支持。我知道我可以明確聲明不同的列是我模型中的主鍵。但是我想知道的是,我可以在關聯中進行連接嗎?而不需要在我的模型上更改我的主鍵? – 2010-02-04 10:37:57

+0

好的。我現在明白你的問題。生成的SQL語句在categories.id上創建爲JOIN,而不是categories.uid。我不能想到解決方案在我頭上。我的解決方案確實解決了您的一個問題,即a.post/a.category爲零。在您的Assignment模型中,belongs_to指令是錯誤的。 – 2010-02-04 11:39:14

+0

@KandaBoggu,belongs_to指令改變你上面提到的只有在post/uuid/category_uuid作爲post/category模型中的主鍵時才起作用。我不希望在我的情況下這樣做。我只是問,是否有某種方法可以將id列保留爲主鍵,但是當我指定我的關係時,AR會爲連接使用不同的列。 – 2010-02-04 21:45:50

相關問題