RailsのMigrationでPostgresqlのテーブル&カラムコメントを使う

RailsのMigrationファイルでMySQLのカラムコメントを付加するcolumn_commentプラグインというものがある。
(Postgresqlでも使えるようなパッチもリンク先で紹介されていた)
Rails1系では何度か使っていて非常に便利だったのだが、残念ながらRails2系では使用できなくなっていた。(トランザクション管理の関係?)


しかしRails2系で同じ事を行っている「RailsのMigrationでMySQLのカラムコメントを使う」エントリを発見。
このエントリに触発され、Postgresqlのカラムコメントを使うパッチを書いてみた。

パッチ

これをconfig/initializers/column_comment.rbにでも入れておけば、Migration時にコメントを付加してくれる。

注意点
  • Rails2.3のMigration部分を思い切りコピペして改造しているため、意図しない動きになるかもしれない。
  • create_table, add_tableの場合のみ動作確認。rename_columnするとどうなるか分からない。

 

module ActiveRecord
  module ConnectionAdapters
    class TableDefinition
      attr_accessor :comments

      def column(name, type, options = {})
        column = self[name] || ColumnDefinition.new(@base, name, type)
        column.limit = options[:limit] || native[type.to_sym][:limit] if options[:limit] or native[type.to_sym]
        column.default = options[:default]
        column.null = options[:null]
        @comments ||= {}
        @comments[name] = options[:comment] if options[:comment]
        @columns << column unless @columns.include? column
        self
      end
    end

    module SchemaStatements
      def create_table(table_name, options = {})
        table_definition = TableDefinition.new(self)
        table_definition.primary_key(options[:primary_key] || Base.get_primary_key(table_name)) unless options[:id] == false

        yield table_definition

        if options[:comment]
          table_comment = options[:comment]
          options.delete(:comment)
        end

        if options[:force] && table_exists?(table_name)
          drop_table(table_name, options)
        end

        create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
        create_sql << "#{quote_table_name(table_name)} ("
        create_sql << table_definition.to_sql
        create_sql << ") #{options[:options]}"
        execute create_sql
        table_comment(table_name, table_comment) unless table_comment.blank?
        column_comments({table_name => table_definition.comments}) unless table_definition.comments.blank?
      end

      def column_comments(contents)
        contents.each_pair do |table, cols|
          cols.each_pair do |col, comment|
            column_comment(table, col, comment)
          end
        end
      end

      def table_comment(table_name, comment)
        execute "COMMENT ON TABLE #{table_name} IS #{quote(comment.to_s)}"
      end

      def column_comment(table_name, column_name, comment)
        execute "COMMENT ON COLUMN #{table_name}.#{column_name} IS #{quote(comment.to_s)}"
      end
    end

    class PostgreSQLAdapter < AbstractAdapter
      def add_column(table_name, column_name, type, options = {})
        default = options[:default]
        notnull = options[:null] == false
        comment = options[:comment]
        execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}")
        change_column_default(table_name, column_name, default) if options_include_default?(options)
        change_column_null(table_name, column_name, false, default) if notnull
        column_comment(table_name, column_name, comment) if comment
      end
    end

  end
end

migrationファイル

以下の通り。:commentオプションをつければ良い。

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users, :comment => 'ユーザ' do |t|  # テーブルコメント 
      t.string :name  :comment => '氏名'             # カラムコメント 
      t.string :age   :comment => '年齢'             # カラムコメント 
    end
  end

  def self.down
    drop_table :users
  end
end

こうすることでDB定義がMigrationファイルで一元管理することが出来た。
リバースエンジニアリングするツールでDB定義書を自動生成することも可能だろう。

2009/10/2 追記
id:akmさんが作ったschema_commentsプラグインで同様のことができる模様。 http://github.com/akm/schema_comments