Set default value for Postgres JSON column in Rails < 4

前端 未结 3 1842
[愿得一人]
[愿得一人] 2020-12-31 04:00

So I\'m starting to use the Postgres JSON datatype, now that there\'s a lot of fun stuff you can do with it. In one of my Rails apps which is not yet Rails 4 (where support

相关标签:
3条回答
  • Code below works for PostgreSQL 9.3.4 and Rails 3.2.17

    class YourModel < ActiveRecord::Base
    ...
      serialize :your_column, JSON
      before_create do
        self.your_column ||= {}
      end
    ...
    end
    

    migration code

    add_column :your_table, :your_column, :json
    execute "ALTER TABLE your_table ALTER COLUMN your_column SET DEFAULT '{}'"
    execute "UPDATE your_table SET your_column = '{}';"
    

    application.rb

    config.active_record.schema_format = :sql
    
    0 讨论(0)
  • 2020-12-31 04:19

    You can basically just do something like this

    create_table :foo do |t|
      t.column :bar, :json, default: []
    end
    
    

    State the default with default: [] or default: {} or any other thing you feel comfortable with.

    Update: Note that this is for Rails 4+

    0 讨论(0)
  • 2020-12-31 04:21

    Although a bit late, this worked for me (requires Postgres >= 9.3):

    create_table :foo do |t|
      t.column :bar, :json
    end
    
    execute "ALTER TABLE foo ALTER COLUMN bar SET DEFAULT '[]'::JSON"
    

    EDIT: this answer used to advocate for to_json('[]'::text) instead of '[]'::JSON - thanks to @Offirmo for the hint.

    The problem with the old method was that it didn't actually define an array or an object as the default value as one would expect, but a scalar (string) that looked like one. Why does that matter?

    Postgres allows three kinds of values to be inserted into JSON columns:

    1. Objects

      INSERT INTO foo (bar) VALUE('{}')

    2. Arrays

      INSERT INTO foo (bar) VALUE('[]')

    3. Scalars

      INSERT INTO foo (bar) VALUE('"string"')

    The problem is that if you mix these three kinds in the same column, you lose the ability to use the JSON operators. If you set a default of '[]' using the previously advocated method and queried for an array element, encountering a single row with a scalar default value would abort the whole query with an error:

    =# SELECT * FROM foo WHERE bar->>1 = 'baz';
    ERROR:  cannot extract element from a scalar
    
    0 讨论(0)
提交回复
热议问题