ActiveRecord migrations don't allow you to control column order when adding or changing columns. You can always just
execute "ALTER TABLE ..."
If you're willing to give up vendor neutrality, you can have the feature in pretty-Ruby-migration syntax with a small effort. Here's an implementation for MySQL that adds options :first
and :after
to add_column
and change_column
.
ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
def add_column_options!(sql, options)
super
if options[:after]
sql << " AFTER #{quote_column_name(options[:after])}"
elsif options[:first]
sql << " FIRST"
end
end
end
(It's also available in this gist if you'd like to suggest a cleaner way.)
With that in place,
a.add_column :foos, :bar, :string, :after => :baz
will execute
ALTER TABLE `foos` ADD `bar` varchar(255) AFTER `baz`
and
a.add_column :foos, :bar, :string, :first => true
will execute
ALTER TABLE `foos` ADD `bar` varchar(255) FIRST
Love that Ruby!
Now this is a monkey-patch, but as monkey-patches go it's pretty innocuous. Rather than redefining a method that's already implemented in MysqlAdapter (and as with many monkey-patches copy-pasting the existing implementation so we can modify it), we're defining a new override of a method (albeit undocumented) inherited from the SchemaStatements module (via AbstractAdapter). If you wanted to, you could subclass MysqlAdapter and then configure Rails to use your own adapter, but I suspect that would be more expensive to own than just adding this method to MysqlAdapter. (Beware: there are many useful Rails-provided rake tasks that look at your adapter string to decide whether to be useful or to spit in your face.)