【问题标题】:How to generate right sql for using hstore in rails migration postgres using change_column如何使用change_column在rails迁移postgres中生成正确的sql以使用hstore
【发布时间】:2018-09-17 05:29:02
【问题描述】:

我需要让 hstore 在 Rails 迁移中工作。我已经通过迁移启用了 hstore,现在,我正在尝试生成正确的 sql 以使其正常工作,但是当我运行 db:migrate 时出现此错误;

C:\Sites\Peoples_Profiles>rails db:migrate
rails aborted!
SyntaxError: C:/Sites/Peoples_Profiles/db/migrate/20180407073155_add_hstore_hash_to_urls.rb:4: syntax error, unexpected '\n', expecting =>
C:/Sites/Peoples_Profiles/db/migrate/20180407073155_add_hstore_hash_to_urls.rb:10: syntax error, unexpected end-of-input, expecting keyword_end
bin/rails:4:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

迁移看起来像这样。

class AddHstoreHashToUrls < ActiveRecord::Migration[5.0]

  def self.up
    change_column :users, :urls, default: {}, "hstore USING urls::hstore" 
  end

  def self.down
    change_column :users, :urls, :text
  end
end

获取该列的类型集的正确 sql 是什么?为什么会出现换行错误?

更新 我的 url 像这样存储在 db 中

 urls: {"url1"=>"", "url2"=>"", "url3"=>"", "url4"=>"", "url5"=>""}

所以我认为 postgres 抱怨是因为它正在尝试转换此代码..

所以在检查 rails 是如何实际引入参数后,它看起来像这样

 ["urls", "--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\nurl1: http://hello\nurl2: http://jack\nurl3: http://boo\nurl4: ''\nurl5: ''\n"]

不幸的是,不确定它在数据库中是否看起来像这样,但我说那里有一个 \n 导致此错误。将不得不进一步追求这一点。

...我现在意识到 \n 将来自将哈希序列化为 YAML 的转换。

【问题讨论】:

  • 我将尝试做一个 create_table 只是为了看看它是否只是迁移过来..
  • 好的,所以如果我这样做 add_column :users, :urlss, :hstore, default: {}, null: false 并添加一个新列它可以工作,所以我认为它在更改和转换格式时遇到了麻烦

标签: ruby-on-rails postgresql hstore


【解决方案1】:

尝试将 SELF.DOWN 更改为 SELF.ANNUAL 我认为它会解决

【讨论】:

  • 而且你没有关闭线路(见第 4 行)
  • 什么意思?
  • 我认为您不需要关闭线路我认为 rails 会自动执行此操作..
【解决方案2】:

大概你是这样开始的:

serialize :urls

在您的模型中,因此您的哈希值作为 YAML 存储在数据库中。没有从 YAML 文本到 hstore 的类型转换,因此您的使用:

USING urls::hstore

行不通。没有简单的方法可以在 PostgreSQL 中可靠地解析 YAML,所以最好的办法是:

  1. users.urls 列重命名为users.yaml_urls
  2. 添加一个带有(最好)jsonb 类型的新urls 列,但如有必要,您可以使用hstorejsonb 是未来,未来会得到更好的支持。
  3. 将数据库中的每个 yaml_urls 值读入 Ruby。
  4. 将该 YAML 字符串转换为带有 h = YAML.load(yaml_from_db) 的哈希。
  5. 将哈希编码为 JSON (h.to_json) 并将其放回数据库中。
  6. 如果需要,将 urls 设为 NOT NULL 并删除 yaml_urls 列。

我建议为此使用低级别的pg interface,因为您不想要 ActiveRecord 的东西,您能在ApplicationRecord.connection.raw_connection 中找到这样的连接吗?我这样说是因为您不希望数据迁移以任何方式与模型交互,并且低级接口支持占位符,因此您可以避免转义和引用问题。

该过程假定您没有那么多数据,或者等效地,您的应用可以在您修复数据库时处于离线状态。如果不是这种情况,那么您需要在修复数据时维护这两种格式(添加一个新的jsonb 列,在调用urlsurls= 时从模型内部写入和读取),并且稍后再清理。

【讨论】:

  • 所以你说我可以使用 pg gem 或 ApplicationRecord.connection.raw_connection 我找不到任何东西。我已经安装了 pg gem。你说我可以在建立连接后运行所有这些代码。然后把我的ruby和sql混合起来达到效果?
  • 您可以在迁移中找到 PG::Connection 中的 ApplicationRecord.connection.raw_connection 或仅 connection.raw_connection。我在答案中链接到pg 文档。然后,您必须使用 SQL(获取数据并放回新数据)和 Ruby(解码 YAML 并编码为 JSON)手动逐行修复所有内容。是的,这是一个丑陋的过程,但这是使用serialize 的必然结果。
猜你喜欢
  • 2018-10-31
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 2013-08-28
  • 2015-12-25
  • 2011-07-28
  • 1970-01-01
  • 2016-10-25
相关资源
最近更新 更多