Pięć miesięcy po pierwotnym pytaniu problem nadal istnieje. Odpowiedź brzmi, że zrobiłeś wszystko poprawnie, ale w Railsach jest błąd.
Nawet w the guides wygląda na to wszystko, co potrzebne jest, aby zmienić format z Ruby do: SQL, ale zadanie Migrate jest zdefiniowany następująco (activerecord/lib/active_record/railties/databases.rake linia 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
Jak widać, nic się nie dzieje, chyba że schemat ma format: ruby. Automatyczne odrzucanie schematu w formacie SQL działało w Railsach 1.x. Coś się zmieniło w Rails 2 i nie zostało naprawione.
Problem polega na tym, że nawet jeśli uda się utworzyć schemat w formacie SQL, nie ma zadania, aby załadować je do bazy danych, a zadanie rake db:setup
zignoruje strukturę bazy danych.
Błąd został zauważony niedawno: https://github.com/rails/rails/issues/715 (i issues/715), a tam jest łata na https://gist.github.com/971720
Możesz poczekać, aż łata jest nakładana na Rails (wersja krawędź nadal ma ten błąd) lub zastosuj łatkę samodzielnie (może być konieczne ręczne wykonanie, ponieważ numery linii zmieniły się nieznacznie).
Obejście:
Z Bundler jest stosunkowo trudno załatać bibliotek (aktualizacje są tak łatwe, że są one wykonywane bardzo często i ścieżki są zanieczyszczone dziwnych numerów - przynajmniej jeśli używać krawędź szyny ;-), więc zamiast łatania plik bezpośrednio, może chcesz utworzyć dwa pliki w folderze 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
i 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
Mając te pliki, trzeba monkeypatched zadania Rake, a nadal można łatwo uaktualnić szynach. Oczywiście powinieneś monitorować zmiany wprowadzone w pliku activerecord/lib/active_record/railties/databases.rake
i zdecydować, czy modyfikacje są nadal konieczne.
Dałbym ci +10, gdybym mógł, dobre rozwiązanie, również rozwiązał moją sprawę. – KensoDev
Dobrą wiadomością jest to, że zostało to rozwiązane. Złą wiadomością jest to, że znajduje się on w wersjach 3.2.0, bez żadnych oznak przywracania ich do wersji 3.1.x. Kto wie, kiedy skończy się wersja 3.2.0. Zobacz commit: https://github.com/rails/rails/commit/15fb4302b6ff16e641b6279a3530eb8ed97f2899 –
Dobra wiadomość ponownie, 3.2.0 jest już dostępny! –