2011-07-14 62 views
119

我试着在我的Rails应用程序中保存一个哈希映射id到一定数量的尝试。我对数据库迁移,以适应这个新列:使用Rails序列化将散列保存到数据库

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

+0

将来,您可以使用bang方法(save!)来引发异常并显示错误消息。 – leishman

回答

162

列类型错误。您应该使用文本而不是字符串。因此,迁移应该是:

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

然后Rails会适当地将其转换成YAML你(和执行正确的序列化)。字符串字段的大小有限,只能保存特别小的值。

+1

@BenjaminTan背后的原因是什么,为什么我不能在'字符串'数据类型中存储散列。 –

+7

因为在数据库中,字符串的固定长度为255(我认为)。但是如果你要序列化一个比较大小的散列,这很容易超过这个长度。数组的情况相同。文字允许更大的长度。 –

56

有关详细信息: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

真的很棒!谢谢! –

+0

这适用于导轨4? –

11

轨道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' 
相关问题