LoginSignup
0
1

More than 5 years have passed since last update.

Rails 5 で PostgreSQL の Array 型を含むモデルを to_json すると Encoding::UndefinedConversionError 例外になる件

Last updated at Posted at 2016-07-20

TL;DR

  • Array 型の要素が全て ASCII のみの文字列なら問題は無い
  • find しただけのインスタンスなら非 ASCII 文字を含んでいても問題は無い
  • save した後のインスタンスをエンコーディングが必要な処理に通すと問題発生(Encoding::UndefinedConversionError)
  • 未解決
    • save 後に reload すれば回避できる、という逃げ道はあるけど……
    • そもそも Array 型を使わなければ良い、という話ではあるけれど……

再現

$ rails new test-pg-array -d postgresql --api -T -C
$ cd test-pg-array
$ rails g model PgArray data:text
$ vi db/migrate/20160720125308_create_pg_arrays.rb
$ cat db/migrate/20160720125308_create_pg_arrays.rb
class CreatePgArrays < ActiveRecord::Migration[5.0]
  def change
    create_table :pg_arrays do |t|
      t.text :data, array: true

      t.timestamps
    end
  end
end
$ rails db:create db:migrate
$ rails r 'PgArray.create!(data: %w(a あ)).to_json'
/Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/core_ext/object/json.rb:34:in `encode': "\xE3" from ASCII-8BIT to UTF-8 (Encoding::UndefinedConversionError)
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/core_ext/object/json.rb:34:in `to_json'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/core_ext/object/json.rb:34:in `to_json'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/json/encoding.rb:55:in `to_json'
        from /Users/koshigoe/.rbenv/versions/2.3.1/lib/ruby/2.3.0/json/common.rb:224:in `generate'
        from /Users/koshigoe/.rbenv/versions/2.3.1/lib/ruby/2.3.0/json/common.rb:224:in `generate'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/json/encoding.rb:99:in `stringify'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/json/encoding.rb:33:in `encode'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/json/encoding.rb:20:in `encode'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/core_ext/object/json.rb:37:in `to_json'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/railties-5.0.0/lib/rails/commands/runner.rb:63:in `<top (required)>'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/railties-5.0.0/lib/rails/commands/runner.rb:63:in `eval'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/railties-5.0.0/lib/rails/commands/runner.rb:63:in `<top (required)>'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:293:in `require'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:293:in `block in require'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:259:in `load_dependency'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:293:in `require'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:138:in `require_command!'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:104:in `runner'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/railties-5.0.0/lib/rails/commands.rb:18:in `<top (required)>'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:293:in `require'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:293:in `block in require'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:259:in `load_dependency'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:293:in `require'
        from /Users/koshigoe/tmp/test-pg-array/bin/rails:9:in `<top (required)>'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:287:in `load'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:287:in `block in load'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:259:in `load_dependency'
        from /Users/koshigoe/tmp/test-pg-array/vendor/bundle/gems/activesupport-5.0.0/lib/active_support/dependencies.rb:287:in `load'
        from /Users/koshigoe/.rbenv/versions/2.3.1/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from /Users/koshigoe/.rbenv/versions/2.3.1/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from -e:1:in `<main>'
$ rails r 'puts PgArray.first.to_json'
{"id":1,"data":["a","あ"],"created_at":"2016-07-20T12:55:46.951Z","updated_at":"2016-07-20T12:55:46.951Z"}
$ rails r 'puts PgArray.create!(data: %w(a あ)).reload.to_json'
{"id":3,"data":["a","あ"],"created_at":"2016-07-20T13:17:38.298Z","updated_at":"2016-07-20T13:17:38.298Z"}

メモ

pg gem を使った Array のエンコード、デコードの挙動確認

(001): >> encoder = PG::TextEncoder::Array.new(name: 'text[]', delimiter: ',')
=> #<PG::TextEncoder::Array:0x007feb5d0fd368 "text[]"  elements_type=nil needs quotation>
(002): >> encoded = encoder.encode([%w(a あ)])
=> "{{a,\xE3\x81\x82}}"
(003): >> decoder = PG::TextDecoder::Array.new(name: 'text[]', delimiter: ',')
=> #<PG::TextDecoder::Array:0x007feb5c277848 "text[]"  elements_type=nil needs quotation>
(004): >> decoded = decoder.decode(encoded)
=> [["a", "\xE3\x81\x82"]]

関連

0
1
0

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
0
1