Run a single migration file - ruby-on-rails

Is there an easy way to run a single migration? I don't want to migrate to a certain version I just want to run a specific one.

Assuming fairly recent version of Rails you can always run:
rake db:migrate:up VERSION=20090408054532
Where version is the timestamp in the filename of the migration.
Edit: At some point over the last 8 years (I'm not sure what version) Rails added checks that prevent this from running if it has already been run. This is indicated by an entry in the schema_migrations table. To re-run it, simply execute rake db:migrate:redo VERSION=20090408054532 instead.

You can just run the code directly out of the ruby file:
rails console
>> require "db/migrate/20090408054532_add_foos.rb"
>> AddFoos.new.up
Note: Very old versions of rails may require AddFoos.up rather than AddFoos.new.up.
An alternative way (without IRB) which relies on the fact that require returns an array of class names:
script/runner 'require("db/migrate/20090408054532_add_foos.rb").first.constantize.up'
Note that if you do this, it won't update the schema_migrations table, but it seems like that's what you want anyway.
Additionally, if it can't find the file you may need to use require("./db/..." or try require_relative depending on your working directory

If you want to run a specific migration, do
$ rake db:migrate:up VERSION=20080906120000
If you want to run migrations multiple times, do
# use the STEP parameter if you need to go more than one version back
$ rake db:migrate:redo STEP=3
If you want to run a single migration multiple times, do
# this is super useful
$ rake db:migrate:redo VERSION=20080906120000
(you can find the version number in the filename of your migration)
Edit: You can also simply rename your migration file, Eg:
20151013131830_my_migration.rb -> 20151013131831_my_migration.rb
Then migrate normally, this will treat the migration as a new one (usefull if you want to migrate on a remote environment (such as staging) on which you have less control.
Edit 2: You can also just nuke the migration entry in the database. Eg:
rails_c> q = "delete from schema_migrations where version = '20151013131830'"
rails_c> ActiveRecord::Base.connection.execute(q)
rake db:migrate will then rerun the up method of the nuked migrations.

If you've implemented a change method like this:
class AddPartNumberToProducts < ActiveRecord::Migration
def change
add_column :products, :part_number, :string
end
end
You can create an instance of the migration and run migrate(:up) or migrate(:down) on an instance, like this:
$ rails console
>> require "db/migrate/20090408054532_add_part_number_to_products.rb"
>> AddPartNumberToProducts.new.migrate(:down)

This are the steps to run again this migration file "20150927161307_create_users.rb"
Run the console mode. (rails c)
Copy and past the class which is in that file to the console.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps null: false end
end
end
end
Create an instance of the class CreateUsers: c1 = CreateUsers.new
Execute the method change of that instance: c1.change

As of rails 5 you can also use rails instead of rake
Rails 3 - 4
# < rails-5.0
rake db:migrate:up VERSION=20160920130051
Rails 5
# >= rails-5.0
rake db:migrate:up VERSION=20160920130051
# or
rails db:migrate:up VERSION=20160920130051

If you're having trouble with paths you can use
require Rails.root + 'db/migrate/20090408054532_add_foos.rb'

If you want to run it from console, this is what you are looking for:
$ rails console
irb(main)> require "#{Rails.root.to_s}/db/migrate/XXXXX_my_migration.rb"
irb(main)> AddFoo.migrate(:up)
I tried the other answers, but requiring without Rails.root didnt work for me.
Also, .migrate(:up) part forces the migration to rerun regardless if it has already run or not. This is useful for when you already ran a migration, have kinda undone it by messing around with the db and want a quick solution to have it up again.

Method 1 :
rake db:migrate:up VERSION=20080906120000
Method 2:
In Rails Console
1. Copy paste the migration class in console (say add_name_to_user.rb)
2. Then in console, type the following
Sharding.run_on_all_shards{AddNameToUser.up}
It is done!!

Please notice that instead of script/runner, you may have to use rails runner on new rails environments.

Looks like at least in the latest Rails release (5.2 at the time of writing) there is one more way of filtering the migrations being ran. One can pass a filter in a SCOPE environment variable which would be then used to select migration files.
Assuming you have two migration files 1_add_foos.rb and 2_add_foos.run_this_one.rb running
SCOPE=run_this_one rails db:migrate:up
will select and run only 2_add_foos.run_this_one.rb. Keep in mind that all migration files matching the scope will be ran.

Related

ERROR: extension "btree_gist" must be installed in schema "heroku_ext"

Heroku made a change to the way postgressql extensions gets installed
This is screwing up new rails review apps in heroku with the following error.
ERROR: extension "btree_gist" must be installed in schema "heroku_ext"
This is screwing up things as I need to drop existing extensions and re-enable with heroku_ext schema. I use bin/rails db:structure:load which is before running a migration.
Also the structure.sql is going to diverge as heroku add the schema in review app and we need to run the creation manually in local dev machine.
Does anybody came across this issue?
I have developed a monkey-patch solution that is, well, definitely a hack, but better than pre-dating migrations, or deleting lines from schema.rb.
Put this in config/initializers. I called mine _enable_extension_hack.rb to make sure it gets loaded early.
module EnableExtensionHerokuMonkeypatch
# Earl was here
def self.apply_patch!
adapter_const = begin
Kernel.const_get('ActiveRecord::ConnectionAdapters::PostgreSQLAdapter')
rescue NameError => ne
puts "#{self.name} -- #{ne}"
end
if adapter_const
patched_method = adapter_const.instance_method(:enable_extension)
# Only patch this method if it's method signature matches what we're expecting
if 1 == patched_method&.arity
adapter_const.prepend InstanceMethods
end
end
end
module InstanceMethods
def enable_extension(name)
name_override = name
if schema_exists?('heroku_ext')
puts "enable_extension -- Adding SCHEMA heroku_ext"
name_override = "#{name}\" SCHEMA heroku_ext -- Ignore trailing double quote"
end
super name_override
end
end
end
EnableExtensionHerokuMonkeypatch.apply_patch!
What does it do? It monkey-patches the enable_extension call that's causing the problem in db/schema.rb. Specifically, if it finds that there is a schema called "heroku_ext", it will decorate the parameter given to enable_extension so that the SQL that gets executed specifies the "heroku_ext" schema. Like this:
CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" SCHEMA heroku_ext -- Ignore trailing double quote"
Without this hack, the generated SQL looks like this:
CREATE EXTENSION IF NOT EXISTS "pg_stat_statements"
That's cleaner way of patching schema.rb
# config/initializers/patch_enable_extension.rb
require 'active_record/connection_adapters/postgresql_adapter'
# NOTE: patch for https://devcenter.heroku.com/changelog-items/2446
module EnableExtensionHerokuPatch
def enable_extension(name, **)
return super unless schema_exists?("heroku_ext")
exec_query("CREATE EXTENSION IF NOT EXISTS \"#{name}\" SCHEMA heroku_ext").tap { reload_type_map }
end
end
module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter
prepend EnableExtensionHerokuPatch
end
end
end
EDIT: Here’s the official changelog as a reference https://devcenter.heroku.com/changelog-items/2446
You'll need to do the unthinkable because of the recent heroku changes and modify past migration files for your review apps to work with the new Heroku system for extensions.
Add a predated, or at the top of the first migration file connection.execute 'CREATE SCHEMA IF NOT EXISTS heroku_ext'
Potentially also add to the database.yml a schema_search_path that includes heroku_ext (or set it to public,heroku_ext if you hadn't customized it)
Grep all enable_extension('extension_name')
Replace them all by a connection.execute('CREATE EXTENSION IF NOT EXISTS "extension_name" WITH SCHEMA "heroku_ext")
Pray that is enough to fix the problem
After making those changes we still had to contact heroku support because of, in order:
a pgaudit stack is not empty error
The fix here was to run a maintenance twice (because the postgres add-on which was scheduled for maintenance pre-dated the schema/extension changes change)
a ERROR: function pg_stat_statements_reset(oid, oid, bigint) does not exist error
The fix here was a manual intervention from heroku on the databases. It was caused by heroku trying to run a pg_stat_statements_reset each time a schema is created.
This hack seems to be working for me. The following script runs in the postdeploy step in app.json.
#!/bin/bash -xue
# Create extensions in the schema where Heroku requires them to be created
# The plpgsql extension has already been created before this script is run
heroku pg:psql -a $HEROKU_APP_NAME -c 'create extension if not exists citext schema heroku_ext'
heroku pg:psql -a $HEROKU_APP_NAME -c 'create extension if not exists pg_stat_statements schema heroku_ext'
# Remove enable_extension statements from schema.rb before loading it, since
# even 'create extension if not exists' fails when the schema is not heroku_ext
mv db/schema.rb{,.orig}
grep -v enable_extension db/schema.rb.orig > db/schema.rb
rails db:schema:load
As of Tuesday 16th August 2022, we've found that a patch no longer seems to be needed and enable_extension appears to be working seamlessly as normal without the need to explicitly specify a schema.
When I mentioned this in our ongoing thread with Heroku Support, they said that some of their fixes around the heroku_ext change may have been released at the time of resolving https://status.heroku.com/incidents/2450, but that there are still further fixes in development and yet to be released - so my guess is that this particular issue is one on those that has been fixed!
The answer supplied by dzirtusss got me most of the way there, the last thing I had to do to get this working for my Rails application was to edit the search paths in config/database.yml to include heroku_ext. This is what I appended to my default configuration.
# config/database.yml
default:
schema_search_path: public,heroku_ext
After adding the initialization script and the database.yml edit, I was able to successfully run a heroku pg:copy from one application to another with no errors and no unexpected behavior.
Heroku has introduced an --extensions flag recently, which helps as a workaround. See this FAQ.
For example, if you're using the btree_gist extension, you can use heroku run pg:reset --extensions 'btree_gist' --app YOUR_APP_NAME before running your migrations, they should then work without any changes in your codebase.
Use the Heroku datastore durability tool to create a backup on the
source database or heroku pg:backups:capture -a <SOURCE_APP>.
Determine which pg extensions the database uses (can check from psql
with \dx)
create a comma-separated string of the extensions (e.g.:fuzzystrmatch,pg_stat_statements,pg_trgm,pgcrypto,plpgsql,unaccent,uuid-ossp')
Make sure your Heroku CLI is updated to at least version 7.63.0 (use
heroku update to update)
Run this:
heroku pg:backups:restore $(heroku pg:backups public-url -a <SOURCE_APP>) DATABASE_URL --extensions '<EXTENSIONS>' -a <TARGET_APP>
Reset dynos on the TARGET_APP

Ruby on Rails. Why schema.rb builded on existing data through db:schema:dump is almost empty?

I am trying to find the correct (any) method to create an application in Ruby on Rails having an existing database (PostgreSQL) with data and fresh app made with:
rails new --database=postgresql -J --skip-coffee .
I found https://github.com/frenesim/schema_to_scaffold but first I need to have a file with a database structure: schema.rb. I’m looking for a way to do it automatically.
In result of rake db:schema:dumpfile schema.rb is generated, but only with content like that:
ActiveRecord::Schema.define(version: 0) do
enable_extension "plpgsql"
end
And I stuck here. Why that file is empty? Why are there no tables here?
I have a connection with DB and no errors. I did rake db:create before to test. Creation of bases described in database.yml is successful.
At the beginning I used Docker containers and this is my goal. But to exclude the probability of error, I installed the environment in the system (macOS Mojave) based on the socket. And I’ve got the same effect.
How to generate schema.rb with structure of existing database? Or is there different way to build RoR app based on the existing data structure?
Update: Connection with the new database I only did for testing purposes. To verify configuration.
Here's what else I did:
Dump existing structure with
pg_dump --schema-only app_development > db/structure.sql
I changed name in database.yml to have fresh place to import.
rake db:setup created new DB
rake db:structure:load create tables from db/structure.sql file in DB correctly.
But rake db:schema:dump still generate empty file as earlier.
If you have set proper db config you can use rake db:migrate to regenerate the schema file.
edit:
Ok so lets check if I understood correctly:
you have an existing db with tables and data in it
you have brand new rails app
you want to reflect db structure in you schema.rb file
Is that correct? If yes then like I wrote before - without adding any new migrations to your codebase, run rake db:migrate. That task not only applies changes from the migration file but also updates your schema file to be in sync with the actual database.
I've got it! Two days of my life.
File used to import PostgreSQL database has at the beginning:
CREATE SCHEMA employees;
-- and later
CREATE TABLE employees.department;
I thought that since Rails generates database by rake db:structure:load , the file's syntax is correct.
But when I create manually table users in new empty database and then pg_dump that new base I don't have CREATE SCHEMA query there.
And finally rake db:schema:dump fills schema.rb with tables as I want:
create_table "users", id: :serial, force: :cascade do |t|
t.text "name"
end
Because that fresh pg_dumped file has CREATE TABLE public.users query. public.
I think the key is in comments in database.yml file:
# Schema search path. The server defaults to $user,public
#schema_search_path: myapp,sharedapp,public
One picture is more valuable than a thousand words: that's the differences Table users on the right goes to schema.rb after rake db:schema:dump
Thanks guys for the comments. It's made sure me that I do not make a terrible mistake.
It sounds like you did rake db:create which creates a new database for you and then did rake db:schema:dump which generated a schema.rb file for you from the newly created (empty) database.
If you have an existing database that you want to use you will need to modify your database.yml file to connect to it.
If you want to create a new database you will need to generate Active Record database migrations e.g.) rails generate migration CreateProducts name:string part_number:string and then run them rake db:migrate to update your database and generate your schema.rb.

Rails 5: Why does rails add column to schema.rb even though I've deleted the migration file

I created a migration:
class AddFormCounterToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :form_count, :integer, default: 0
end
end
I ran rails db:migrate but soon realised I had renamed the column incorrectly. So I ran git reset master --hard -- so that the migration file was removed and schema.rb was reset -- and started again:
class AddFormCounterToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :forms_count, :integer, default: 0
end
end
But when I ran rails db:migrate this time, not only was the new column created but also the old one.
t.integer "form_count", default: 0
t.integer "forms_count", default: 0
Wuh? So I ran rails db:rollback to see if that would work. But that fails with the error: No migration with version number 20181025092233. Since I hadn't committed that file, I believe there isn't a way of restoring it.
Where and why is this migration persisting? What's the best practise when deciding to remove and redo a migration? What's the best way out of this pickle? Is there any way other than running rails db:reset? (I'm using Postgres.)
First, do a database backup. Then, drop down your database ( rake db:drop ), after this delete your schema.rb and then, start to clean your project
rake db:schema:cache:clear
rake db:schema:cache:dump
Finally create your database again
rake db:create
rake db:migrate
Most of the time, just remove the "schema.rb" to avoid this kind of error. Always maintain the project organization through the console rails commands. Leave Git to control the versions of your application.
I think you have two solutions here.
Either your recreate the exact migration file you destroyed (with the correct timestamp), and you'll be able to rollback from here rails db:rollback and delete it. The schema will be destroyed accordingly.
Another solution: rails hold all the migration it has done in a database table called schema_migrations. When you migrated the database, a corresponding entry in the schema_migrations was created. When you deleted the migration file by reseting on master, you didn't delete that entry in the table. So you can do this:
rails dbconsole
Once in the console
SELECT * FROM schema_migrations;
you'll see all the timestamps from the migrations you made on the database, the one you thought you deleted is here as well. Copy the timestamp and:
DELETE FROM schema_migrations WHERE version=$yourtimestamp;
Quit the db console and reset your database

Rebuild database enable extension pg_stat_statements line got removed in schema file

After rebuild the database by running:
bin/rake db:drop db:create db:migrate
pg_stat_statements line got removed in db/schema.rb.
Why this line got removed?
The question is really how did it get there in the first place. Did you restore the database from another source, perhaps? This is fairly common if you're using a cloud provider (like Heroku, for example).
You can create an actual migration to add this extension:
class AddStatsExtension < ActiveRecord::Migration
def change
enable_extension 'pg_stat_statements'
end
end

Modify schema.rb in rails application

I am new to rails.
I want to create an Article model. So I run,
rails g model Article name:string context:string
Instead of content I type in context, Is there a way to update the schema.rb file that gets generated?
I would like the articles table to have name and content columns.
Don't focus on schema.rb -- this is just a dump of the current state of your database. Instead, what you need to do is correct the migration file. It is the migration files that actually define what tables/column will exist in production in the end so they must be correct. I'd recommend:
Run ls -ltr db/migrate -- use this to find your migration file and copy the date string. Rails uses this as the "version" of the migration. For example: "20140809165359_create_articles", the version is "20140809165359".
Run bundle exec rake db:migrate:down VERSION=20140809165359 (replace the version number with your own, here)
Now go fix your migration file (change "context" to "content")
Run bundle exec rake db:migrate to migrate back up.
This will fix the underlying problem and you'll notice that now, after migrating back up, your schema.rb will be fixed too.

Resources