我想确认以下分析是正确的:
我正在RoR中构建一个Web应用程序。我有一个我的postgres db设计的数据结构(大约70个表;这个设计可能需要在开发过程中进行更改和添加以反映Rails的处理方式.EG,我设计了一些用户和角色表 - 但是如果使用Restful是有意义的身份验证,我将擦除它们并替换为RA要求的任何内容。)。
我有一个shellcript,它调用一系列.sql文件,用表格和初始数据填充空数据库(例如,城镇预先填充了邮政城镇)以及测试数据(例如,公司得到一些虚拟数据)公司所以我有数据可以玩)。
例如:
CREATE TABLE towns (
id integer PRIMARY KEY DEFAULT nextval ('towns_seq'),
county_id integer REFERENCES counties ON DELETE RESTRICT ON UPDATE CASCADE,
country_id integer REFERENCES countries ON DELETE RESTRICT ON UPDATE CASCADE NOT NULL,
name text NOT NULL UNIQUE
);
命题0:数据持续的时间比应用程序长,因此我确信我希望在数据库级别强制执行参照完整性以及在我的RoR模型中进行验证,尽管缺少DRYNESS。
命题1:如果我用迁移替换脚本和sql文件,目前无法告诉我的Postgres数据库有关外键和我当前在迁移代码中的SQL DDL文件中设置的其他约束。
命题2:迁移的好处是对架构的更改与RoR模型代码一起进行了版本控制。但是如果我将我的脚本和.sql文件保存在railsapp / db中,我可以轻松地对它们进行版本化。
命题3:鉴于迁移缺乏我想要的功能,并提供我可以复制的好处,我没有理由考虑使用它们。所以我应该在脚本/生成模型时间--skipmigrations。
我的问题:如果命题0被接受,命题1,2,3是真还是假,为什么?
谢谢!
答案 0 :(得分:10)
命题1在至少两种情况下是错误的 - 您可以使用foreign_key_migrations等插件执行以下操作:
def self.up
create_table :users do |t|
t.column :department_id, :integer, :references => :departments
end
end
在数据库中创建适当的外键约束。
当然,您可能还有其他想要在DDL中执行的操作,在这种情况下,第二种情况会变得更加引人注目:您不必在迁移中使用Ruby DSL。请尝试使用execute
方法:
def self.up
execute 'YOUR SQL HERE'
end
通过这种方式,您可以将SQL脚本的内容保留在迁移中,从而获得后者的好处(最突出的是down
方法,这些方法在原始问题中未解决)并保留较低级别你喜欢的级别控制。
答案 1 :(得分:4)
命题1是错误的:如果仅在迁移中使用直接SQL,则可以使用迁移定义参照完整性,有关详细信息,请参阅this post。
命题2:对迁移的强烈兴趣是能够逐步定义数据库模型,同时跟踪每个更改的添加内容,并能够在以后轻松回滚任何此类更改。
您必须小心创建/修改内容的顺序,但您可以这样做。
要记住一件事:rails更适合应用程序集中设计。在Rails Way(tm)中,数据库只能通过应用程序活动记录层访问,并使用webservices将数据暴露给外部
答案 2 :(得分:1)
1:您可能想尝试this plugin。我自己并没有尝试过,但它似乎能够通过迁移添加外键约束。
2:迁移的真正好处是能够在数据库的历史记录中来回来回。使用.sql文件并不容易。
3:看看上面提到的插件是否适合你,然后决定:)无论如何,如果你不使用它们,它不是一个死角!
答案 3 :(得分:0)
由于您使用的是Postgres,并且可能不想安装foreign_key_migrations插件,所以当我想同时使用迁移和外键约束时,我就会这样做。
我将一个SchemaStatements方法添加到名为“add_fk_constraint”的ActiveRecord :: SchemaStatements中。 这可以放在一些集中文件中,但在下面的示例迁移文件中,我只是将其内联。
module ActiveRecord
module ConnectionAdapters # :nodoc:
module SchemaStatements
# Example call:
# add_fk_constraint 'orders','advertiser_id','advertisers','id'
# "If you want add/alter a 'orders' record, then its 'advertiser_id' had
# better point to an existing 'advertisers' record with corresponsding 'id'"
def add_fk_constraint(table_name, referencing_col, referenced_table, referenced_col)
fk_name = "#{table_name}_#{referencing_col}"
sql = <<-ENDSQL
ALTER TABLE #{table_name}
ADD CONSTRAINT #{fk_name}
FOREIGN KEY (#{referencing_col}) REFERENCES #{referenced_table} (#{referenced_col})
ON UPDATE NO ACTION ON DELETE CASCADE;
CREATE INDEX fki_#{fk_name} ON #{table_name}(#{referencing_col});
ENDSQL
execute sql
end
end
end
end
class AdvertisersOrders < ActiveRecord::Migration
def self.up
create_table :advertisers do |t|
t.column :name, :string, :null => false
t.column :net_id, :integer, :null => false
t.column :source_service_id, :integer, :null => false, :default => 1
t.column :source_id, :integer, :null => false
end
create_table :orders do |t|
t.column :name, :string, :null => false
t.column :advertiser_id, :integer, :null => false
t.column :source_id, :integer, :null => false
end
add_fk_constraint 'orders','advertiser_id','advertisers','id'
end
def self.down
drop_table :orders
drop_table :advertisers
end
end
我希望这有助于某人。它对我来说非常有用,因为我需要使用SQL“COPY”调用加载大量外部提供的数据,但我发现迁移系统非常方便。