即使在设置 schema_format = :sql 之后,schema.sql 也不会创建 [英] schema.sql not creating even after setting schema_format = :sql

查看:39
本文介绍了即使在设置 schema_format = :sql 之后,schema.sql 也不会创建的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建 schema.sql 而不是 schema.rb.在谷歌搜索后我发现它可以通过在 application.rb 中设置 sql 模式格式来完成.所以我在 application.rb 中设置了以下

config.active_record.schema_format = :sql

但如果我将 schema_format 设置为 :sql,则根本不会创建 schema.rb/schema.sql.如果我注释上面的行,它会创建 schema.rb,但我需要 schema.sql.我假设它将在其中转储数据库结构并且我知道可以使用

转储数据库结构

rake db:structure:dump

但我希望在迁移数据库时自动完成.

有什么我遗漏或假设错误的地方吗?

解决方案

在原来的问题五个月后问题仍然存在.答案是你做的一切都是正确的,但是 Rails 有一个错误.

即使在指南中,看起来您只需要更改格式从 :ruby 到 :sql,但是迁移任务是这样定义的(activerecord/lib/active_record/railties/databases.rake line 155):

task :migrate =>[:environment, :load_config] 做ActiveRecord::Migration.verbose = ENV["VERBOSE"] ?ENV["VERBOSE"] == "true" : trueActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby结尾

如您所见,除非 schema_format 等于 :ruby,否则不会发生任何事情.以 SQL 格式自动转储模式在 Rails 1.x 中工作.Rails 2 中发生了一些变化,但尚未修复.

问题是,即使您设法以 SQL 格式创建模式,也没有将其加载到数据库中的任务,并且任务 rake db:setup 将忽略您的数据库结构.

最近注意到了这个错误:https://github.com/rails/rails/issues/715(和 issues/715),https://gist.github.com/971720

您可能希望等到补丁应用到 Rails(边缘版本仍然存在此错误),或者自己应用补丁(您可能需要手动执行,因为行号已更改了一点).<小时>

解决方法:

使用 bundler 相对难以修补库(升级非常简单,它们经常进行并且路径被奇怪的数字污染 - 至少如果您使用边缘导轨;-),因此,您可能希望在 lib/tasks 文件夹中创建两个文件,而不是直接修补文件:

lib/tasks/schema_format.rake:

import File.expand_path(File.dirname(__FILE__)+"/schema_format.rb")# 将 *_structure.sql 文件加载到当前环境的数据库中.# 这是'test:clone_structure'任务的一个稍微修改的副本.def db_load_structure(文件名)abcs = ActiveRecord::Base.configurations案例 abcs[Rails.env]['适配器']当/mysql/ActiveRecord::Base.establish_connection(Rails.env)ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')IO.readlines(filename).join.split("\n\n").each do |table|ActiveRecord::Base.connection.execute(table)结尾当/postgresql/ENV['PGHOST'] = abcs[Rails.env]['host'] if abcs[Rails.env]['host']ENV['PGPORT'] = abcs[Rails.env]['port'].to_s if abcs[Rails.env]['port']ENV['PGPASSWORD'] = abcs[Rails.env]['password'].to_s if abcs[Rails.env]['password']`psql -U "#{abcs[Rails.env]['username']}" -f #{filename} #{abcs[Rails.env]['database']} #{abcs[Rails.env]['模板']}`当/sqlite/dbfile = abcs[Rails.env]['database'] ||abcs[Rails.env]['dbfile']`sqlite3 #{dbfile} <#{文件名}`当'sqlserver'`osql -E -S #{abcs[Rails.env]['host']} -d #{abcs[Rails.env]['database']} -i #{filename}`# 有一个相对路径.那很重要吗?: db\\#{Rails.env}_structure.sql`当 'oci', 'oracle'ActiveRecord::Base.establish_connection(Rails.env)IO.readlines(filename).join.split(";\n\n").each do |ddl|ActiveRecord::Base.connection.execute(ddl)结尾当火鸟"set_firebird_env(abcs[Rails.env])db_string = firebird_db_string(abcs[Rails.env])sh "isql -i #{文件名} #{db_string}"别的引发'#{abcs[Rails.env]['adapter']}'不支持的任务"结尾结尾命名空间 :db 做命名空间:结构做desc "将 development_structure.sql 文件加载到当前环境的数据库中"任务:加载 =>:环境做file_env = 'development' # 你想要结构来自哪个环境?# 您可以使用参数或定义不同的任务.db_load_structure "#{Rails.root}/db/#{file_env}_structure.sql"结尾结尾结尾

