I dont want Rails 3 to generate my schema every time I do migration. How to properly disable it?
Thanks
For anyone who is still looking for a way to disable the db dump after migration a configuration is now available in rails 4 which can be set to false like this:
config.active_record.dump_schema_after_migration = false
will prevent it. The configuration has been added in this change - https://github.com/rails/rails/pull/13948
Create an application specific task (as Alex Kaushovik suggested) like so...
Create a file lib\tasks\db_schema_override (actual name doesn't matter, you need a .rake file in lib\tasks) with contents as below (credit to Matthew Bass for remove_task)
Rake::TaskManager.class_eval do
def remove_task(task_name)
#tasks.delete(task_name.to_s)
end
end
Rake.application.remove_task('db:schema:dump')
namespace :db do
namespace :schema do
task :dump do
# Overridden to do nothing
end
end
end
A modification based on David Waller's answer that retains the ability to run db:schema:dump manually. Covers all tasks where schema dumping is automatically invoked. Based on rails 3.2.14 versions of the relevant tasks - when you change rails versions, you'll want to ensure that the task definitions are still valid.
Seriously, there should be a config option to disable automatic schema dumps.
Rake::TaskManager.class_eval do
def remove_task(task_name)
#tasks.delete(task_name.to_s)
end
Rake.application.remove_task("db:migrate")
Rake.application.remove_task("db:rollback")
Rake.application.remove_task("db:forward")
Rake.application.remove_task("db:migrate:up")
Rake.application.remove_task("db:migrate:down")
end
namespace :db do
desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
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) do |migration|
ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
end
# db_namespace['_dump'].invoke
end
desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
task :rollback => [:environment, :load_config] do
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
# db_namespace['_dump'].invoke
end
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
task :forward => [:environment, :load_config] do
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_paths, step)
# db_namespace['_dump'].invoke
end
namespace :migrate do
# desc 'Runs the "up" for a given migration VERSION.'
task :up => [:environment, :load_config] do
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
raise 'VERSION is required' unless version
ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
# db_namespace['_dump'].invoke
end
# desc 'Runs the "down" for a given migration VERSION.'
task :down => [:environment, :load_config] do
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
raise 'VERSION is required' unless version
ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
# db_namespace['_dump'].invoke
end
end
end
I've tested the following - it works:
You could modify the file "databases.rake" inside of the Rails gem's lib/tasks folder on your server(s). Comment out lines with the following code:
Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
By default on Ubuntu (and Ubuntu server) it is here: /var/lib/gems/1.8/gems/rails-x.x.x/lib/tasks/databases.rake.
Tested with Rails 2.3.11, but I'm pretty sure it'll work with Rails 3.x.x too.
Another possible solution (didn't test):
You wouldn't have to modify Rails files, just your application.
A rails plugin called "override_rake_task" could be used to override Rake task "db:schema:dump" which is defined inside if Rails gem.
Apparently if you are not using this plugin and if you define a task in your rails application with the same name, rake would execute both tasks: the default and yours.
The default behavior of Active Record is to dump the schema, but it only does it if the schema dump format is set to ruby (the default).
You can disable the schema dump after migrations by setting the schema format to sql. You can safely reverse it to ruby after the migration finishes without consequences.
You can do it in this way:
1) If you have a line like this one setting explicitly the schema to ruby:
config.active_record.schema_format = :ruby
(it could be inside config/application.rb, on config/environment or in the specific environment you are running the migration in).
Then comment it out:
#config.active_record.schema_format = :ruby
2) Then add a line to set the schema format to SQL, either in the environment you are using, or at config/application.rb, as follows:
config.active_record.schema_format = :sql
Rather than overriding the db:migrate behavior (which is obviously necessary when you're building the migration in development, but unnecessary when deploying) I would suggest creating a separate task like:
# http://stackoverflow.com/questions/13646840/how-to-make-rake-dbmigrate-generate-schema-rb-when-using-sql-schema-format
namespace :db do
desc "Migrate the database, without dumping the schema.rb"
task :deploy => :environment do
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
ActiveRecord::Migrator.migrate("db/migrate/", nil)
end
end
Then during your deployments you can simply do
rake db:deploy
Related
In Rails 5, I am no longer able to use a rake task that migrates files in a different directory. I get the error ActiveRecord::UnknownMigrationVersionError: No migration with version number 20180209214145.
Any idea how I could do this in Rails 5? I think that the line ActiveRecord::Migrator.migrations_paths = ['db/manual_migrate'] no longer works as expected, but I am not quite sure how to fix it.
desc 'Run db:migrate:up on a task we wish to migrate manually (e.g. not on all servers).' \
'VERSION is required.'
task manual_migrate: [:environment, :load_config] do
raise 'VERSION of migration is required for this task!' unless ENV['VERSION']
default_paths = ActiveRecord::Migrator.migrations_paths
ActiveRecord::Migrator.migrations_paths = ['db/manual_migrate']
begin
Rake::Task['db:migrate:up'].invoke
ensure
ActiveRecord::Migrator.migrations_paths = default_paths
end
end
I'm trying to use Sequel to manage migrations for my database, and sometimes, due to feature-branching, there are moments when the database has migrations applied that don't exist in the filesystem.
By default, when I apply migrations with sequel -m on those situations I get this error:
Error: Sequel::Migrator::Error: Applied migration files not in file system
"Migrations" says there's an option for that:
Ignoring missing migrations
In some cases, you may want to allow a migration in the database that does not exist in the filesystem (deploying to an older version of code without running a down migration when deploy auto-migrates, for example). If required, you can pass :allow_missing_migration_files => true as an option. This will stop errors from being raised if there are migrations in the database that do not exist in the filesystem.
Nice!
How do I pass that allow_missing_migration_files option to sequel -m?
I think you'll have to use the Sequel::Migrator API for that. Something like
Sequel::Migrator.run(DB, '/path/to/migrations/dir', allow_missing_migration_files: true)
You can also wrap this behavior in a Rake task, so you don't have to start a console to run migrations.
namespace :db do
desc "Run migrations ignoring the missing ones"
task :migrate_without_missing, [:version] do |t, args|
require "sequel"
Sequel.extension :migration
db = Sequel.connect(ENV.fetch("DATABASE_URL"))
if args[:version]
puts "Migrating to version #{args[:version]}"
Sequel::Migrator.run(db, "db/migrations", target: args[:version].to_i, allow_missing_migration_files: true)
else
puts "Migrating to latest"
Sequel::Migrator.run(db, "db/migrations", allow_missing_migration_files: true)
end
end
end
Then run rake db:migrate_without_missing.
I see that the Sequel gem supports migrations here, but I don't see any type of generator documented. Does one exist; or should I be manually creating all of my migrations (or alternately creating my own task to generate migrations)?
From the documentation:
Sequel doesn't come with generators that create migrations for you. However, creating a migration is as simple as creating a file with the appropriate filename in your migrations directory that contains a Sequel.migration call.
The contents of the migration file doesn't have to specify a timestamp or index and it's an extremely simple format.
I generally just copy a previous migration (maybe one similar to the migration I'm creating) and alter the filename. See existing migrations with:
$ ls -1 db/migrate/
20170320075430_check_postgres_extensions.rb
...
For running migrations, I use the rake task that's available here.
Sequel has no migration generator. But you can easily write your own, for example using a rake task. Here is one:
# Rakefile
require 'fileutils'
namespace :db do
MIGRATIONS_DIR = 'db/migrations'
desc "generates a migration file with a timestamp and name"
task :generate_migration, :name do |_, args|
args.with_defaults(name: 'migration')
migration_template = <<~MIGRATION
Sequel.migration do
up do
end
down do
end
end
MIGRATION
file_name = "#{Time.now.strftime('%Y%m%d%H%M%S')}_#{args.name}.rb"
FileUtils.mkdir_p(MIGRATIONS_DIR)
File.open(File.join(MIGRATIONS_DIR, file_name), 'w') do |file|
file.write(migration_template)
end
end
end
Then run the rake task like this rake db:generate_migration[my_migration_name]. This command will create a Sequel migration file 20220720233750_my_migration_name.rb in the directory db/migrations.
ActiveRecord 3.2.14
I want to use ActiveRecord in a non-Rails Ruby project. I want to have available the rake tasks that are defined by ActiveRecord. How can I do that?
rake db:create # Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)
rake db:drop # Drops the database using DATABASE_URL or the current Rails.env (use db:drop:all to drop all databases)
rake db:fixtures:load # Load fixtures into the current environment's database
rake db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false)
rake db:migrate:status # Display status of migrations
rake db:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n)
rake db:schema:dump # Create a db/schema.rb file that can be portably used against any DB supported by AR
rake db:schema:load # Load a schema.rb file into the database
rake db:seed # Load the seed data from db/seeds.rb
rake db:setup # Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)
rake db:structure:dump # Dump the database structure to db/structure.sql
rake db:version # Retrieves the current schema version number
The above list is the list of tasks that I want to be able to use on my non-Rails Ruby project that uses ActiveRecord. What do I have to write in my Rakefile?
Thanks in advance
The easiest thing to do is to load the tasks already defined in databases.rake. Here is a GIST of how it was done.
Inspired by this GIST by Drogus
Rakefile.rb
require 'yaml'
require 'logger'
require 'active_record'
include ActiveRecord::Tasks
class Seeder
def initialize(seed_file)
#seed_file = seed_file
end
def load_seed
raise "Seed file '#{#seed_file}' does not exist" unless File.file?(#seed_file)
load #seed_file
end
end
root = File.expand_path '..', __FILE__
DatabaseTasks.env = ENV['ENV'] || 'development'
DatabaseTasks.database_configuration = YAML.load(File.read(File.join(root, 'config/database.yml')))
DatabaseTasks.db_dir = File.join root, 'db'
DatabaseTasks.fixtures_path = File.join root, 'test/fixtures'
DatabaseTasks.migrations_paths = [File.join(root, 'db/migrate')]
DatabaseTasks.seed_loader = Seeder.new File.join root, 'db/seeds.rb'
DatabaseTasks.root = root
task :environment do
ActiveRecord::Base.configurations = DatabaseTasks.database_configuration
ActiveRecord::Base.establish_connection DatabaseTasks.env.to_sym
end
load 'active_record/railties/databases.rake'
You could try the standalone-migrations gem:
https://github.com/thuss/standalone-migrations
For Rails 3.x:
You need to manually create the tasks. As example here is how to add them (this example uses the environment variables like Rails):
namespace :db do
desc "Drop and create the current database"
task :recreate => :environment do
abcs = ActiveRecord::Base.configurations
ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
ActiveRecord::Base.connection.recreate_database(ActiveRecord::Base.connection.current_database)
end
end
and you'll have the task rake db:recreate available
For Rails 4.x:
If you want to have the ActiveRecord rake tasks available in your ruby app, take a look at the documentation.
Example usage of DatabaseTasks outside Rails could look as such:
include ActiveRecord::Tasks
DatabaseTasks.database_configuration = YAML.load(File.read('my_database_config.yml'))
DatabaseTasks.db_dir = 'db'
# other settings...
DatabaseTasks.create_current('production')
Also you have here an example on how to use ActiveRecord in your ruby aplication.
Create your own!
Reference the Rails one though:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/railties/databases.rake
Create a Rake Task file. To use Rake, generally you want a tasks folder filled with Rake task files. These files have the ".task" extension.
Study the file to link given.
Take parts of that file, or even the entire contents of the file, and add it to your new Rake task file.
Make sure your Rakefile loads those task files. Your Rakefile should have something like this
-
Dir[File.join(PROJECT_ROOT, 'tasks', '**', '*.rake')].each do |file|
load file
end
I believe you can use the sinatra-activerecord gem even if you're not using Sinatra. I just solved this problem by requiring that gem and then adding
require 'sinatra/activerecord/rake'
to my rakefile.
Once I added that require line the db tasks showed up in my rake -T!
If you are using Sinatra, you can use this gem:
https://github.com/janko-m/sinatra-activerecord
However, if you don't use it either, the source code inside provides a good example on how to implement AR rake tasks.
How can I have the tests for my Rails app to be executed in a random order?
Is there a simple solution using rake?
Here you go, define this in lib/tasks/tasks.rb
namespace :test do
namespace :randomize do
desc "Randomize tests"
Rake::TestTask.new(:all => "db:test:prepare") do |t|
t.libs << "test"
t.test_files = Rake::FileList[
'test/unit/**/*_test.rb',
'test/functional/**/*_test.rb',
'test/integration/**/*_test.rb'
].shuffle
t.verbose = true
end
end
end
Run: rake test:randomize:all
Keep in mind that within file tests will still be executed in the order they appear. I guess you could monkey patch test unit to allow for that.
You may wish to check out "ZenTest 3.9.0: now with more Evil" (can't do a direct link, use google's cache)
Added ability to set test execution order, defaults to :random. EVIL!