And Ruby is a nice language. I use it for everything for which I would have used Perl earlier, but also for a lot more serious programming than that. Earlier this year, the RedDotRubyConf came to Singapore, where I'm living now. That was a great opportunity to catch up on what's going on around Ruby, with all the big names from the Ruby world making their appearances as speakers.
I even made second place in the Ruby programming competition.
So now I'm looking at Rails more seriously. I worked a lot with Java frameworks like Wicket in the past. I still like the component-based approach, and I'm missing that in Rails. But it's absolutely easier to develop web-sites in Rails faster, and they are still structured enough to be maintainable as well, unlike many other page-based web development frameworks.
As I am trying to develop a site for myself, I ran into some issues with migrations. It's a site to display some holidays pictures in a way that I can't do with any existing apps that I know of, and it's a nice exercise anyway. I have my product owner who tells me what features she likes in it and I program them :-)
The issue occurs when I create a migration to add a 'references'-type column to a model. I forgot to add a 'main photo' field to my Photoset model, so I'm adding that with a migration:
rails generate migration add_main_photo_to_photoset main_photo:references
The migration looks like this:
class AddMainPhotoToPhotoset < ActiveRecord::Migration
def change
add_column :photosets, :main_photo, :references
end
end
Now when I try to run that, I get an error:
$ rake db:migrate
== AddMainPhotoToPhotoset: migrating =========================================
-- add_column(:photosets, :main_photo, :references)
rake aborted!
An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: near "references": syntax error: ALTER TABLE "photosets" ADD "main_photo" references
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
== AddMainPhotoToPhotoset: migrating =========================================
-- add_column(:photosets, :main_photo, :references)
rake aborted!
An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: near "references": syntax error: ALTER TABLE "photosets" ADD "main_photo" references
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
I could change the migration to do that, and it would work. But wait - when I create a model initially, I am free to use the type 'references' - so why can't I do that when I add a new column later?
When I created the Photoset model, the migration looked like this:
$ rails generate model photoset name:string region:references
class CreatePhotosets < ActiveRecord::Migration
def change
create_table :photosets do |t|
t.string :name
t.references :region
t.timestamps
end
add_index :photosets, :region_id
end
end
A photoset belongs to a region of the world. This works.
So if I change the migration that adds a main_photo column to this, it also works:
class AddMainPhotoToPhotoset < ActiveRecord::Migration
def change
change_table :photosets do |t|
t.references :main_photo
end
end
end
That looks nice and clean and it looks just like the migration that created the model. There is value in consistency.
So now I know how to fix this. I'm only left wondering - am I missing something? Why didn't wasn't the migration created like this in the first place?
If this is something that still needs to be updated in the rails code, that's fine. I don't feel ready yet to dive into the framework's code and contribute to it, but I can do this by hand right now.
As long as there is no underlying reason why this change_table approach is a bad idea, that is.