我在Rails / Postgres应用程序中有一列想要从Hstore更改为Array。(我将手机存储为哈希,所以可以这样做{default: 123, mobile: 1234}
,但认为这是不必要的/没用的)
因此,我进行了以下迁移:
class ChangePhonesToArray < ActiveRecord::Migration
def up
new_phones = {}
Place.find_each do |p|
new_phones[p.id] = p.phones.values.map{ |v| v.gsub(%r!\D!, '') } # get rid of non-number characters while I'm at it
end
remove_column :places, :phones
add_column :places, :phones, :string, array: true, default: []
new_phones.each do |k, v|
p = Place.find(k)
p.update_attributes!(phones: v)
end
end
...
end
但是,当我这样做时,我得到了这个讨厌的数据库错误,表明那phones
仍然是Hstore列!
StandardError: An error has occurred, this and all later migrations canceled:
can't cast Array to hstore/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/abstract/quoting.rb:76:in `type_cast'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/postgresql/quoting.rb:111:in `type_cast'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/postgresql_adapter.rb:828:in `block in exec_cache'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/postgresql_adapter.rb:827:in `map'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/postgresql_adapter.rb:827:in `exec_cache'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/postgresql/database_statements.rb:155:in `exec_delete'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/abstract/database_statements.rb:101:in `update'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/abstract/query_cache.rb:14:in `update'
我以为该列未被正确删除,因此我remove_column
在第一列之后立即扔了第二列,这引发了以下错误,表明该列已被移除!(但显然并不完全)。
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedColumn: ERROR: column "phones" of relation "places" does not exist
: ALTER TABLE "places" DROP "phones"/Users/sasha/.rvm/gems/ruby-2.1.2/gems/rack-mini-profiler-0.9.2/lib/patches/sql_patches.rb:160:in `exec'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/rack-mini-profiler-0.9.2/lib/patches/sql_patches.rb:160:in `async_exec'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/postgresql/database_statements.rb:128:in `block in execute'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/abstract_adapter.rb:373:in `block in log'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.4/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/abstract_adapter.rb:367:in `log'
/Users/sasha/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.4/lib/active_record/connection_adapters/postgresql/database_statements.rb:127:in `execute'
知道这里发生了什么,以及如何解决/解决它吗?
仅仅因为您更改了数据库内部的表架构并不意味着您的Place
类知道这些更改。ActiveRecord::Base
子类仅加载一次列信息,以避免不必要地一遍又一遍地访问数据库。一旦您这样做:
Place.find_each
您Place
将知道列的类型。然后,您更改背后的模式,Place
并尝试编写新值,但Place
不知道更改。解决此问题的常用方法是致电reset_column_information
:
重置所有有关列的缓存信息,这将导致它们在下一个请求时重新加载。
此方法最常见的用法模式可能是在迁移中...
所以你只想说:
#...
remove_column :places, :phones
add_column :places, :phones, :string, array: true, default: []
Place.reset_column_information
#...
顺便说一句,不能保证hstore
将保持任何顺序,因此您可能希望p.phones.values_at(:default, :mobile)
而不是p.phones.values
确保数组中的顺序正确。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句