how devise db:migrate works on production - ruby-on-rails

I'm doing my first project on RoR I decided to use Devise gem for the authentication everything is working fine in Localhost, right now i'm able to sing_up, log_in, reset pass and some other default features that comes with devise.
What I don't understand is how everything gets setup once i push the project into production environment. Let me explain better.
-I see that devise generates db/schema.rb file based on the user.rb model that devise auto generate, these schema i assume needs to be created in the production db.
I have to push the project into git repo but..
1) How the code gets executed once is published
2) How the user table gets created
3) where do I need to specify the db connection (db, user, pass)
In general how is the process to migrate into production env?
I appreciate your help.

In rails db schema is controlled using migrations. Migrations are usually very small files living in db/migrations folder. Each of them defines a single subclass of ActiveRecord::Migration class.
Each migration is supposed to go both-ways, so it has to implement both up and down method (for rollback). In majority of the changes those are obvious (like when up action creates a table, down action should destroy it). For migrations like this you can use change function - rails will create down function automatically (assuming that all actions are reversible - some of the methods even accept extra arguments to make it possible like remove_column :table, :field, :integer. :integer bit might seem redundant here, however the action is irreversible without that information).
You run your migrations using db:migrate rake task. Effectively it will run all the migration which has not been run against current database. When it is done, it will dump your current database into db/schema.rb file. This file is used only as a snapshot of your current database schema, which is of great help if you need to get back to previous version of your application (which is why schema.rb should always be checked into your source control). It is also possible to recreate your database directly from that file rake db:schema:load, however it will cost you all your data.
If you check your database (any environment), you will notice there is one extra table called schema_migrations which does not appear in your schema file. This table contains all the migrations that has been executed against this database. This way rails will not retry migrations that already has been run.
There are many advantages of using migration system:
It is easy for every developer to bring their local database up to the latest schema.
It is easy to rollback your latest changes if deployment failed. (Not always the case)
So how to use it in production? You simply has to point the rake task to the right database:
RAILS_ENV=production rake db:migrate
You can find your database configuration in config/database.yml file. Note that this is the best practice not to store that file in source control and in case of production it is not advisable to store your database password there. Normally you will need to set it through environment variable.
It is important to remember couple of things about migrations:
Never, ever change the existing migration if there is a chance that someone has already run it. Especially, do not modify migrations that has run in production unless you are 100% sure what you are doing (for example fixing rollback). Since database remembers which migrations has run, it might lead to getting your local db out of sync with production db and hence lead to bugs.
Never ever change database schema manually - every change has to be made through migrations.

Well depending on where you're hosting your code you should still do a rake db:migrate to make the changes to the production DB.
If deployed on Heroku, run the following in the console:
heroku run rake db:migrate
Hope that answers your question?

Related

Can I manually create migrations for production in Heroku, Ruby on Rails?

I have created an application with Ruby and Rails. The thing is that when I was develpoing it, I had some problems with the migrations, because I created them but with a wrong syntax. What happened is that I deleted some of the files because sold migrations that didn´t work had the same name than the new ones, but in the middle of that I accidentally deleted some of the migrations (obviously after running rails db:migrate) that the project uses actually. So for instance, i have the Service table, which is related to the Reservation table because Service has reservation_id, but i don´t have the migration file that says AddReservationIdToService.
So now I want to use Heroku for production. the thing is that O have to change to postgresql because Heroku doesn't support sqlite. So i have to run the de:migrate again to create the tables and relationships in the new DB, but I need the files that I explained that I deleted. The question is:
Can I create the migrations manually, so when i run db:migrate for postgres the full structure of the database is created without lacking relations?
You don't really need the migrations to recreate the existing DB -- in fact it's not a good idea to try for a couple of reasons (including the missing migration file problem you encountered). You can simply run:
bin/rails db:schema:load
to populate a new database from the existing schema. If for some reason you haven't got a db/schema.rb checked under version control you can run:
bin/rails db:schema:dump
against the sqlite version to re-create a fresh schema file from the database.
You can also keep your migrations list tidy by occasionally zapping really old migrations, since all the cumulative changes are captured in the schema file.
Yes, you might create another couple of migration files.
Certify you have now the tables you wish locally with your sqlite. Draw these table in a piece of paper (or where it be the best fr you), then check this official API documentation of Rails.
Delete all migrations made before and create another according to the tables you drew.
The workflow is gonna be like:
1) "I need to create a table called Reservation, where is it shown on the documentation?"
2) "I need a table called Service, where is it shown on the documentation?
3) "I need to add a column with a foreign key to service named reservaton_id, how does this documentation says it?
For all this steps above, create the correspondent migration file as you normally have done.
The main difference here is not to run the migration locally. Instead, push your new version app to your heroku remote branch and there you run the migration, like:
heroku run rails db:migrate
Remember to not run this same migration locally because you already have these tables locally.
The last two advise is:
1) If your migration doesn't go as you expect, don't delete the migration file. Instead, run rails db:rollback and try again.
2) Keep tracking your migration files on the same branch of your version control.

