0

Hstore에서 Array로 변경할 열이 내 Rails/Postgres 앱에 있습니다. 그러나, 나는 그렇게 할 때HStore 열을 배열로 변경

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 

: (나는 해시로 전화를 저장했다, 그래서 나는 {default: 123, mobile: 1234}을 할 수 있지만,이/필요한 유용하지라고 판단했습니다)

그래서 나는 다음과 같은 마이그레이션을했다 phones은 여전히 ​​Hstore 열임을 알리는이 불쾌한 DB 오류가 발생합니다!

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' 

I의 열이 제대로 제거되지 않고, 그래서 바로 제 뒤에 존재하는 제 2 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' 

여기에 무슨 일이 벌어지고 있는지, 어떻게 해결할 수 있습니까?

답변

3

데이터베이스 내에서 테이블 스키마를 변경했기 때문에 귀하의 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 
#... 

BTW, hstore 어떤을 유지할 것이라는 보장이 없다 정렬 순서이므로 p.phones.values 대신 p.phones.values_at(:default, :mobile)을 사용하여 배열에 올바른 순서로 항목을 만들 수 있습니다.

+0

고맙습니다! 정보를 재설정해야하는 클래스 자체에 대해서는 전혀 몰랐습니다. 차가워서 배우십시오. 매력처럼 일했습니다. – Sasha