Rails を utf8mb4 で動かす

絵文字などを格納できるようにするため、MySQL の encoding を utf8mb4 にすると、1文字が最大 4バイトになる。すると、primary key と unique key として使うカラムが、InnoDB の最大長 767バイトを超えるために、 ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes というエラーが発生する。

それを乗り越えるための手順は以下の通り。

1) まず、my.cnf に以下を追加して restart させる。

character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci

innodb_file_per_table = 1 innodb_file_format = Barracuda innodb_large_prefix </code>

innodb_large_prefix が、767バイトを超えるキーを使うための設定。

collation として utf8mb4_unicode_ci と utf8mb4_general_ci の 2つが考えられるが、ここでは unicode_ci を選んだ。文字列の比較処理が拡張されていて、半角全角を同一とみなしてくれるなどの利点がある。その一方で、濁点などを区別しないという問題もある。

2) 次に、テーブルの ROW_FORMAT を変更する。Dynamic か Compressed にしないと、 innodb_large_prefix が効かない。

現状の ROW_FORMAT を確認すると、全部デフォルトの Compact になっている。 mysql> select row_format from information_schema.tables where table_schema='データベース名';

そこで、ROW_FORMAT を Dynamic に変更する。 mysql> ALTER TABLE テーブル名 ROW_FORMAT=DYNAMIC;

3) 新規に migration で作成されるテーブルの ROW_FORMAT を Dynamic にするため、 以下のコードを追加する(http://qiita.com/kamipo/items/101aaf8159cf1470d823)。 config/initializers/ar_innodb_row_format.rb

ActiveSupport.on_load :active_record do module ActiveRecord::ConnectionAdapters

class AbstractMysqlAdapter
  def create_table_with_innodb_row_format(table_name, options = {})
    table_options = options.reverse_merge(:options => 'ENGINE=InnoDB ROW_FORMAT=DYNAMIC')
    create_table_without_innodb_row_format(table_name, table_options) do |td|
      yield td if block_given?
    end
  end
  alias_method_chain :create_table, :innodb_row_format
end

end end </code>

4) 既存のテーブルのエンコーディングを変換する ALTER TABLE テーブル名 CONVERT TO CHARACTER SET utf8mb4;

参考 http://qiita.com/kamipo/items/101aaf8159cf1470d823 http://blog.kamipo.net/entry/2012/11/13/102024

リツイートしたユーザーの一覧を ruby で取得する

require 'rubygems' require 'twitter'

client = Twitter::REST::Client.new do |config| config.consumer_key = ‘………’ config.consumer_secret = ‘………’ config.access_token = ‘………’ config.access_token_secret = ‘………’ end

#

指定された Tweet にリツイートしたユーザー一覧を得る

ただし、Twitter API の制限により、最大で100件まで

# tweet = client.status(489034564640063492) puts tweet.text retweets = client.retweets(tweet, count: 100) retweets.each do |retweet| puts retweet.user.screen_name end </code>

sudo でユーザのPATHが引き継がれないとき - secure_path, env_keep

CentOS 6.5 で sudo コマンドを使ったとき、command not found になりました。その一般ユーザのパスにも、root ユーザのパスにも含まれているコマンドなのに。secure_path という機能で、sudo 時のパスを /etc/sudoers に明示されたパスに限定しているためです。

$ sudo bash -c 'echo $PATH' /sbin:/bin:/usr/sbin:/usr/bin

visudo コマンドで /etc/sudoers の env_keep に PATH を追加して、secure_path を無効にすればユーザのパスが効くようになります。

Defaults env_reset Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS" Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE" Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES" Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE" Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY" Defaults env_keep += "PATH" ←追加

#

Adding HOME to env_keep may enable a user to run unrestricted

commands via sudo.

#

Defaults env_keep += “HOME”

#Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin ← コメントアウト </code>

PHPのファイルからBOMを削除する

翻訳会社さんが英中韓に翻訳してくれたPHPのビュー部分のソースコードにBOMが付いていました。BOM というのは byte order mark の略で、ユニコードで記述されたファイルのエンディアンを識別するための目印です。これがファイルの先頭に付いているものをBOMあり、付いていないものをBOMなしと呼びます。

普段はBOMの有無など気にすることはないのですが、このビューファイルを使うと、画面上に不可解な空白が発生して、レイアウトが多少崩れるのです。原因を追ううちに、BOMを削ると正常に表示できることがわかりました。

調べてみると、PHP と BOM との相性はよくありません。例えば、header() や session_start() 関数を使う場合、BOMありのPHPファイルだと、HTTP のヘッダ部分が出力される前にBOMが出力されます。ヘッダ以外のものを出力した後にヘッダを出力することはHTTP上できないので、エラーになります。

BOMそのものは U+FEFF のユニコードキャラクタです。UTF-8の場合、ファイルの先頭3バイトが 0xEF, 0xBB, 0xBF にエンコーディングされます。

では、これをどう取り除くか。

$ sed -e '1s/^\xef\xbb\xbf//' text.txt

このsed版が一番短くて美しいでしょうか。

$ awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' text.txt

今回はこれを使いました。NRは行番号ですね。

$ tail --bytes=+4 text.txt

強制的に先頭3バイトを取り除くので、確実にBOMが付いていることがわかっているUTF-8ファイルのみ利用可能です。

$ ruby -e 'data = File.read(ARGV.first).sub(/\A\xef\xbb\xbf/,""); File.open(ARGV.first, "w") { |f| f.write data }' /path/to/file

指定したファイルをそのまま変換可能なことがウリです。が、こんな長いコード、打ちたくありません。

参考 http://www.linuxask.com/questions/how-to-remove-bom-from-utf-8 http://www.linuxask.com/questions/how-to-remove-bom-from-utf-8-using-sed

#1548 - Cannot load from mysql.proc. The table is probably corrupted

MySQL のテーブルが壊れている、という意味の、初めて見るエラーメッセージに遭遇しました。 #1548 - Cannot load from mysql.proc. The table is probably corrupted

でも、check table しても問題はなし。 mysql> check table mysql.proc extended; +------------+-------+----------+----------+ | Table | Op | Msg_type | Msg_text | +------------+-------+----------+----------+ | mysql.proc | check | status | OK | +------------+-------+----------+----------+ 1 row in set (0.00 sec)

念のためDBをダンプして、drop & create しても変化なし。こんなときは mysql_upgrade すればいいらしい。テーブルの構造や存在などの整合性を正してくれるとのこと。

正確には、このコマンドは「examines all tables in all databases for incompatibilities with the current version of MySQL Server」、つまり、MySQLサーバーのバージョンとデータとの不整合を正してくれる。「should be executed each time you upgrade MySQL」なので、本当は yum update で MySQl がバージョンアップされたときにやっておくべきなのでしょう(え、自動でやってくれないの?)。

mysql_upgrade

Looking for ‘mysql’ as: mysql Looking for ‘mysqlcheck’ as: mysqlcheck FATAL ERROR: Upgrade failed </code>

あ、失敗した。ユーザー名とパスワードが必要らしい。

mysql_upgrade -u root -p

Enter password: Looking for ‘mysql’ as: mysql Looking for ‘mysqlcheck’ as: mysqlcheck Running ‘mysqlcheck with default connection arguments Running ‘mysqlcheck with default connection arguments 〜 テーブル名がずらずら 〜 </code>