【问题标题】:Set default value for Postgres JSON column in Rails < 4在 Rails < 4 中为 Postgres JSON 列设置默认值
【发布时间】:2013-11-11 23:25:46
【问题描述】:

所以我开始使用 Postgres JSON 数据类型,现在是 there's a lot of fun stuff you can do with it。 在我的一个 Rails 应用程序中,它还不是 Rails 4(support for Postgres JSON has been added),我添加了一个 JSON 列,如下所示:

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

但我不知道如何为该列设置默认值。 我尝试了所有变体,例如{}'{}''{}'::json'[]'::json 等,但是当迁移运行时我得到一个错误,或者它根本不起作用,这意味着迁移运行但是,当我创建一个新的Foobarnil

【问题讨论】:

  • 您是否尝试过在模型中手动设置默认值? AR 通常会破坏或忽略它不理解的默认值。
  • 是的,现在我使用after_initialize 回调,但我通常不喜欢那些...
  • 试试"",我相信这就是hstore用来表示空哈希的原因
  • -- add_column(:foo, :bar, :json, {:default=&gt;""}) rake aborted! An error has occurred, this and all later migrations canceled: PG::InvalidTextRepresentation: ERROR: invalid input syntax for type json DETAIL: The input string ended unexpectedly. CONTEXT: JSON data, line 1: : ALTER TABLE "foo" ADD COLUMN "bar" json DEFAULT ''
  • 您可以尝试将默认设置为“null”吗?

标签: ruby-on-rails json ruby-on-rails-3.2 rails-postgresql pg


【解决方案1】:

虽然有点晚了,但这对我有用(需要 Postgres >= 9.3):

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

execute "ALTER TABLE foo ALTER COLUMN bar SET DEFAULT '[]'::JSON"

编辑:这个答案曾经提倡to_json('[]'::text) 而不是'[]'::JSON - 感谢@Offirmo 的提示。

旧方法的问题在于它实际上并没有像人们期望的那样将数组或对象定义为默认值,而是一个看起来像一个的标量(字符串)。为什么这很重要?

Postgres 允许将三种值插入到 JSON 列中:

  1. 对象

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

  2. 数组

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

  3. 标量

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

问题是,如果在同一列中混合这三种类型,您将失去使用 JSON 运算符的能力。如果您使用先前提倡的方法设置默认值 '[]' 并查询数组元素,遇到具有标量默认值的单行将中止整个查询并出现错误:

=# SELECT * FROM foo WHERE bar->>1 = 'baz';
ERROR:  cannot extract element from a scalar

【讨论】:

  • 我收到以下错误:PG::UndefinedFunction: ERROR: function to_json(text) does not exist HINT: No function matches the given name and argument types. You might need to add explicit type casts.
  • @ManuelMeurer 我相信你需要一个最新版本的 Postgres;我在 9.3.2。
  • 是的,它是在 9.3 中添加的。你能在回答中提到这一点吗?那我就可以接受了。
  • 还有一件小事,你能把&gt;改成&gt;=吗?干杯!
  • 这个语法也有效:SET DEFAULT '{}'::JSON;我觉得它更干净。
【解决方案2】:

以下代码适用于 PostgreSQL 9.3.4 和 Rails 3.2.17

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

迁移代码

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 = '{}';"

应用程序.rb

config.active_record.schema_format = :sql

【讨论】:

    【解决方案3】:

    你基本上可以做这样的事情

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

    使用default: []default: {} 或任何其他您觉得合适的方式声明默认值。

    更新:请注意,这是针对 Rails 4+

    【讨论】:

    • 正如我在 6.5 年前的问题中提到的那样,该应用程序仍在 Rails 3 上,所以这不会(没有)工作。您能否通过提及您的建议中的哪个 Rails 版本来改进您的答案?
    猜你喜欢
    • 2016-12-22
    • 1970-01-01
    • 2014-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-14
    • 1970-01-01
    • 2011-12-01
    相关资源
    最近更新 更多