在Ruby on Rails中使用迁移

时间:2008-09-23 11:38:51

标签: ruby-on-rails ruby

我想确认以下分析是正确的:

我正在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是真还是假,为什么?

谢谢!

4 个答案:

答案 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”调用加载大量外部提供的数据,但我发现迁移系统非常方便。