Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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"]]

関連

koshigoe
feedforce
『「働く」を豊かにする。』というミッションを掲げ、企業向けネットサービスを開発・提供しています。
https://www.feedforce.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away