lib/tasks/schema_format.rb:

def dump_structure_if_sqlRake::Task['db:structure:dump'].invoke if ActiveRecord::Base.schema_format == :sql结尾Rake::Task['db:migrate'].enhance do dump_structure_if_sql endRake::Task['db:migrate:up'].enhance do dump_structure_if_sql endRake::Task['db:migrate:down'].enhance do dump_structure_if_sql endRake::Task['db:rollback'].enhance do dump_structure_if_sql endRake::Task['db:forward'].enhance do dump_structure_if_sql endRake::Task['db:structure:dump'].enhance do# 如果没有重新启用,那么在 db:migrate:redo 任务中,转储只会被调用一次,# 并且将仅包含向下迁移后的状态.Rake::Task['db:structure:dump'].reenable结尾# 'db:setup' 任务需要重写.Rake::Task['db:setup'].clear.enhance(['environment']) # 看到调用的 .clear 方法了吗?Rake::Task['db:create'].invokeRake::Task['db:schema:load'].invoke if ActiveRecord::Base.schema_format == :rubyRake::Task['db:structure:load'].invoke if ActiveRecord::Base.schema_format == :sqlRake::Task['db:seed'].invoke结尾

有了这些文件,你就有了猴子补丁的 rake 任务,你仍然可以轻松地升级 Rails.当然,您应该监视文件 activerecord/lib/active_record/railties/databases.rake 中引入的更改,并决定是否仍然需要修改.

I want to create schema.sql instead of schema.rb. After googling around I found that it can be done by setting sql schema format in application.rb. So I set following in application.rb

config.active_record.schema_format = :sql

But if I set schema_format to :sql, schema.rb/schema.sql is not created at all. If I comment the line above it creates schema.rb but I need schema.sql. I am assuming that it will have database structure dumped in it and I know that the database structure can be dumped using

rake db:structure:dump 

But I want it to be done automatically when database is migrated.

Is there anything I am missing or assuming wrong ?

解决方案

Five months after the original question the problem still exists. The answer is that you did everything correctly, but there is a bug in Rails.

Even in the guides it looks like all you need is to change the format from :ruby to :sql, but the migrate task is defined like this (activerecord/lib/active_record/railties/databases.rake line 155):

task :migrate => [:environment, :load_config] do
  ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
  ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
  db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
end

As you can see, nothing happens unless the schema_format equals :ruby. Automatic dumping of the schema in SQL format was working in Rails 1.x. Something has changed in Rails 2, and has not been fixed.

The problem is that even if you manage to create the schema in SQL format, there is no task to load this into the database, and the task rake db:setup will ignore your database structure.

The bug has been noticed recently: https://github.com/rails/rails/issues/715 (and issues/715), and there is a patch at https://gist.github.com/971720

You may want to wait until the patch is applied to Rails (the edge version still has this bug), or apply the patch yourself (you may need to do it manually, since line numbers have changed a little).


Workaround:

With bundler it's relatively hard to patch the libraries (upgrades are so easy, that they are done very often and the paths are polluted with strange numbers - at least if you use edge rails ;-), so, instead of patching the file directly, you may want to create two files in your lib/tasks folder:

lib/tasks/schema_format.rake:

