ActiveRecord how to ignore pending migrations - ruby-on-rails

The problem is the following:
I have db/seed.rb full of initial data.
One of migrations depends on data this seed provides.
I'm trying to deploy my app from empty db.
Result is:
RAILS_ENV=production rake db:migrate - fails due to lack of initial data
RAILS_ENV=production rake db:seed - fails due to pending migrations
I wanted to somehow tell rake to ignore pending migrations, but unable to do it so far.
UPDATE (due to additional experience)
Sometimes migrations and model code goes out of sync, so migrations are not being run.
To avoid this problem recently used redefining of model in migrations:
# reset all callbacks, hooks, etc for this model
class MyAwesomeModel < ActiveRecord::Base
end
class DoSomethingCool < ActiveRecord::Migration
def change
...
end
end

I am not very sure if this will help you. But I was looking for something and found this question. So it looks like this might help:
In RAILS_ROOT/config/environments/development.rb
Set the following setting to false:
# NOTE: original version is `:page_load`
config.active_record.migration_error = false
In my situation it now does not show the pending migration error anymore. Should work for rake tasks and console for the same environment as well.
Source in rails/rails

Rename the migration dependent on the data from:
20140730091353_migration_name.rb
to
.20140730091353_migration_name.rb
(add a dot at the start of the filename)
Then run rake db:seed (it will no longer complain on the pending migrations) and then rename back the migration.
If you have more migrations following after, you have to rename all of them or just move it temporary away.

Rails stores migration information in a table called schema_migrations.
You can add the version from your migration into that table to skip a specific migration.
The version is the number string which comes before the description in the file name.
[version]_Create_Awesome.rb

I had a similar issue. I commented out the add_column lines and ran the rake db:migrate commands and then removed the comment when I will need it for the testing or production environment.

There is no way unless you monkey patch the Rails code. I strongly advise you to fix your migrations instead.
A migration should not depend on the existence of some data in the database. It can depend on a previous migration, but of course absolutely not on the data on the db.

If you came across the "pending migrations" issue when trying to seed your data from within a running Rails application, you can simply call this directly which avoids the abort_if_pending_migrations check:
ActiveRecord::Tasks::DatabaseTasks.load_seed
See where seeds are actually called from within ActiveRecord:
https://github.com/rails/rails/blob/v6.0.3.2/activerecord/lib/active_record/railties/databases.rake#L331
and see the DatabaseTasks docs:
https://apidock.com/rails/v6.0.0/ActiveRecord/Tasks/DatabaseTasks
https://apidock.com/rails/v6.0.0/ActiveRecord/Tasks/DatabaseTasks/load_seed

Related

How to keep overview of the migrations?

I have a question regarding my migrations in rails.
Normally when i want to add a colum to a model for i dont make extra migrations but instead i perform this steps:
rake db:rollback
next i change the migration file in db/migrations and rerune:
rake db:migrate
The biggest problem is that when i do this i loose my data.
Previous i wrote migrations from the command line with for example
rake g migration Add_Column_House_to_Users house:string
The problem with this approach is that my db/migrations folder afterwards get very large and not very clear! I mean at the end i dont know wich variables the object has! Im not an expert in rails and would like to ask you how to keep the overview over the migrations!Thanks
Just a minor thought - I just use the file db/migrate/schema.rb to determine whats in the database as opposed to tracking through the migrations
You definitely shouldn't use db:rollback with a table with existing data.
I have a few production RonR apps with a ton of data and there are 100+ entries in the migrations table and adding new migrations to tweak tables is the rails way to do things. Not sure what you mean by lucid, but your schema and data model are going to change over time and that is ok and expected.
One tip. The migrations are great, but they are just the beginning, you can include complex logic as needed to fix your existing data (like so)
Changing data in existing table:
def up
add_column :rsvps, :column_name_id, :integer
update_data
end
def update_data
rsvps = Rsvp.where("other_column is not null")
rsvps.each do |rsvp|
invite = Blah.find(rsvp.example_id)
...
rsvp.save
end
end
Another tip: backup your production database often (should do this anyway), but use it to test all of your migrations before deploying. I run scripts like this all the time for local testing:
mysql -u root -ppassword
drop database mydatabase_dev;
create database mydatabase_dev;
use mydatabase_dev;
source /var/www/bak/mydatabase_backup_2013-10-04-16.28.06.sql
exit
rake db:migrate

Can I delete a migration file?

