Run migrations from rails console - ruby-on-rails

Is there a way to run rake commands for db:migrate and db:rollback on the console?
It sucks to wait for the rails environment to load!

In the console:
ActiveRecord::Migration.remove_column :table_name, :column_name
To update your schema.rb file after running migrations from the console, you must run rails db:migrate

Rails <= 4
This will allow you to migrate without reloading the whole rails environment:
ActiveRecord::Migrator.migrate "db/migrate"
and rollback:
# 3 is the number of migration to rollback, optional, defaults to 1
ActiveRecord::Migrator.rollback "db/migrate", 3
Rails >= 5 (thanks to #gssbzn, his answer is below)
Migrate :
ActiveRecord::MigrationContext.new("db/migrate").migrate
And rollback :
# 3 is the number of migration to rollback, optional, defaults to 1
ActiveRecord::MigrationContext.new("db/migrate").rollback 3

Another way that I find neater to just run some migration command from console is this:
ActiveRecord::Schema.define do
create_table :foo do |t|
t.string :bar
t.timestamps
end
end
This has the advantage that the contents inside the block is compatible with just copy and pasting random contents from a real migration file / schema.rb.

For rails 5.2 the accepted answer has been removed and replaced with
ActiveRecord::MigrationContext.new("db/migrate").migrate
Please be aware as this may also change for future versions of rails as they work to add multiple database connections

For Rails 5 and Rails 6:
ActiveRecord::Base.connection.migration_context.migrate
For Rails 3 and Rails 4:
ActiveRecord::Migrator.migrate 'db/migrate'

I needed to pretend a migration was run to unblock a deploy, this can be done with:
class Mig < ActiveRecord::Base; self.table_name = 'schema_migrations';end
Mig.create! version: '20180611172637'

You can use the %x[command]
%x[rake db:migrate]

To run single migration
ActiveRecord::Migration.add_column(:table_name, :column_name, :data_type)
To run all migrations
ActiveRecord::Migrator.migrate('db/migrate')
To rollback n migrations
ActiveRecord::Migrator.rollback('db/migrate', n)

I created a method in my .irbrc file that runs migrations then reloads the console:
def migrate
if defined? Rails::Console # turn off info logging for Rails 3
old_log_level = ActiveRecord::Base.logger.try(:sev_threshold)
ActiveRecord::Base.logger.sev_threshold = Logger::WARN
end
reload! && migations_ran = true if ActiveRecord::Migrator.migrate(Rails.root.join("db/migrate")).any?
ActiveRecord::Base.logger.sev_threshold = old_log_level if defined? old_log_level
migations_ran ||= nil # useful exit status
end
See the entire file here: https://gist.github.com/imme5150/6548368

Related

Rails 4 Migration Error (Can't rake db:migrate) SQLite3::SQLException: duplicate column name

I've been trying to get the Paperclip gem working. The problem that I was initially running into was that pictures were getting uploaded but not displaying. I then messed around with the database by doing a rake db:rollback to try and fix the error. Now I can't rake db:migrate again because of this error
SQLite3::SQLException: duplicate column name: image_file_name: ALTER TABLE "posts" ADD "image_file_name" varchar
I've personally went into the migration folder and deleted the file to try and generate a migration again. I've been trying to do rails generate paperclip post image and it does create a migration file, but I'm unable to rake db:migrate.
Any suggestions?
Thanks!
Deleting a migration file doesn't really rollback the change it made in your database. Your best bet is to:
Don't delete the migration but comment out the content of the migration class, and run rake db:migrate,
Let's say I have this as my migration file
class AddEmailSentToNeeds < ActiveRecord::Migration
def change
add_column :needs, :email_sent, :boolean ,default: false
end
end
Just comment out the method but leave the class, so it would be:
class AddEmailSentToNeeds < ActiveRecord::Migration
# def change
# add_column :needs, :email_sent, :boolean ,default: false
# end
end
This is just a hacky way to tell rails to skip this migration.
OR
start from the start so go do, rake db:drop, rake db:create, and rake db:migrate

What to do after a failed heroku db:rollback

I'm at the very beginning stages of learning rails using heroku as deployment tool. I ran into a bit of problem today, which is now fixed, but I was wondering if there's a proper/better way to do what I did.
My problem was as follows: I wrote a migration file that created a table with some indices (using add_index). The code would look like this:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
t.string :username
...
end
add_index :users, :username, :unique => true
end
def self.down
drop_table(:users)
remove_index :users, :username
end
end
heroku run rake db:migrate ran fine but heroku run rake db:rollback failed because (I assume) remove_index was trying to delete an index from a column that had already been erased.
So I then added a self.down method to my migration file (removing the indices before dropping the table). Afterwards, heroku run rake db:migrate didn't do anything, and heroku run rake db:rollback is stuck at the same error as before. Resetting the database or dropping the table didn't work either. I ended up removing the add_index lines in my migration before the rollback finally works.
... and unfortunately I no longer have any idea why db:rollback failed. The error message was 'index_users_on_username' on table 'users' does not exist', so my guess is that I did something stupid like modifying the database or modified the migration file before doing a rollback. Or could it be because I am mixing change and down method in the same migration file?
Anyway, my main question is, if a db:rollback fails, what then?
Some options in my head:
Fix the migration file until the rollback works
Fix the database manually until the rollback works
Fix the database manually and ignore the migration completely (dunno how to do this)
this)
???

new to rails, setting up db then running rake db:create/migrate

hi im currently learning rails, and following a tutorial. the instructions were to edit the migration file after i've created the app, then running rake db:migrate, then rake db:create.
i've edited the migration file to this:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :username
t.string :email
t.string :encrypted_password
t.string :salt
t.timestamps
end
end
end
then when i've run 'rake db:migrate' i got an error
Mysql2::Error: Table 'users' already exists: CREATE TABLE `users` ...
after i'm supposed to run 'rake db:create', then im getting this
user_auth_development already exists
user_auth_test already exists
You run rake db:create once and only once, and you run it first. Then you run rake db:migrate every time you add/change a migration. You've either already run this migration, or you are pointing at a database that already exists and already contains a table named users. My guess is that you ran the migration once already, in which case you're probably good to go. If you want to nuke the DB and start over, do rake db:drop db:create db:migrate.
We can simply give, it will do all the rake task which is require for database creation and migration
rake db:setup
For Rails 5 and 6, the command is:
rails setup
This will "create the database, load the schema, and initialize it with the seed data" (docs).
For rails 6 & above, you can give this command to create a database, migrate all the migration files, and seed the data into the database:
rails db:prepare

Show SQL generated by pending migrations in rails without updating the database

I'd like to have a way to produce the actual sql (ie: if I pasted into a mysql console, it would work) that will be generated by a rake db:migrate without actually updating the target database.
rake db:migrate:status does a good job of showing which migrations are pending for a given database, but I've yet to find a way to get the actual SQL produced.
Any ideas?
Very interesting question! I found this way:
Assume your migration placed in file db/migrate/20160102210050_create_items.rb and called CreateItems
Go to Rails console and load migration file:
rails c
require './db/migrate/20160102210050_create_items'
Open transaction, run migration and rollback transaction before commit :)
ActiveRecord::Base.connection.transaction do
CreateItems.new.migrate :up
raise ActiveRecord::Rollback
end
If you want to check SQL on rollback, just call CreateItems.new.migrate :down on step 3. SQL will be executed and tested on database, but not committed - so you can verify your migration without affects.
This can be done by monkey-patching the database adapter. This example works for MySQL.
Create a rake task for "fake db:migrate":
desc "Prints all SQL to be executed during pending migrations"
task :fake_db_migrate => :environment do
module ActiveRecord
module ConnectionAdapters
class AbstractMysqlAdapter < AbstractAdapter
alias_method :real_execute, :execute
def execute(sql, name = nil)
if sql =~ /^SHOW/ || sql =~ /^SELECT.*FROM.*schema_migrations/ || sql =~ /^SELECT.*information_schema/m
real_execute(sql, name)
else
puts sql
end
end
end
end
end
Rake::Task["db:migrate"].invoke
end
The rake task monkey-patches the execute method in the connection adapter so that SQL is printed instead of being executed, before actually running the migrations. However, we still have to execute some of the internal SQLs that are used by the db:migrate task to get the database schema and to find out which migrations are pending. That's what the real_execute call does.
Test
Suppose now that and we have a pending migration in db/migrate/20160211212415_create_some_table.rb:
class CreateSomeTable < ActiveRecord::Migration
def change
create_table :some_table do |t|
t.string :string_column, null: false, default: 'ok'
t.timestamps
end
end
end
$ rake db:migrate:status
...
down 20160211212415 Create some table
Now, let's run our fake migrations task:
$ rake fake_db_migrate
== 20160211212415 CreateSomeTable: migrating ==================================
-- create_table(:some_table)
CREATE TABLE `some_table` (`id` int(11) auto_increment PRIMARY KEY, `string_column` varchar(255) DEFAULT 'ok' NOT NULL, `created_at` datetime, `updated_at` datetime) ENGINE=InnoDB
-> 0.0009s
== 20160211212415 CreateSomeTable: migrated (0.0010s) =========================
BEGIN
INSERT INTO `schema_migrations` (`version`) VALUES ('20160211212415')
COMMIT
The migrations status has not been changed, i.e. the migration is still pending:
$ rake db:migrate:status
...
down 20160211212415 Create some table
Tested on rails 4.2.3 with the mysql2 gem.
A slightly more low-level function, which can be used for your purpose:
# Get SQL query of a migration expression without executing it.
#
# #example
# schema_statement_to_sql { create_table(:tomatoes) }
# # => "CREATE TABLE \"tomatoes\" (\"id\" serial primary key) "
def schema_statement_to_sql(&block)
raise ArgumentError, 'No block given' unless block_given?
connection = ActiveRecord::Base.connection
original_execute = connection.method(:execute)
sql_to_return = ''
capturing_execute = proc { |sql| sql_to_return = sql }
connection.define_singleton_method(:execute, &capturing_execute)
begin
connection.instance_eval(&block)
ensure
connection.define_singleton_method(:execute, &original_execute)
end
sql_to_return
end
You can do
rake db:migrate --dry-run --trace
and rake will test the task. Then use one of the methods listed to get the SQL that would be run.