import File.expand_path(File.dirname(__FILE__)+"/schema_format.rb")

# Loads the *_structure.sql file into current environment's database.
# This is a slightly modified copy of the 'test:clone_structure' task.
def db_load_structure(filename)
  abcs = ActiveRecord::Base.configurations
  case abcs[Rails.env]['adapter']
  when /mysql/
    ActiveRecord::Base.establish_connection(Rails.env)
    ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
    IO.readlines(filename).join.split("\n\n").each do |table|
      ActiveRecord::Base.connection.execute(table)
    end
  when /postgresql/
    ENV['PGHOST']     = abcs[Rails.env]['host'] if abcs[Rails.env]['host']
    ENV['PGPORT']     = abcs[Rails.env]['port'].to_s if abcs[Rails.env]['port']
    ENV['PGPASSWORD'] = abcs[Rails.env]['password'].to_s if abcs[Rails.env]['password']
    `psql -U "#{abcs[Rails.env]['username']}" -f #{filename} #{abcs[Rails.env]['database']} #{abcs[Rails.env]['template']}`
  when /sqlite/
    dbfile = abcs[Rails.env]['database'] || abcs[Rails.env]['dbfile']
    `sqlite3 #{dbfile} < #{filename}`
  when 'sqlserver'
    `osql -E -S #{abcs[Rails.env]['host']} -d #{abcs[Rails.env]['database']} -i #{filename}`
    # There was a relative path. Is that important? : db\\#{Rails.env}_structure.sql`
  when 'oci', 'oracle'
    ActiveRecord::Base.establish_connection(Rails.env)
    IO.readlines(filename).join.split(";\n\n").each do |ddl|
      ActiveRecord::Base.connection.execute(ddl)
    end
  when 'firebird'
    set_firebird_env(abcs[Rails.env])
    db_string = firebird_db_string(abcs[Rails.env])
    sh "isql -i #{filename} #{db_string}"
  else
    raise "Task not supported by '#{abcs[Rails.env]['adapter']}'"
  end
end

namespace :db do
  namespace :structure do
    desc "Load development_structure.sql file into the current environment's database"
    task :load => :environment do
      file_env = 'development' # From which environment you want the structure?
                               # You may use a parameter or define different tasks.
      db_load_structure "#{Rails.root}/db/#{file_env}_structure.sql"
    end
  end
end

and lib/tasks/schema_format.rb:

def dump_structure_if_sql
  Rake::Task['db:structure:dump'].invoke if ActiveRecord::Base.schema_format == :sql
end
Rake::Task['db:migrate'     ].enhance do dump_structure_if_sql end
Rake::Task['db:migrate:up'  ].enhance do dump_structure_if_sql end
Rake::Task['db:migrate:down'].enhance do dump_structure_if_sql end
Rake::Task['db:rollback'    ].enhance do dump_structure_if_sql end
Rake::Task['db:forward'     ].enhance do dump_structure_if_sql end

Rake::Task['db:structure:dump'].enhance do
  # If not reenabled, then in db:migrate:redo task the dump would be called only once,
  # and would contain only the state after the down-migration.
  Rake::Task['db:structure:dump'].reenable
end 

# The 'db:setup' task needs to be rewritten.
Rake::Task['db:setup'].clear.enhance(['environment']) do # see the .clear method invoked?
  Rake::Task['db:create'].invoke
  Rake::Task['db:schema:load'].invoke if ActiveRecord::Base.schema_format == :ruby
  Rake::Task['db:structure:load'].invoke if ActiveRecord::Base.schema_format == :sql
  Rake::Task['db:seed'].invoke
end 

Having these files, you have monkeypatched rake tasks, and you still can easily upgrade Rails. Of course, you should monitor the changes introduced in the file activerecord/lib/active_record/railties/databases.rake and decide whether the modifications are still necessary.

这篇关于即使在设置 schema_format = :sql 之后,schema.sql 也不会创建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