背景
- 少々古いプロジェクトでPostgresqlの配列型が使われていた。
- ActiveRecord経由であれば取得カラムは自動で配列に変換されるが個別に変換したい場合があった
概要
- Rails側で以下の変換を行いたい
- 半角スペースや改行などの要エスケープ文字がある要素だけダブルクォート囲みされたりしている
- アポストロフィーエス
's
なども少々変換が必要らしい
input | output
--- + ---
{}
| []
{1,2,3}
| [1,2,3]
{赤,青,緑}
| ["赤","青","緑"]
{"徳川 家康",豊臣秀吉,"織田 信長"}
| ["徳川 家康","豊臣秀吉","織田 信長"]
実装
モデルのconcernを追加する形にしてみた
app/models/concerns/varying_array_parsable.rb
module VaryingArrayParsable
extend ActiveSupport::Concern
class VaryingArrayParser
# @see {https://github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb}
# Loads pg_array_parser if available. String parsing can be
# performed quicker by a native extension, which will not create
# a large amount of Ruby objects that will need to be garbage
# collected. pg_array_parser has a C and Java extension
begin
require 'pg_array_parser'
include PgArrayParser
rescue LoadError
require 'active_record/connection_adapters/postgresql/array_parser'
include ActiveRecord::ConnectionAdapters::PostgreSQL::ArrayParser
end
end
module ClassMethods
private
# @param value [String] varying arrayカラムの値
# @return [Array] 型キャスト後の配列
def cast_to_array(value)
@pg_parser ||= VaryingArrayParser.new
@pg_parser.parse_pg_array(value)
end
end
end
使用例
app/models/hoge.rb
class Hoge < ActiveRecord::Base
include VaryingArrayParsable
class << self
# @param str [String]
# @return [Array]
def hogehoge(str)
cast_to_array(str)
end
end
end
まとめ?
-
pgのarray型の文字列→railsの配列 への変換ができるようになった
-
エスケープなどの考慮もされていた
-
postgresqlには
array_to_string
関数やunnest
関数があるのでSQL側でこれを使うのもアリだった -
もっと良い書き方がありそう。ActiveRecordにすでに実装済みのものを真似ているだけなので
参考
- rails4.2がActiveRecordでやってる部分
- pg_array_parseのgem