Why are relations between databases not part of the migration file? - ruby-on-rails

I use the migration file to setup the database structure.
That is very convenient as I am not constrained to a specific type of database (mysql, sql,...)
If I want to have relationships between different tables, I have to use the Associations has_to, belongs_to IN THE MODEL FILE.
I don't get this. Now you can't just roll back a migration of the database go on from this point. No, you also have to modify the model file manually.
Why did they choose this design concept?

Migrations are for changing the state of your database, not for altering the behavior of your models.
I don't get this. Now you can't just roll back a migration of the database go on from this point. No, you also have to modify the model file manually.
Of course you do. You have to modify the model/controller/view code to use any migrated changes to the database, associations or otherwise. What's the big deal? How else would you consume the changes you're making to your database, if not through changes to your application code?
Your application code is always going to be tied to the state of the database. Migrations aren't supposed to isolate you from this.

Related

iOS CoreData Migration using Custom Mapping Models with multiple historical database versions

I have an app and many history versions of the database.
Our users are typically "once in a year" users, so this means you can never be sure which version of the database their app is running on.
Now in my new version of the database I need to do some custom migration.
The method I use to do this is described in this tutorial: http://9elements.com/io/index.php/customizing-core-data-migrations/
To summarize: I have to make Custom Mapping Models so that I can write my own migration policies for some fields.
Now when I create a Custom Mapping Model, I have to select a Source "xcdatamodel" and a Destination "xcdatamodel" (where "destination" is te new version of my database).
My question is, if I want to do this custom migration from all possible versions, do I need to create multiple Custom Mapping Models, all with a different source, or is there a smarter way to do this?
Or is CoreData smart enough to recognize this?
The short answer is yes; you need to test every migration from every source model to your current destination model. If that migration requires a custom mapping then you will need to have a mapping for that pair.
Core Data does not understand versions; it only understands source and destination. If there is not a way to get from A to B then it will fail. If it can migrate from A to B automatically and you have the option turned on, then it will. Otherwise a heavy (manual) migration is required.
Keep in mind that heavy migrations are VERY labor intensive and I strictly recommend avoiding them. I have found it is far more efficient to export (for example to JSON) and import the data back in then it is to do a heavy migration.
It is enough to have a consistent sequential series of migration models up to the current version. Core Data is "smart" enough to execute the migrations you tell it to migrate in the given order.

Rails - How to create database tables from models (I have no migration scripts)

