Почему ActiveRecord не использует столбцы primary_key и foreign_key при генерации SQL для объединения в ассоциации? - PullRequest
3 голосов
/ 04 февраля 2010

Я знаю, что могу использовать: finder_sql, чтобы вручную определить SQL, который будет использоваться для извлечения связанных записей, но мне интересно, использует ли ActiveRecord параметры: primary_key и: foreign_key в ассоциации для генерации присоединяющегося SQL.Кажется, это не так, но я что-то здесь упускаю?


Обновление : Чтобы быть более точным, мой вопрос: Есть ли способ сохранитьстолбцы 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

1 Ответ

4 голосов
/ 04 февраля 2010

Мне удалось заставить ваш код работать, изменив определения модели.

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

Вы не можете установить значение для uuid посредством массовых назначений при вызове метода new / create. Вы должны установить значение для 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 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...