rails migration version issue: any new migration not working

From this morning, I am facing weird issues with Rails devise. Following is output of my ls and rake db version command.
hrishikesh#hrishikesh-ubuntu:~/git-public/personaldiary/db/migrate$ ls -1
20120110083934_devise_create_users.rb
20120110090514_create_posts.rb
20120110090845_add_user_id_to_post.rb
20120203035323_add_confirmable_to_devise.rb
20120203035323_add_confirmable_to_devise.rb~
20120203043601_add_lockable_to_devise.rb
20120203043601_add_lockable_to_devise.rb~
hrishikesh#hrishikesh-ubuntu:~/git-public/personaldiary/db/migrate$ rake db:version
(in /home/hrishikesh/git-public/personaldiary)
DEPRECATION WARNING: require "activerecord" is deprecated and will be removed in Rails 3. Use require "active_record" instead. (called from /usr/lib/ruby/vendor_ruby/activerecord.rb:2)
Current version: 20120203034555
hrishikesh#hrishikesh-ubuntu:~/git-public/personaldiary/db/migrate$
If I try to add any new migrations, rake db:migrate throws error that tells me that some column already exists, and fails.
My failing migration code is here:
class AddConfirmableToDevise < ActiveRecord::Migration
def change
change_table(:users) do |t|
t.confirmable
end
add_index :users, :confirmation_token, :unique => true
end
end
I specifically do not want to use up and down methods because of this
Please help.
After spending hours to find solution, I decided to give up and ran
rake db:migrate:reset
And it worked, only thing is my data was lost, which was not that big deal at this point.
Thank you everyone for attempting to solve this.

Resources