I'm a newbie in rails and its a great platform.
I created an application but removed all the migration scripts.
I want to create the database with the tables from my existed models.
I can't find it on the net and I'm sure that might be an option to do that like any other platform (java hibernate, etc)
the command rails generate... only create the table without columns but I have columns in the existed models. so how can I do that?
Thanks!
If you've accidentally scrubbed your models and don't have any migrations, you can still generate a db/schema.rb file by running rake db:migrate and using that instead. It should reflect the current state of your database no matter what you've done to it.
If you create a migration with the important parts of this in it, as you'll notice the format is very similar, you will be able to replicate that configuration on other systems.
This is a bit of a heavy-handed way to do it, though. Each model should have its associated migration. Generally these are never deleted and only modified if strictly necessary, preserving a history of how the schema evolved into its final state.
If I understand your question correctly, there really isn't a way to construct your database tables from your ActiveRecord model classes - it's best to think of ActiveRecord models as more of a mapping between different flavors of relational databases and Ruby objects. In other words, ActiveRecord models abstract away the details of a database in order to become database-independent. They make your database data more easily accessible in Ruby. In doing so, they don't have the power to construct your tables. Think of them as very pretty getters and setters rather than a binding to a database.
This is exactly why migrations exist - they contain the database-specific stuff. They essentially contain the "other half" of your model definition - most of the application level stuff (like relations, which don't exist in, say, MySQL, right? They are an ActiveRecord convention) is defined on your model, but, for example, if you want to have a string on your Foo model, you define that in your migration, and the appropriate getters and setters will be available on your model for you to play with this string.
tl;dr: you need your migrations. The fact that they exist in Rails is an intentional design decision to separate the Ruby half of the models from the database half.

Best Practice for DB Schema in Ruby on Rails

I'm a PHP programmer for over a decade and making the move to RoR. Here is what I'm used to from the PHP world:
Create DB schema in a tool like MySQL WorkBench -- and make fields precisely the size I want without wasting space (e.g. varchar(15) if it's ip_address).
Write models using Datamapper and place those exact field lengths and specifications in there so my app doesn't try to put in any larger values.
In the RoR world from what I've seen over the past two days, this seems to be the flow suggested:
Add fields / schema using the command line which creates a migration script and apparently created large ass fields (e.g. "ip_address string" is probably making the field varchar(255) in the db when I run the migration).
Put in validations during model creation.
Am I missing something here? What's the process in the RoR world for enterprise level applications where you actually want to create a highly customized schema? Do I manually write out migration scripts?
The scaffolding is what you use to get started quickly. But before running the migration, you can edit it and add constraints and specific column lengths.
Validations specified in the model (in the ruby code) does not carry the same level of security as validations /constraints specified on the database. So you still need to define those on the database.
While it is possible to work with Rails without migrations, I would strongly advice against it. In some cases it cannot be avoided (when working with legacy databases for instance).
The biggest advantage of using the migrations is that your database schema, accross different platforms, can be held in sync through different stages. E.g. your development and your production database. When deploying your code, the migrations will take care that the database is migrated correctly.
You can edit the migration scripts before you run the migration in order to customize the fields.
Yes, if you need to tweak the defaults, you edit the migration scripts.
Also note that you don't need to use migrations, they're a "convenience" while iterating through DB development. There's nothing that says you must use them. The active record pattern doesn't rely on how the DB tables/fields/etc. are created or defined.
For example, migrations are useless when dealing with legacy DBs, but you can still write a Rails app around them.

loading seed data for a rails migration

I have an existing database in which I am converting a formerly 'NULL' column to one that has a default value (and populating that with said default value). However, that value is an ID of a record I need to create. If I put this record in db/seeds.rb, it won't run because db/seeds.rb runs after migrations -- but the migration needs seed data. If I leave the record creation in the migration, then I don't get the record if I make a fresh database with db:load. Is there a better way other than duplicating this in both db/seeds.rb and the migration?
Thanks!
While I can understand your desire to stay DRY and not have to write this in both the migration and seeds.rb, I think you should write it in both places. Not just to make it work, but to accomplish different requirements related to your problem.
You need to ensure that your migration can execute properly regardless of external processes. That means you should put any code required within that specific migration. This isn't to accomplish anything besides making sure your migration executes properly. Suppose someone else tries to migrate without knowing you put part of the code in seeds.rb, it would be very difficult for them to figure out what's going on.
You can make db:load work properly by including similar code in seeds.rb. However, you should be evaluating the current state of your database in seeds.rb due to the fact that it runs after the migrations. So you can check to see if the column exists, and what the default value is etc. This means that if the migration ran and took care of everything, seeds.rb doesn't repeat work or modify values inappropriately. However, if the migration did not set these variables as expected, it is able to set the values.
I'd recommend looking at it as two separate issues so you can be more confident of each one executing successfully independent of one another. It also creates better maintainability for understanding by yourself or others of what's happening in the future.
In my opinion you should treat this in both db/seeds.rb and the migration.
The migration is used to get an existing database from an older version to another version while seeds.rb and schema.rb are used for a fresh database with the latest version.

Usefulness of db migrations rollback

Many people talking about db migrations, especially about its rollback possibility.
I doubt, whether it is useful at all, because schema of db and model are tightly connected with application logic (MVC).
Suppose i've done rollback of some migration. And what ? The application will not work, because its logic fully relies on db.
What are the use cases of rollback ability for db migrations ?
Update 1
The main question
Why the rollback is presented as a feature, when i need to change the code ?
I don't create the migrations, like "add_another_field_to_table". Instead, each migration file fully describes each table in DB. When i need to change something in my DB, i just change the migration file, but don't roll it back.
Really, if i rollback the migration, it does't brings me back in time, like a version control does. I have a lot of work, when changes are planned and rollback gives me nothing.
The point of rollback is that you rollback code and DB at the same time. The scenario is you upgrade your code and your DB on your production server, then you find a bug and you really need to go back. So rollback your code and use your down migration to roll back your DB.
What are the point of Up migrations?
You create table structures.
You code round it, it works well.
You put site into production, everyone is happy.
Oh, wait, they want a new feature that involves adding a column to an existing table.
How do you handle this? You have to add a column to your development tables, test code, update live site without forgetting to update live DB at the same time (cos if you do there will be big errors) And also remmember to preserve existing live data. This aspect of DB management can be a real pain without a nice managed solution like rails has.
So ...
Code a one line migration that adds a column
Run migration on dev copy, scehma.rb will update
Code new features, if you need to check DB schema use schema.rb NOT migration files.
Now your ready to release on production ....
Update code on production
Run migrations on production. Rails will automatically work out what needs to be applied and do it for you!
Sure, with you adding one column it's not that confusing to do it yourself.
But what if there were 3 programmers all adding migrations? What if you have many live sites, all at different versions? Is that live site 2 or 17 migrations behind? What do I have to do to get the DB up to the latest code, whilst preserving live data? Can you see how this would very quickly get confusing to deal with?
Rails migrations (and practically every migration system works on the same principles) are designed to make updating DB structures really easy. Well worth using properly.
I've found that rollbacks are only useful if they are done locally, ie while you're working on a new bit of code. Once a migration has been committed into your version control system, if you realise there was a mistake then it doesn't really work to roll back the migration because other developers will have pulled the migration down and run it, so you'd need to tell them to roll back as well - this is too difficult to manage and also makes you look incompetent :)
Better in this situation to just do another migration to fix the problem, then everyone (including your production server) just sticks with the pull & migrate system.
Don't really understand your problem, but i try to explain a bit the rollback.
You do rollback if you want to undo the changes by the respective migration. This means that the database will be modified, and also your schema.rb will be automatically regenerated. When you do this probably you want to remove the referencing code too. For example if you removed a field from the model, probably you don't want to refer to that attribute in your code. If you try to access then will gives you undefined attribute exception. That's it.
Can become a bit cumbersome to rollback for example if you created some model 10 migrations before, and you want to change some fields. It's better to create a new migration and modify there, instead of rolling back to the respective migration.
Update 1
Read your update, and i think yo don't use the main advantage of migrations, the flexibility.
But your solution gives more overview of the database situation. If you like to do that way, I suggest the following steps in order.
Roll back to the respective migration.(rake db:migrate VERSION=XXX, I like better rake db:rollback STEP = 2 for example, rolls back 2 migrations, STEP optional)
Make your changes
Migrate your database to update all the tables, and get to current migration version.(rake db:migrate)
This feature don't affect your models or something, just changes the migration file, regenerates your schema.rb and changes the database structure, nothing else. Can't do code rollback like with version control system, and don't really has sense to do something like that. You have to take care about not using removed fields. Rails has automated mapping between database fields and model attibutes, for example if you have an user_id in your comment table, you can call it as an attribute in your model, comment_instance.user_id.
Consider a scenario where you use capistrano to deploy your site and create timestamped snapshots of each deployment. Using the timestamp on the folder and your migrations, you could identify which versions of the code and schema go hand in hand and perform a rollback.
A git repository would give you similar options.
Of course, the real problem is that once users of a site start adding data, that will potentially get purged too, unless you back it up before a rollback and painstakingly restore it at a later date.
I use migration rollback locally with rake db:migrate:redo while working on migration code and before final commit.

Resources