LoginSignup
55
52

More than 5 years have passed since last update.

ActiveRecordでカラム毎にcharsetとcollationを指定する

Last updated at Posted at 2013-11-20

MySQLではカラム毎にcharsetとcollationを指定できるので、こういうMigrationファイルがあったときに

db/migrate/20131120120000_create_users.rb
class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email, charset: 'ascii', collation: 'ascii_bin', null: false
      t.string :password_digest, charset: 'ascii', collation: 'ascii_bin'
      t.timestamps
    end

    add_index :users, :email, name: "idx_email", unique: true
  end
end

こういうテーブルをCREATEしてほしい。

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
  `password_digest` varchar(255) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC

ちょっと長いけど以下のコードをてきとうにRailsで読み込まれるところにコピペしてもらうといい感じに動くのではないかと思います。

config/initializers/activerecord.rb
ActiveSupport.on_load :active_record do

require 'active_record/connection_adapters/abstract_mysql_adapter'

module ActiveRecord::ConnectionAdapters
  class AbstractMysqlAdapter
    class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
      attr_accessor :charset, :collation
    end

    class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
      def new_column_definition(name, type, options) # :nodoc:
        column = super
        column.charset = options[:charset]
        column.collation = options[:collation]
        column
      end

      private

      def create_column_definition(name, type)
        ColumnDefinition.new(name, type)
      end
    end

    class SchemaCreation < AbstractAdapter::SchemaCreation
      def column_options(o)
        column_options = super
        column_options[:charset] = o.charset
        column_options[:collation] = o.collation
        column_options
      end

      def add_column_options!(sql, options)
        if options[:charset]
          sql << " CHARACTER SET #{options[:charset]}"
        end
        if options[:collation]
          sql << " COLLATE #{options[:collation]}"
        end
        super
      end
    end

    def prepare_column_options(column, types)
      spec = super
      spec[:collation] = column.collation.inspect if column.collation && column.collation != collation
      spec
    end

    def migration_keys
      super + [:collation]
    end

    private

    def create_table_definition(name, temporary = false, options = nil, as = nil)
      TableDefinition.new(native_database_types, name, temporary, options, as)
    end
  end
end

end

Rails 4.0.0以降で動きます。

【追記】上記のパッチはactiverecord-mysql-awesomeにてリリースしているのでこちらをお使い頂くのがよいかと思います。

55
52
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
55
52