1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
This will create a drop down list with all TzInfo's available Time Zones. The second parameter ('TimeZone.us_zones', in this example) is a 'priority zone'. The purpose is to group the most relevant time zones at the top of the list. The TimeZone class already has a 'us_zones' array of TimeZone instances, but you can use any other group of TimeZones from your current location.
When the user chooses it, you should grab it and save somewhere (the User model, for instance). Then, at each request, when the users is signed on the system, the Application Controller's before_filter will set the singleton 'Time.zone', as we've seen before.
And that's it for Time support. This opens up lots of possibilities and future enhancements, but for now it is good to know that all the mess of 1 separated gem, 2 different plugins and one incomplete Time-alternative class are gone for a more consistent and stand-alone approach. To know more watch "RailsCasts":http://railscasts.com/episodes/106, "Ryan Daigle":http://ryandaigle.com/articles/2008/1/25/what-s-new-in-edge-rails-easier-timezones and "Geoff Buesing":http://mad.ly/2008/04/09/rails-21-time-zone-support-an-overview/.
h2. "Sexier" Migrations
This is not the official name, but Migrations finally received some more love. At this day and age, with bigger projects being done, the original Migrations had to evolve. I faced this problem a while back and the solution I found that was most reasonable was Revolution Health's "Enhanced Migration":http://revolutiononrails.blogspot.com/2007/11/enhanced-migrations-v120.html. Several others attempted to solve this puzzle but this was still the least convoluted alternative.
_"But, what's the issue?"_ you might ask. Well, let me describe a hypothetical scenario.
* Developer A starts a new Rails projects and creates a few migrations. As you well known, they're gonna be incrementally labeled as 1, 2, etc. So he creates migrations up until 4 and then commits the source code back to the central repository (Subversion or what have you).
* Developer B checks out the code and starts to collaborate on the project. He needs 2 new models so the 'script/generate migration' is going to create migrations 5 and 6.
* At the same time, Developer A keeps coding and he needs to create 3 other models. Remember that at this point in time, his machine only has migrations 1 up to 4, as Developer B still didn't commit his work. So, Developer A will generate migrations 5, 6, and 7.
* Now Developer B is done his initial task and commits his work back to the repository.
* Developer A updates from the repository and receives Developer's B migrations 5 and 6. Now Developer A has two migrations named '5' and two other migrations named '6'. When he runs 'rake db:migrate', Developer's B changes will never be executed because he is already at his own migration 7.
You have several variations to this scenario, but the bottom line is:
* You have more than 1 person working in the same project
* By the very nature of collaborative working, you will necessarily have several overlapping migrations that will either conflict or never run
* Several kinds of nasty non-trivial problems will arise very fast and your productivity will fall down quickly.
What did the guys at Revolution Health did? Instead of incremental integer numbers, they replaced it for *numerical timestamps*. So, an example of an 'enhanced' migration file would be named: "1203964042_Add_foo_column.rb".
This avoids having conflicted identifiers but it didn't solve this scenario:
* Developer A creates 2 migrations at 10AM, runs it and commits right away
* Developer B updates from the repository, creates another 2 migrations at 11AM, runs it and commits right away
* Developer A creates 2 migrations at 12PM, runs it. Only after that he remembers to update and then commit his work back.
See the problem? Because the last 2 migrations Developer A created are more recent than Developer B, even after updating from the repository and running 'rake db:migrate', nothing will happen, because Developer B's migrations are in the past and Revolution Health's plugin only records the timestamp of the last migration file it executed.
So, even though you will avoid the conflicts, you will still have plenty of opportunities to lose migrations and have difficult to find problems later, like a missing column because its migration was never executed.
In Rails 2.1 it registers the whole history of migrations (the old table schema_info was replaced by schema_migrations). In the same scenario as above, it would 'detect' that Developer B's migrations were never executed and then it will try to execute them, even though it is out of order. It works almost all the time because each developer's changes should not be dependent upon each other (unless Developer A's last migration was dropping a table that Developer B's migration tries to operate on, but this is a rare condition).
*Detour:* Actually, this could be a good time to add Restful Authentication to our project. To accomplish that, we will use yet another new feature in Rails 2.1: install a plugin from a Git repository, like this:
<macro:code>
./script/plugin install git://github.com/technoweenie/restful-authentication.git
|