使用Rails序列化将哈希保存到数据库

cmw*_*ght 135 ruby serialization activerecord ruby-on-rails

我试图在我的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
Run Code Online (Sandbox Code Playgroud)

在我的模型中,我有:

class User < ActiveRecord::Base 
 serialize :multi_wrong, Hash
end
Run Code Online (Sandbox Code Playgroud)

但是,当我使用rails控制台通过执行以下操作来测试时:

user = User.create()
user.multi_wrong = {"test"=>"123"}
user.save
Run Code Online (Sandbox Code Playgroud)

输出为false.这里出了什么问题?

Ben*_*Hao 174

列类型错误.您应该使用Text而不是String.因此,您的迁移应该是:

 def self.up
   add_column :users, :multi_wrong, :text
 end
Run Code Online (Sandbox Code Playgroud)

然后Rails会正确地将它转换为YAML(并执行正确的序列化).字符串字段的大小有限,只能包含特别小的值.

  • 因为在数据库中,String的固定长度为255(我认为).但是如果你要序列化比较大小的哈希值,这很容易超过长度.数组的情况相同.文本允许更长的长度. (8认同)

Bla*_*son 68

更新:

确切的实现将取决于您的数据库,但PostgreSQL现在有jsonjsonb列可以本机存储您的哈希/对象数据,并允许您使用ActiveRecord查询JSON!

改变你的迁移,你就完成了.

class Migration0001
  def change
    add_column :users, :location_data, :json, default: {}
  end
end
Run Code Online (Sandbox Code Playgroud)

原版的:

有关更多详细信息: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
Run Code Online (Sandbox Code Playgroud)

你的班级看起来像:

class User < ActiveRecord::Base
  serialize :location_data
end
Run Code Online (Sandbox Code Playgroud)

可用操作:

b = User.new
b.location_data = [1,2,{foot: 3, bart: "noodles"}]
b.save
Run Code Online (Sandbox Code Playgroud)

更棒真棒?!

利用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
Run Code Online (Sandbox Code Playgroud)

使用hstore,您可以在序列化字段上设置属性

class User < ActiveRecord::Base  
  # setup hstore
  store_accessor :location_data, :city, :state
end
Run Code Online (Sandbox Code Playgroud)

  • 真是棒极了!谢谢! (2认同)

Abo*_*abi 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'
Run Code Online (Sandbox Code Playgroud)