Ruby on rails schema.sql即使在设置schema_format=:sql之后也不创建

Ruby on rails schema.sql即使在设置schema_format=:sql之后也不创建,ruby-on-rails,ruby-on-rails-3,schema,Ruby On Rails,Ruby On Rails 3,Schema,我想创建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。我假设它将在其中转储数据库

我想创建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 
但我希望它在数据库迁移时自动完成


是否有我遗漏或假设错误的内容?

您可能需要删除
schema.rb
以创建
schema.sql

我使用的是rails 2.3.5,但这也可能适用于3.0:


rake db:structure:dump帮了我的忙。

在最初的问题出现五个月后,问题仍然存在。答案是你做的每件事都是正确的,但是Rails中有一个bug

即使在这种情况下,看起来您只需要将格式从:ruby更改为:sql,但迁移任务的定义如下(activerecord/lib/active_record/railties/databases.rake第155行):

如您所见,除非schema_格式等于:ruby,否则不会发生任何事情。 SQL格式模式的自动转储在Rails 1.x中运行。Rails 2中的某些内容已更改,尚未修复

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

该漏洞最近已被注意到:(和),并且在

您可能希望等待修补程序应用于Rails(edge版本仍然存在此缺陷),或者自己应用修补程序(您可能需要手动执行,因为行号有点变化)


解决方法:

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
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 
使用bundler对库进行修补相对比较困难(升级非常容易,经常进行,路径被奇怪的数字所污染-至少如果使用edge rails;-),因此,与其直接修补文件,不如在
lib/tasks
文件夹中创建两个文件:

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
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 

有了这些文件,您就有了修补过的rake任务,而且您仍然可以轻松地升级Rails。当然,您应该监视文件
activerecord/lib/active\u record/railties/databases.rake中引入的更改,并确定是否仍有必要进行修改。

如果可以,我会给您+10,很好的解决方案,也解决了我的问题。好消息是,这已经得到解决。坏消息是,它出现在3.2.0版本候选中,没有迹象表明它被移植到3.1.x。谁知道3.2.0决赛什么时候结束。再次看到提交:好消息,3.2.0出局了!坏消息是,在Rails 3.2.3中,schema_format:sql()的“rake db:setup”被破坏了。嗨,我通过只覆盖两个db:schema:{load,dump}任务对其进行了一些修改,还添加了两个转储和加载数据的实用程序任务。您可以在这里找到源代码:-)这不起作用(至少在我使用的Rails 3.2.7中是这样)。我失败了,消息是
表'schema_migrations'不存在
,这是真的,因为我试图转储没有此Rails特定表的旧数据库的架构。更正:structure.sql文件似乎创建正确。不知道为什么我会犯这个错误。