Railsシリアライズを使用してハッシュをデータベースに保存する


135

Railsアプリで、ハッシュマッピングIDをいくつかの試行に保存しようとしています。この新しい列に対応するためのデータベースへの移行:

class AddMultiWrongToUser < ActiveRecord::Migration
  def self.up
    add_column :users, :multi_wrong, :string
  end

  def self.down
    remove_column :users, :multi_wrong
  end
end

私のモデルでは:

class User < ActiveRecord::Base 
 serialize :multi_wrong, Hash
end

しかし、私がレールコンソールを使用してこれをテストすると、次のようになります:

user = User.create()
user.multi_wrong = {"test"=>"123"}
user.save

出力は偽です。ここで何が問題になっていますか?


4
レコードを保存しようとした後、user.errorsに何かありますか?
Martijn、2011

1
将来的には、bangメソッド(save!)を使用して例外を発生させ、エラーメッセージを表示することができます。
リーシュ

回答:


174

列のタイプが間違っています。文字列の代わりにテキストを使用する必要があります。したがって、移行は次のようになります。

 def self.up
   add_column :users, :multi_wrong, :text
 end

次に、RailsはそれをYAMLに適切に変換します(適切なシリアル化を実行します)。文字列フィールドはサイズに制限があり、特に小さい値のみを保持します。


1
@BenjaminTanその背後にある理由は何ですか、なぜ「string」データ型にハッシュを格納できないのですか?
Lohith MV 2012

8
データベースでは、Stringは255の固定長であるためです(私はそう思います)。しかし、比較サイズのハッシュをシリアル化すると、これは簡単に長さを超えてしまいます。配列の場合も同じです。テキストでは、はるかに長い長さを使用できます。
Benjamin Tan Wei Hao

72

更新しました:

正確な実装はデータベースに依存しますが、PostgreSQLには、ハッシュ/オブジェクトデータをネイティブに格納し、ActiveRecord使用してJSONに対してクエリ実行できるjsonjsonb列があります。

移行を変更すれば完了です。

class Migration0001
  def change
    add_column :users, :location_data, :json, default: {}
  end
end

元の:

詳細:rails docs && apidock

あなたの列があることを確認しません:text:string

移行:

$ rails g migration add_location_data_to_users location_data:text

作成する必要があります:

class Migration0001
  def change
    add_column :users, :location_data, :text
  end
end

クラスは次のようになります。

class User < ActiveRecord::Base
  serialize :location_data
end

利用可能なアクション:

b = User.new
b.location_data = [1,2,{foot: 3, bart: "noodles"}]
b.save

もっと素晴らしい?!

postgresql hstoreを利用する

class AddHstore < ActiveRecord::Migration  
  def up
    enable_extension :hstore
  end

  def down
    disable_extension :hstore
  end
end 

class Migration0001
  def change
    add_column :users, :location_data, :hstore
  end
end

hstoreを使用すると、シリアル化されたフィールドに属性を設定できます

class User < ActiveRecord::Base  
  # setup hstore
  store_accessor :location_data, :city, :state
end

2
本当にすごい!ありがとう!
Alexander Gorg 2017年

18

Rails 4にはStoreと呼ばれる新機能があるため、簡単に問題を解決するために使用できます。そのためのアクセサーを定義でき、シリアル化されたストアに使用されるデータベース列をテキストとして宣言することをお勧めします。元の例:

class User < ActiveRecord::Base
  store :settings, accessors: [ :color, :homepage ], coder: JSON
end

u = User.new(color: 'black', homepage: '37signals.com')
u.color                          # Accessor stored attribute
u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor

# There is no difference between strings and symbols for accessing custom attributes
u.settings[:country]  # => 'Denmark'
u.settings['country'] # => 'Denmark'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.