We all love ActiveRecord migrations and the sexy DSL for declaring fields. OK, I don't know if you do, but I sure do. But life isn't perfect (don't get me started), and there's various details that make using the migration DSL a bit of a pain.
The one thing that has annoyed me for ages is how string (VARCHAR) fields are handled for PostgreSQL. While the standard for SQL requires you specify a limit for the length, PostgreSQL is more flexible. From the PostgreSQL docs at http://www.postgresql.org/docs/current/static/datatype-character.html:
If character varying is used without length specifier, the type accepts strings of any size. The latter is a PostgreSQL extension.
Unless your string field needs a limited length for semantics (like a SSN or ZIP code), it's better not to specify a limit for VARCHAR fields.
The problem is that ActiveRecord follows the SQL standard and insists on a limit of 255 if none is specified. So if you define a field thusly:
create_table "users" do |t| t.string "name" end
That is equivalent to
CREATE TABLE users ( name character varying(255) );
OK, you think, I know what to do. I'll specify a limit of nil!
create_table "users" do |t| t.string "name", :limit => nil end
But no, that doesn't work. A nil limit is ignored and the default 255 is used anyway. There's a tiny patch for that I might pursue, but in the mean time there is a pretty simple workaround.
Drop these lines into application.rb (assuming you are on Rails 3.0 or greater) within the Application class definition:
initializer "postgresql.no_default_string_limit" do ActiveSupport.on_load(:active_record) do ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:string].delete(:limit) end end
That removes the default limit for string fields. Problem solved. And that's even nicer than saying
:limit => nil anyway.
And also, this is pretty cool. I got to use one of those fancy ActiveSupport initializer hooks. Let me explain in case you haven't
used one before. What that's doing is waiting until the
active_record library is done loading, then running some code to
act on the initialized library. That ensures that the default value is removed after it's been created, but before anyone gets
a chance to use it.