読者です 読者をやめる 読者になる 読者になる

Ruby on Rails 2.3 + PostgreSQL 9.6.1 は一部の機能が動かない

ある仕事でRuby on Rails 2.3をメンテナンスしていますが、PostgreSQL のバージョンを 9.2 から 9.6.1 にアップデートする事になったのですが、一部の機能(Active Scaffold 覚えてますか?)が動きませんでした。

f:id:yuum3:20170115150154p:plain

ソースを調べていくと、ActiveRecord の connection.table_exists?メソッドがいつでも falseを返しています。 ActiveRecord2.3のtable_exists?メソッドのソースを調べていくと PostgreSQLの SHOW search_path コマンドの戻り値を使っているのですが

PostgreSQLバージョン 戻り値
9.6より前 "$user",public
9.6.1 "$user", public

違いが判りますか? 9.6.1 は , の後ろに スペースが入っています。 ActiveRecord2.3では split(/,/)でパースしているので9.6.1では " public" が戻り、この値で pg_tablesテーブルの schemaname を検索するぐるのでテーブルが全くみつからなくなります。

そういうわけで、Ruby on Rails 2.3 はもうメンテされていないのでモンキーパッチを書いて対応しました。 ちなみにRuby on Rails4, 5 のソースを見てみましたが SHOW search_path ではなく current_schema() 関数を使っているのでこの問題ないです。

module ActiveRecord
  module ConnectionAdapters
    class PostgreSQLAdapter < AbstractAdapter

      def tables(name = nil)
        schemas = schema_search_path.split(/\s*,\s*/).map { |p| quote(p) }.join(',')
        query(<<-SQL, name).map { |row| row[0] }
          SELECT tablename
            FROM pg_tables
           WHERE schemaname IN (#{schemas})
        SQL
      end
    end
  end
end