When I ran bundle exec rake db:test:prepare I got the following:
rake aborted!
Multiple migrations have the name CreateMicroposts
To check the status of my migration files, I ran
rake db:migrate:status
And got:
Status Migration ID Migration Name
------- --------------- -----------------
up 20120616205407 Create users
up 20120622103932 Add index to users email
up 20120622114559 Add password digest to users
up 20120628095820 Add remember token to users
up 20120704123654 Add admin to users
down 20120706103254 Create microposts
up 20120707073410 Create microposts
As you can see, I have two migration files with the exact same names and the exact same code in them. It's only their statuses differ, i.e. Up and Down.
What does Up and Down signify?
And which one can I delete, if I have to?
The problem is that you have two different migration files containing the header
class CreateMicroposts< ActiveRecord::Migration
rake db:migrate:status does not check the status of your migration files. It tells you what migrations will be applied if you run rake db:migrate. The up/down labels are pretty much self-explanatory: it tells you whether the migration will be applied via the up method or the down method. The up method is ran when you migrate and the down when you rollback a migration. You can make some further reading about Rails migrations here.
up is the method called when "evolving" (ie migrating to a new schema), while down is the method called when "regressing" (ie migrating to an older schema version, because one of your changes doesn't suit you). db:migrate calls up, db:rollback calls down. In recent versions of rails, there's change that handles both at the same time.
As for the deletion... I don't do activerecord much these days, but I think you're free to do whatever you want with your files. I don't think deleting a duplicate file will do any harm, and if it does.. Well, you use source control, right ? :)

Recreating database: rake tasks using the db end up loading models/other files?

I have a lot of spots in my code that actually call activerecord finders. For example, in a Blog engine, I might have a table of tags that correspond to an activerecord model Tag. Suppose, for some reason, that I want special logic to happen if a post is created with a tag where tag.description == 'humor'. Then I might have a method in the model:
class Tag < ActiveRecord::Base
def self.humor_tag
find_by_description('humor')
end
end
Whether or not this is poor design, it causes insane amounts of problems for me when using rake commands to build a database. Say that later on, I've finished my development and I want to deploy to production. So I take the dumped schema.rb file, and then I want to load a new database structure from that schema.rb, or alternatively, just run my migrations to create a production database.
RAILS_ENV=production rake db:schema:load
The problem is that, in the production environment, the rake command seems to load every model. When it tries to load the Tag#humor_tag method, it throws an error that stops the process:
rake aborted!
Table 'production_database.tags' doesn't exist
Well of course it doesn't exist, it hasn't been created yet! I've googled around and people seem to solve this problem by either cloning the database in SQL or moving around their code just so they can run the rake task.
What are you supposed to do? It seems like there might be some configuration somewhere to let you tell rake to freaking ignore calls to database tables before any tables are created.
I would suggest replacing queries by class methods with scopes: http://guides.rubyonrails.org/active_record_querying.html#scopes
and if you have an initializer that is causing the models to load, use a proc in the scope definition, such as
class Post < ActiveRecord::Base
scope :published, Proc.new { where(:published => true) }
end
to prevent the scope from running at initialization time.
I'm not completely satisfied with this answer, but if anyone gets to this question and has a similar problem, this may be helpful. In order to move over a database in a situation where you would usually rake db:schema:load or just create it and run the migrations, you can alternatively load the database from SQL (or presumably other database technologies).
rake db:structure:dump
That command will dump the structure of the database into a file that will then be able to recreate it. For me, it created a file db/development_dump.sql, that contained calls to create all of the tables and indices, but didn't copy any of the data like on a normal sql dump. Then, I moved that file to my production database, and ran it:
mysql prod_database < development_dump.sql
This doesn't answer the question at hand, but it may be relevant for someone facing a similar problem.

My Migration broke after renaming a model, I can no longer run a db:create

here's what happened. I used to have a Model called Message, I then wanted to rename it so I created a migration that renamed that table from Message to Thread. I had later migrations that then added to that table.
That worked fine, it terms of db:migrate to move forward with our existing databases. Now I noticed that when I do a db:create to create a fresh db it fails, as rails creates Message, then when it goes to add a field to message I get a:
uninitialized constant AddActiveMessageIdToWalls::Message
I think the problem is that I also renamed all the controller & models from message to thread and now the migration can't find the model when migrating? Does that sound right?
How do you deal with this in the rails world? Thanks
I like to keep my db/schema.rb updated to avoid this. So when I need to create the db in a new environment, I just need to do the rake db:create and rake db:schema:load. No migration is needed.
easiest solution: just add an empty Message < ActiveRecord::Base subclass in the earlier migration.
... migration file ...
class Message < ActiveRecord::Base;end

Rails: how to rollback a botched migration

I'm an idiot...screwed up a migration in Rails:
thinking migrations would work like model generators (using references:modelname) I did the following:
$ rails g migration add_event_to_photos references:event
which created the migration
class AddEventToPhotos < ActiveRecord::Migration
def change
add_column :photos, :references, :event
end
end
And now my development database (SQLite3) has a references column of type event in the photos table.
And my schema.rb has a line in the middle saying:
# Could not dump table "photos" because of following StandardError
# Unknown type 'event' for column 'references'
rake db:rollback is powerless against this:
$ rake db:rollback
== AddEventToPhotos: reverting ===============================================
-- remove_column("photos", :references)
rake aborted!
An error has occurred, this and all later migrations canceled:
undefined method `to_sym' for nil:NilClass
So, how to roll back and maintain my development data in the database? I'd even be happy trashing the photos table if that's my only choice..but don't want to have to rebuild the whole thing. What to do?
btw- for anyone reading this about to make same stupid mistake...don't! Use the correct migration generator:
$ rails g migration add_event_to_photos event_id:integer
The easiest way I found to do this was to recreate the table in the schema.rb file in /db/. Afterwards I ran a rake db:reset (if it says you have pending migrations, just delete them and try again).
This took care of the problem.
Go into the database by ./script/rails dbconsole. Then type these commands:
.output dump.sql
.dump
In the file dump.sql you will have the SQL commands used to recreate and populate your database. Just edit it with your favourite editor (like vim ;-) removing or fixing the column type. You may also remove the invalid migration identifier from the schema_migrations table. Drop your database (I suggest just rename the db/development.sqlite file), create new database and read the dump file into it (using command .read dump.sql).
Now you just need to fix and run your migrations.
add an empty down method and run rake db:rollback
edit ahh that's the new migration syntax, you can replace the body with simply:
def self.down; end
which is the old syntax, or perhaps delete the body altogether (haven't tried this) and then run rake db:rollback
Just an idea, I know it's not SQLite specific you can revert to an older version schema perhaps, load it up. And try again from there? You can revert (checkout) specific files in GIT. And then do def self.down; end, as was suggested by another poster.
The problem arises because while SQLite will create the schema with whatever type you give it (in this case event it can't dump that type back to ActiveRecord.
You need to edit the sqlite_master file and change create table string (sql) to be the right thing.
You probably want to back up your table first since messing up that string will wreck your table if you do it wrong.
Here is a related rails issue

Resources