无法在postgresql(rails)中的json字段中存储数组,无法将数组转换为json

时间:2013-06-29 21:50:27

标签: ruby-on-rails ruby ruby-on-rails-4 postgresql-9.2 rails-postgresql

这是我运行db:migrate

时遇到的错误
rake aborted!
can't cast Array to json

这是我的表

  class CreateTrips < ActiveRecord::Migration

          def change
            create_table :trips do |t|

              t.json :flights
              t.timestamps
            end
          end 
        end

这是在我的seeds.rb文件

flights = [{
    depart_time_hour: 600,
    arrive_time_hour: 700,

    passengers: [
        {
            user_id: 1,
            request: true    
        }
    ]
}]

trip = Trip.create(
  {
    name: 'Flight',

    flights: flights.to_json 
  }
)

出于某种原因,我不能这样做。如果我这样做。

trip = Trip.create(
      {
        name: 'Flight',
        flights: { flights: flights.to_json }
      }
    )

有效。我不想这样,因为现在我必须使用trip.flights.flights访问json数组。不是我想要的行为。

1 个答案:

答案 0 :(得分:7)

执行摘要:这是一个已知的issue,并在此pull request中解决,在撰写本文时正在等待合并。

长版:

好吧,基于Array / Hash,我可以看到它为什么以及如何失败/成功。这是进行类型转换的Rails方法(来自quoting.rb),它显然不支持从Ruby Array到Postgres json的转换支持从Hash投射。另外,我在此方法的开头添加了一些调试代码,发现如果使用flightsflights.to_json作为值,则无关紧要,因为后者转换为前者为这个铸造的目的。我将进行更多挖掘,因为使用psql将flights.to_json的值插入到json列中没有问题。

    def type_cast(value, column, array_member = false)
      return super(value, column) unless column

      case value
      when Range
        return super(value, column) unless /range$/ =~ column.sql_type
        PostgreSQLColumn.range_to_string(value)
      when NilClass
        if column.array && array_member
          'NULL'
        elsif column.array
          value
        else
          super(value, column)
        end
      when Array
        case column.sql_type
        when 'point' then PostgreSQLColumn.point_to_string(value)
        else
          return super(value, column) unless column.array
          PostgreSQLColumn.array_to_string(value, column, self)
        end
      when String
        return super(value, column) unless 'bytea' == column.sql_type
        { :value => value, :format => 1 }
      when Hash
        case column.sql_type
        when 'hstore' then PostgreSQLColumn.hstore_to_string(value)
        when 'json' then PostgreSQLColumn.json_to_string(value)
        else super(value, column)
        end
      when IPAddr
        return super(value, column) unless ['inet','cidr'].include? column.sql_type
        PostgreSQLColumn.cidr_to_string(value)
      else
        super(value, column)
      end
    end

我继续将以下行添加到Array案例中:

        when 'json' then PostgreSQLColumn.json_to_string(value)

然后更改PostgreSQLColumn.json_to_string(在cast.rb中)以对Array以及Hash类型的参数进行操作,并且我能够让您的用例通过。

此时我还没有检查过是否存在任何问题或提出请求

顺便说一句,我猜你知道你可以使用text字段而不是json字段来解决这个问题。 json提供给你的唯一的东西我知道是否在数据库级别进行验证。如果您认为这很重要,我有兴趣了解原因,因为我已经在网络应用中获得了一些带有json内容的文本字段,而我正在努力工作。我想知道转换它们的好处,如果有的话。