Best way to modify DB schema in development - ruby-on-rails

Currently i'm using this:
edit creation migrate
rake db:drop
rake db:migrate
rake db:seed
but I often can see making migrations for every added or edited column and so on.
I think my way is better because its much cleaner and faster to migrate to production environment (one sql for one table). Are there any disadvantages of using my method?
What do you think?
EDIT:
Just to be clear: i'm talking about stage BEFORE any production, when I'm coding on my own PC and even don't think about production yet.

Incremental migrations are definitely needed in production, where you can't get away with dropping entire databases. Using them in development as well helps you to ensure that they're correct.

Understand what you are trying to achieve here but how you're going about it is very wrong.
Your development environment should be as close to your production environment as possible.
Could run into allsorts of problems.
What happens when you need to replicate the production environment on dev?
What happens when you "forget" to add/take-away something on prod that you have done using a migration that is lost?
For dev, maybe a better command would be rake db:rolback, which rolls back the previous migration if you need to edit it for typo or something.
Just out of curosity - why not use rake db:reset instead of the three individual rake tasks?

Related

rake db:migrate doesn't generate table in postgresql

I've been having a problem which doesn't seem uncommon (I've read a lot of stack overflow pages in the last 2 days) but every solution I've read hasn't worked for me.
I've been following this video tutorial
At 6:42 the tutor shows the tables in postgresql and mine don't show up.
When I try rake db:migrate the files migrate no problem. rake doesn't throw up any errors, the relevant .rb files are created in the models folder, my schema.rb looks right. It seems postgresql just isn't reading my schema file.
My problem sounds identical to
rake db:migrate doesn't seem to work in production
However typing rake db:migrate RAILS_ENV=production doesn't work. (I've tried this a few times after other rake commands like rake db:rollback STEP=3 in the past few days because I was paranoid it was the solution, this person on ruby forum, has the same problem and is offered the same answer).
This is my first attempt at programming anything and I'm loving the tutorial (and the learning curve this problem has turned out to be) Asking here is pretty much my last resort because I've tried everything I can understand online as a possible solution so please help me! Thanks a lot in advance
There is quite a bit of confusion going on here:
Migrations
Migrations are a convenient way to alter your database schema over
time in a consistent and easy way. They use a Ruby DSL so that you
don't have to write SQL by hand, allowing your schema and changes to
be database independent.
Postgres does not read your schema file or migrations - rather migrations run SQL queries against your database. In this case a CREATE TABLE ... query will be run when the migration is run.
Migrations are basically a more maintainable and sane way of doing what was classically done by opening a DB console and running SQL queries.
config/schema.rb is not actually used by the database or ActiveRecord - rather its created when you run migrations as a snapshot of what the database schema should look like. Its just a developer convenience. ActiveRecord gets its mappings by querying the database schema.
Migrations and generators
Migrations do not create model files either - those are generators such as:
rails g model Dude abides:boolean
Which creates a CreateDudes migration and a model at app/models/dude.rb.
In fact migrations are just concerned about altering the DB schema and don't care if the model file exists or not - the models is not actually used until you query the database for records.
ENV vars
RAILS_ENV=production sets a environmental variable.
rake db:migrate RAILS_ENV=test
Is the documented way to run a migration in a different environment. Some obscure shells require the ENV var to prefix the command.
However - if you are running a production server you should set the RAILS_ENV env var permanently - not on invocation! This prevents embarrassing misstakes when someone expected you to have configured the server properly and just ran rails s when restarting the server. See the documentation for your server OS on how to set env vars.
If you are still running the migration and do not see the expected results you most likely have not configured config/database.yml properly - the migrations are running. But not against the database you would expect.
http://guides.rubyonrails.org/active_record_migrations.html

We have lots of database migration files - should we keep them?