Rails - autogenerate migrations from database changes

Is it possible to use Rails to auto-generate a migration based on changes that took place in the database outside of Rails since the last migration?
I know that running db:migrate will change the schema.rb to match what's in the database.... (at least if don't make any migrations but I do change the database in some way manually). What I'm wondering is, if there is a way as part of that same mechanism or process to have it create a migration out of those changes.
Many thanks!
I don't think this is something Rails would do or is trying to solve. Rails wants you to explicitly manage those changes through migrations so that your database is under control (and source control).
See if this gem is what you want. - https://github.com/pjhyett/auto_migrations
It might not work with Rails 3. I think since you edit your DB directly you'd have to run rake db:schema:dump to update the schema.rb file.
If you want to capture the deltas between the different db change points then see this SO answer:
How to generate Rails Migration class automatically from MYSQL database instance? , just repeat his steps along the way.

Rails - Generating migration script from model

I am learning rails, and I came across Migrations. It seems that everytime I want to edit a model, I would need to add a migration script, even though I am not yet in production.
Can you edit your model, add all your attributes you need to it, and before releasing it, have the migration script autogenerated?
Thanks!
If your using rails 3+ you might want to consider DataMapper instead of ActiveRecord. It lets you define the data model in the model instead of multiple migration files. As I understand DataMapper lets you generate migrations from changes.
This is a tried and trusted pattern often used in the wider ORM community.
I agree with the comments so far. The idea of migrations is to make it simple to fluidly adapt your data schema to fit your application as you want to add new fields. It's a simple and beautiful system.
So yes, you can (and should) use rails generate migration... as not only does this generate the proper code in many common cases, it also keeps track of which migrations have been run in different versions of the database. See http://guides.rubyonrails.org/migrations.html#creating-a-migration
A common workflow might be something like this:
create a new model, for example User with fields like first_name, last_name, user_name
this will create an associated migration, which you can run using bundle exec rake db:migrate -- your database schema will be updated
you decide you want additional information, such as birthdate, so run rails generate migration AddBirthdateToUser birthdate:date. For some simple operations like adding a column, index, etc., the full migration code will be generated; in other cases you'll need to write the migration. When done, run the migration.
If you find a problem in development, for example a field type should be float, not integer, or you forgot to add an index, you can roll back the migration (bundle exec rake db:rollback), fix the migration and re-run it.
run your tests (which will run the migrations), and when it all works for you locally, check in the files (including the migrations) and deploy to a QA or staging server, which has its own copy of the database.
run rake db:migrate on the staging server. If you're on a team and other developers have checked in migrations, their will run, too. Now your code and data schema are in sync.
repeat :-)
There's no harm whatsoever running migrations during a production deployment (I respectfully disagree with a comment above) -- you should embrace the idea that change, even changes like this (which can be incredibly difficult in other environments) are a normal part of everyday Rails life!

rake db:schema:load vs. migrations

