简单介绍Ruby on Rails对PostgreSQL数组类型的支持
我非常高兴在宣布Rails4.0现在支持PostgreSQL数组类型.你可以方便的在migration通过:array=>true里创建数组类型的字段.创建数组类型的字段的时候还可以添加其它的选项(length,default,等等)
create_table:table_with_arraysdo|t| t.integer:int_array,:array=>true #integer[] t.integer:int_array,:array=>true,:length=>2 #smallint[] t.string:string_array,:array=>true,:length=>30 #charvarying(30)[] end
需要注意在是对数组类型的字段设置默认值的时候,你应该用Postgresql里的写法({value,anothervalue}),如果你想设置数组类型的字段默认值为空数组的时候,你应该使用:default=>'{}'
create_table:table_with_arraysdo|t| t.integer:int_array,:array=>true,:default=>'{}' #integer[],default==[] t.integer:int_array,:array=>true,:length=>2,:default=>'{1}' #smallint[],default==[1] end
在Model里使用Postgresql数组的例子
我们现在有个包含first_name,last_name,nickname的usermodel,其中nickname字段是数组类型.下面的migration代码会创建相应的表:
create_table:usersdo|t| t.string:first_name t.string:last_name t.string:nicknames,:array=>true end
并且对于这个表,我们有个简单的model
classUser<ActiveRecord::Base attr_accessible:first_name,:last_name,:nicknames end
我们没有对字段使用默认值,如果我们实例一个User对象,代码是这样的.
john=User.create(:first_name=>'John',:last_name=>'Doe')
如果,我们调用john.nickname,结果会返回nil,并且在postgreSQL里存储的是NULL值.
我们通过下面的代码可以在创建时,设置nickname属性值
john=User.create(:first_name=>'John',:last_name=>'Doe', :nicknames=>['Jack','Johnny'])
如果我们从数据库获取记录,那么nick_name字段会转变成一个数组,而不是返回字符串{Jack,Johnny}!。Rails4.0拥有一个纯Ruby数组转换器,但是如果你想让转换过程加速,那么就可以使用之前提到的pg_array_parsergem。PgArrayParser拥有一个基于C的扩展,还有一个JRuby的Java的实现(即使这个gem现在在JRuby上存在些问题,我正在尝试去解决这个问题。)
有一个重点需要注意的,就是当在一个model中和数组(或者其他可变数值)交互的时候。ActiveRecord现在并没有跟踪"destructive",或者更改发生的地方。这包括数组的push和pop操作。如果你需要使用"destructive"更新,你必须使用call<属性>_will_change!这样可以让ActiveRecord知道你需要更改属性的值。对于我们的这个Usermodel,如果你想在nickname后面追加元素,你可以这样做:
john=User.first john.nicknames+=['Jackieboy'] #或者 john.nicknames=john.nicknames.push('Jackieboy') #任何时候,属性通过"="赋值,ActiveRecord会跟踪这个更改 john.save john.reload john.nicknames #=>['Jack','Johnny','JackieBoy'] john.nicknames.pop john.nicknames_will_change! #'#pop'操作会改变数组的值,所以我们需要告诉ActiveRecord它将会发生更改 john.save
最后一项在Postgresql中使用数组要注意的事情是:数组没有元素数量限制,可以是多维数组,但是在使用多维数组时,子数组元素个数必须是一样的.
[[1,2,3],[2,3,4],[4,5,nil]] #在PostgreSQL可用,每个子数组元素个数一样 [1,2,[3,4]] #不可用的数组