Rails supports multiple databases. This means you can specify which database to point a migration at when you use a generator (e.g. bin/rails generate migration CreateDogs name:string --database animals
). For gems, when you are creating a Rails engine, you will often need to create some tables, so you register a generator to install the migrations (e.g. bin/rails generate my_gem:install
). I want to ensure that the generator I am providing from my engine/gem allows the user to specify a specific database, and my gem respects that. With the help of some folks from Twitter, I figured out the requirements.
I started building a new gem this weekend (more about that soon). It needs a generator to install the migrations, so I started with the following:
class SolidErrors::InstallGenerator < Rails::Generators::Base source_root File.expand_path("templates", __dir__) class_option :skip_migrations, type: :boolean, default: nil, desc: "Skip migrations" def create_migration_file unless options[:skip_migrations] rails_command "railties:install:migrations FROM=solid_errors", inline: true end endend
This works, but didn’t allow users to specify a database. I tried a few things, but couldn’t get it to work. I asked for help on Twitter, and Chad Lee B. pointed me to the solution and kowa recommended to checkout how GoodJob
does this. Both were very helpful. I ended up with the following:
class SolidErrors::InstallGenerator < Rails::Generators::Base include ActiveRecord::Generators::Migration source_root File.expand_path("templates", __dir__) class_option :database, type: :string, aliases: %i(--db), desc: "The database for your migration. By default, the current environment's primary database is used." class_option :skip_migrations, type: :boolean, default: nil, desc: "Skip migrations" def create_migration_file return if options[:skip_migrations] migration_template 'create_solid_errors_tables.rb.erb', File.join(db_migrate_path, "create_solid_errors_tables.rb") end private def migration_version "[#{ActiveRecord::VERSION::STRING.to_f}]" endend
There are 3 essential details to ensure that your gem’s generator respects the database option:
- Include
ActiveRecord::Generators::Migration
in your generator - Add a
class_option
fordatabase
- Use
migration_template
method
If you add these three details to your gem’s generator, users will be able to specify a database when they run your generator. For example, if you have a gem called my_gem
and you want to install the migrations for the animals
database, you would run bin/rails generate my_gem:install --database animals
.
This was a fun little problem to solve. I hope this helps you if you are building a gem that needs to install migrations.