Very simple question here - if migrations can get slow and cumbersome as an app gets more complex and if we have the much cleaner rake db:schema:load to call instead, why do migrations exist at all?
If the answer to the above is that migrations are used for version control (a stepwise record of changes to the database), then as an app gets more complex and rake db:schema:load is used more instead, do they continue to maintain their primary function?
Caution:
From the answers to this question: rake db:schema:load will delete data on a production server so be careful when using it.
Migrations provide forward and backward step changes to the database. In a production environment, incremental changes must be made to the database during deploys: migrations provide this functionality with a rollback failsafe. If you run rake db:schema:load on a production server, you'll end up deleting all your production data. This is a dangerous habit to get into.
That being said, I believe it is a decent practice to occasionally "collapse" migrations. This entails deleting old migrations, replacing them with a single migration (very similar to your schema.rb file) and updating the schema_migrations table to reflect this change. Be very careful when doing this! You can easily delete your production data if you aren't careful.
As a side note, I strongly believe that you should never put data creation in the migration files. The seed.rb file can be used for this, or custom rake or deploy tasks. Putting this into migration files mixes your database schema specification with your data specification and can lead to conflicts when running migration files.
Just stumbled across this post, that was long ago and didn't see the answer I was expecting.
rake db:schema:load is great for the first time you put a system in production. After that you should run migrations normally.
This also helps you cleaning your migrations whenever you like, since the schema has all the information to put other machines in production even when you cleaned up your migrations.
Migrations lets you add data to the db too. but db:schema:load only loads the schema .
Because migrations can be rolled back, and provide additional functionality. For example, if you need to modify some data as part of a schema change then you'll need to do that as a migration.
As a user of other ORM's, it always seemed strange to me that Rails didn't have a 'sync and update' feature. ie, by using the schema file (which represents the entire, up-to-date schema), go through the existing DB structure and add/remove tables, columns, indexes as required.
To me this would be a lot more robust, even if possibly a little slower.
I have already posted as a comment, but feels it is better to put the comments of the db/schema.rb file here:
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
Actually, my experience is that it is better to put the migration files in git and not the schema.rb file...
rake db:migrate setup the tables in the database. When you run the migration command, it will look in db/migrate/ for any ruby files and execute them starting with the oldest. There is a timestamp at the beginning of each migration filename.
Unlike rake db:migrate that runs migrations that have not run yet, rake db:schema:load loads the schema that is already generated in db/schema.rbinto the database.
You can find out more about rake database commands here.
So schema:load takes the currently configured schema, derives the associated queries to match, and runs them all in one go. It's kind of a one-and-done situation. As you've seen, migrations make changes step-by-step. Loading the schema might make sense when working on a project locally, especially early in the lifetime of a project. But if we were to drop and recreate the production DB each time we do a deployment, we would lose production data each time. That's a no-go. So that's why we use migrations to make the required changes to the existing DB.
So. The deeper into a project you get, the more migrations you'll get stacked up as you make more changes to the DB. And with each migration, those migrations become more and more the source of truth of what's on production - what matters isn't what's in the schema, but what migrations have been run in production. The difference is effectively moot if we have both in sync. But as soon as one goes of out date from the other, you start to have discrepancies. Ideally this would not happen, but we live in the real world, and stuff happens. And if you're using schema:load to set up your DB locally, you might not be getting the actual state of the DB, as it is reflected via the migration history on production.

My rails migrations won't run, and I can't deploy my rails app. How can I start over?

At some point in my rails development I started making database changes (e.g. dropping or altering columns/tables) without using rails migrations. So now I get errors when I try to deploy my rails app from scratch.
blaine#blaine-laptop ~/tmp/rbjacolyte $ rake db:migrate
(in /home/blaine/tmp/rbjacolyte)
== AddHashToTrack: migrating =================================================
-- add_column(:tracks, :hash, :string)
rake aborted!
An error has occurred, all later migrations canceled:
Mysql::Error: Table 'jacolyte_dev_tmp.tracks' doesn't exist: ALTER TABLE `tracks` ADD `hash` varchar(255)
(See full trace by running task with --trace)
How can I sync my production and development environments with migrations after I've mucked it up by using raw SQL? I want to deploy my rails application without database errors, and I don't want to start from scratch.
The data in the production and development environments match, but the migrations fail. I want a way to 'start from scratch.'
Could I simply delete all of the migrations that I have, and then just start using migrations from now on?
The shortcut way: manually add an entry to schema_migrations for a timestamp that represents a baseline. You can add migrations after that and as long as they don't make any bad assumptions about the db schema they should be able to run just fine. You won't be able to migrate backwards, but that's not a huge problem.
The bigger problem is that you won't be able to make a DB from scratch, which gets to be a pain longer term.
The fix for that is to delete all your existing migrations and create a new one that creates the existing schema. Manually delete everything from the schema_migrations table and put in an entry for this one new migration. After that, you can create new migrations that build on this new baseline and they should apply just fine. You should be able to bootstrap new databases in the normal fashion.
As long as your direct SQL is contained in Rails migrations, there's no problem with using it. Just make sure you implement both the #up and #down methods and you should be good. We've actually taken to using raw SQL as a best practice to avoid problems when models are changed later on. Something like
Foo.create(:name => 'bar')
seems innocuous, until the User model is modified to have
validates_presence_of :baz
At which point the new migration will run against an existing database, but that earlier migration that created the table and added the dummy entry will fail because User fails validation. Just using
execute("insert into foos (name) values ('bar')")
will work fine as long as the later migrations properly populate any new columns they add.
Maybe you could just get rid of all your current migrations, and use rake db:schema:dump to create a new schema.rb file, and manually edit your production database to reflect the changes you've made so far?
I like Veeti's suggestion, with a modification: rake db:schema:dump, then move that file to your development machine. Flatten your Rails migrations so far (see this SO thread on that), get rid of most of your migrations, and re-work your migrations to work, given your new schema.
Get this working on your dev machine, commit and deploy.
If the existing production data is compatible with the development database schema, then I would:
Dump the production data to a file using a program such as mysqldump
Drop the production database
Recreate the production database
Run the migrations against the production database, specifying VERSION=0
Import the production data from the file created at step one
If the schemas aren't compatible then you might be able to follow this process but you'll have to edit the SQL in the file created in the first step to take account of the schema differences.

Resources