【发布时间】:2016-09-21 15:40:01
【问题描述】:
我有一个具有非 Rails 常规主键的模型。
class Guoid < ActiveRecord::Base
self.primary_key = :guoid
end
及相关迁移
class CreateGuoids < ActiveRecord::Migration
def change
create_table :guoids, id: false do |t|
t.integer :guoid, limit: 8, auto_increment: true, primary_key: true
t.integer :parent_guoid, limit: 8
t.string :resource_type, limit: 60
end
end
end
现在我想在另一个模型中引用这个模型,并尝试使用 references 创建迁移,但这不起作用。
class ContentUnit < ActiveRecord::Base
self.primary_key = :guoid
end
class Content < ActiveRecord::Base
self.primary_key = :guoid
belongs_to :user
belongs_to :content_unit
end
及相关迁移
class CreateContents < ActiveRecord::Migration
def change
create_table :contents, id: false do |t|
t.references :content_unit, index: true, foreign_key: true
t.references :user, index: true, foreign_key: true
end
end
end
当我运行迁移时,出现以下错误。
Mysql2::Error: Can't create table `myapp_development_cr1`.`#sql-54a_308` (errno: 150 "Foreign key constraint is incorrectly formed"): ALTER TABLE `contents` ADD CONSTRAINT `fk_rails_823443bd0d`
FOREIGN KEY (`content_unit_id`)
REFERENCES `content_units` (`id`)
我希望在contents 表中创建content_unit_guoid 外键,并在guoids 表中引用guoid。
我使用 activerecord-mysql-awesome gem 来很好地处理非 Rails 约定的主键。
这是一个触发器,它首先在guids 表中创建一条记录,并将其 pk 作为目标表的 pk。
DELIMITER $$
CREATE TRIGGER `content_before_insert` BEFORE INSERT ON `content`
FOR EACH ROW BEGIN
IF NEW.guoid = 0 THEN
INSERT INTO `content`.guoids (resource_type)
VALUES('Content');
SET NEW.guoid = LAST_INSERT_ID();
END IF;
END
$$
DELIMITER ;
【问题讨论】:
-
这是一个遗留应用程序,你必须使用这种奇怪的设置,还是你只是喜欢让自己变得困难?
-
没有。它不是遗留应用程序。我必须创建一个全局唯一的 id 并在不同的表中使用它。我的非 Rails 背景技术经理建议使用此类 ID。
-
他是个白痴。经理们通常是:)。您需要在每个表上都有主键才能使 ActiveRecord 工作。我强烈建议您坚持使用 rails 默认设置。
id用于每个表,_id用于外键。 -
首先,检查您是否真的需要全局唯一 ID。如果你这样做,那么我建议使用 uuid,而不是更改约定。改变它们会给你带来很多痛苦。
-
附言。 GUID 真的只是微软为我们其他人所说的 UUID 代言
标签: mysql ruby-on-rails ruby-on-rails-4 database-migration referential-integrity