我想有一种方法来生成将由 rake db:migrate 生成的实际 sql(即:如果我粘贴到 mysql 控制台中,它将起作用),而无需实际更新目标数据库。
rake db:migrate:status 可以很好地显示给定数据库的哪些迁移正在等待,但我还没有找到一种方法来生成实际的 SQL。
有任何想法吗?
我想有一种方法来生成将由 rake db:migrate 生成的实际 sql(即:如果我粘贴到 mysql 控制台中,它将起作用),而无需实际更新目标数据库。
rake db:migrate:status 可以很好地显示给定数据库的哪些迁移正在等待,但我还没有找到一种方法来生成实际的 SQL。
有任何想法吗?
非常有趣的问题!我发现这种方式:
db/migrate/20160102210050_create_items.rb
并调用CreateItems
转到 Rails 控制台并加载迁移文件:
rails c
require './db/migrate/20160102210050_create_items'
打开事务,在提交前运行迁移和回滚事务 :)
ActiveRecord::Base.connection.transaction do
CreateItems.new.migrate :up
raise ActiveRecord::Rollback
end
如果您想在回滚时检查 SQL,只需调用CreateItems.new.migrate :down
第 3 步。SQL 将在数据库上执行和测试,但不会提交 - 因此您可以验证迁移而不会受到影响。
这可以通过对数据库适配器进行猴子修补来完成。此示例适用于 MySQL。
为“fake db:migrate”创建一个 rake 任务:
desc "Prints all SQL to be executed during pending migrations"
task :fake_db_migrate => :environment do
module ActiveRecord
module ConnectionAdapters
class AbstractMysqlAdapter < AbstractAdapter
alias_method :real_execute, :execute
def execute(sql, name = nil)
if sql =~ /^SHOW/ || sql =~ /^SELECT.*FROM.*schema_migrations/ || sql =~ /^SELECT.*information_schema/m
real_execute(sql, name)
else
puts sql
end
end
end
end
end
Rake::Task["db:migrate"].invoke
end
rake 任务猴子修补execute
连接适配器中的方法,以便在实际运行迁移之前打印而不是执行 SQL。但是,我们仍然必须执行db:migrate
任务使用的一些内部 SQL 来获取数据库模式并找出哪些迁移正在等待。这就是real_execute
调用的作用。
现在假设我们有一个待处理的迁移db/migrate/20160211212415_create_some_table.rb
:
class CreateSomeTable < ActiveRecord::Migration
def change
create_table :some_table do |t|
t.string :string_column, null: false, default: 'ok'
t.timestamps
end
end
end
$ rake db:migrate:status
...
down 20160211212415 Create some table
现在,让我们运行我们的假迁移任务:
$ rake fake_db_migrate
== 20160211212415 CreateSomeTable: migrating ==================================
-- create_table(:some_table)
CREATE TABLE `some_table` (`id` int(11) auto_increment PRIMARY KEY, `string_column` varchar(255) DEFAULT 'ok' NOT NULL, `created_at` datetime, `updated_at` datetime) ENGINE=InnoDB
-> 0.0009s
== 20160211212415 CreateSomeTable: migrated (0.0010s) =========================
BEGIN
INSERT INTO `schema_migrations` (`version`) VALUES ('20160211212415')
COMMIT
迁移状态没有改变,即迁移仍然挂起:
$ rake db:migrate:status
...
down 20160211212415 Create some table
mysql2
使用gem在 rails 4.2.3 上测试。
一个稍微低级的函数,可用于您的目的:
# Get SQL query of a migration expression without executing it.
#
# @example
# schema_statement_to_sql { create_table(:tomatoes) }
# # => "CREATE TABLE \"tomatoes\" (\"id\" serial primary key) "
def schema_statement_to_sql(&block)
raise ArgumentError, 'No block given' unless block_given?
connection = ActiveRecord::Base.connection
original_execute = connection.method(:execute)
sql_to_return = ''
capturing_execute = proc { |sql| sql_to_return = sql }
connection.define_singleton_method(:execute, &capturing_execute)
begin
connection.instance_eval(&block)
ensure
connection.define_singleton_method(:execute, &original_execute)
end
sql_to_return
end
你可以做
rake db:migrate --dry-run --trace
并且 rake 将测试任务。然后使用列出的方法之一来获取将要运行的 SQL。