Edited at

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

More than 3 years have passed since last update.

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にてリリースしているのでこちらをお使い頂くのがよいかと思います。