We have around 100 database migration files. Many of them make schema changes which are irreversible. There are also later migrations which change or remove tables which were created in earlier migrations.
We are creating new databases straight from the schema.rb file, so we were wondering if there is any reason to keep the full set of migrations?
We would create a new migration which is based on our existing schema.rb.
Yes, what you're proposing is considered a best practice.
I've done this with my old apps several times. You'll want to back your migrations up somewhere until you're satisfied all is well, of course, this is an important part of application maintenance - if you have a lot of old migrations, it can take forever to do a db:reset or to get a new development environment running.
I use rake db:setup and rake db:reset exclusively (never rake db:migrate) to install a new database, on a production server or on a new development machine. Those commands already use the schema.rb or structure.sql to recreate the database.
That said, it is really easy to make a copy of schema.rb, use that as a new starting-point and delete all the old migrations.
I prefer to keep my migrations for historic purposes, but that is a matter of taste.

Rake in Rails: should I be using db:reset?

I'm a little confused by the intended use of the default Rails Rake tasks, and would like advice on whether I should be using db:reset or writing a custom Rake task. Nothing clever, just daily housekeeping, and I may well be missing an obvious doc as I'm new to Rails.
My problem: I want to throw away my database and run from a completely clean setup, in order that I can be sure the database contains known data only. This is useful for demo prep, for debugging, and for making sure Jenkins is comparing like-with-like in tests.
Currently, I'm writing this:
bin/rake db:drop:all db:create:all db:migrate db:seed db:test:prepare
This is a lot to type, but leaves seed data only in both dev and test databases. I am unsure how this differs from db:reset, which would be more convenient to type.
Should I use db:reset or write a custom db:from_scratch task?
You should be using:
rake db:reset
This will drop the database, recreate it and load the current schema into it.
For a full list of rake db tasks:
rake --describe db
If your requirements change then it would be better to write a custom rake task, where you can apply your own customisation.
If you're not sure what a rake task does, then I would suggest not using it. In this case, you're probably ok, however db:reset is not the equivalent to what you are doing above. db:reset recreates the database from scheme.rb, this may be different as you could have written migrations that have not yet been run.
I would suggest that you use a custom rake task, you can then modify it to fit your exact purposes, especially if you want to perform other tasks as well (for example tagging in git)
What you are trying to achieve in your the tasks you are running through rake is setting both the test and the development databases. rake db:reset will just do it for your current environment db according to the schema.rb and then load the seeds data into the db. The schema.rb in general is never edited, its for a know-only/refer-only purpose, however some people do tend have different schema.rb which might create a problem :(. What sounds better to me is if you need to set both your development and test database, then run your migrations for the dev environment and use the schema.rb to create the test environment db. I would definitely suggest you to get a second opinion from some Rails guru though to find out a real perfect way to achieve what you want.
rake db:reset
This will drop the database, recreate it and load the current schema into it.
rake db:reset will run rake db:seed
Example :
if you have seed file that you wrote after you ran your migration , it will run that too.

Way to "flatten" Rails migrations?

I'm working on deploying my first Rails application right now, and somewhere along the way, I botched a migration. When I try to push my application to the production server and run rake db:migrate, it fails somewhere with an error.
Now, I am way too lazy to work through my migrations individually to find out what went wrong, so I'm trying to avoid doing that. Given that my current development database works just fine, is there a way to "flatten" the current schema into a single, comprehensive migration?
I understand that this is sloppy, and I understand that I likely did a dumb thing to break the migration chain in the first place. (I probably edited the database schema directly somewhere, which I now understand is a no-no.) This is a pretty small project though, and I'm essentially the only developer involved, so I'm comfortable sweeping this issue under the rug if possible.
Is there a way to do that?
Thanks for lending your expertise.
This is what the db/schema.rb file is for. If you've only got structural changes in your migrations you will be able to run rake db:schema:load rather than running rake db:migrate to get the absolute structure for your tables.
If you edited the schema directly you will need to run:
rake db:schema:dump
This will take whatever is in the database and create a schema.rb file. Then you can run rake db:schema:load anytime you want. However it will mean that your migrations are still bad. You could delete all of them and recreate them from the schema.rb file.

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.

Resources