简体   繁体   English

新数据未持久到Postgres上的Rails数组列

[英]New data not persisting to Rails array column on Postgres

I have a user model with a friends column of type text. 我有一个带有text类型的friends列的用户模型。 This migration was ran to use the array feature with postgres: 运行此迁移是为了将数组功能与postgres结合使用:

add_column    :users, :friends, :text, array: true

The user model has this method: 用户模型具有以下方法:

def add_friend(target)
  #target would be a value like "1234"
  self.friends = [] if self.friends == nil
  update_attributes friends: self.friends.push(target)
end

The following spec passes until I add user.reload after calling #add_friend : 通过以下规范,直到我在调用#add_friend之后添加user.reload #add_friend

it "adds a friend to the list of friends" do
  user = create(:user, friends: ["123","456"])
  stranger = create(:user, uid: "789")
  user.add_friend(stranger.uid)
  user.reload #turns the spec red
  user.friends.should include("789")
  user.friends.should include("123")
end

This happens in development as well. 这也在开发中发生。 The model instance is updated and has the new uid in the array, but once reloaded or reloading the user in a different action, it reverts to what it was before the add_friend method was called. 模型实例已更新,并且在数组中具有新的uid,但是一旦重新加载或以其他操作重新加载用户,它就会恢复为调用add_friend方法之前的add_friend

Using Rails 4.0.0.rc2 and pg 0.15.1 使用Rails 4.0.0.rc2和pg 0.15.1

What could this be? 这可能是什么?

I suspect that ActiveRecord isn't noticing that your friends array has changed because, well, the underlying array reference doesn't change when you: 我怀疑ActiveRecord不会注意到您的friends数组已更改,因为,当您执行以下操作时,基础数组引用不会更改:

self.friends.push(target)

That will alter the contents of the array but the array itself will still be the same array. 这将改变数组的内容 ,但数组本身仍将是同一数组。 I know that this problem crops up with the postgres_ext gem in Rails3 and given this issue : 我知道这个问题出现在Rails3中的postgres_ext gem并给出了这个问题

String attribute isn't marked as dirty, when it changes with << 字符串属性用<<更改时,未标记为脏

I'd expect Rails4 to behave the same way. 我希望Rails4的行为相同。

The solution would be to create a new array rather than trying to modify the array in-place: 解决方案是创建一个新数组,而不是尝试就地修改该数组:

update_attributes friends: self.friends + [ target ]

There are lots of ways to create a new array while adding an element to an existing array, use whichever one you like. 有多种方法可在将元素添加到现有数组时创建新数组,无论您喜欢哪种方法。

It looks like the issue might be your use of push , which modifies the array in place. 看来问题可能出在您使用push修改了数组的位置。

I can't find a more primary source atm but this post says: 我找不到更主要的自动取款机,但是这篇文章说:

One important thing to note when interacting with array (or other mutable values) on a model. 与模型上的数组(或其他可变值)交互时要注意的一件事。 ActiveRecord does not currently track "destructive", or in place changes. ActiveRecord当前不跟踪“破坏性”或就地更改。 These include array push ing and pop ing, advance -ing DateTime objects. 这些包括数组pushpopadvance DateTime对象。 If you want to use a "destructive" update, you must call <attribute>_will_change! 如果要使用“破坏性”更新,则必须调用<attribute>_will_change! to let ActiveRecord know you changed that value. 让ActiveRecord知道您更改了该值。

If you want to use Postgresql array type, you'll have to comply with its format. 如果要使用Postgresql数组类型,则必须遵守其格式。 From Postgresql docs the input format is Postgresql文档输入的格式是

'{10000, 10000, 10000, 10000}'

which is not what friends.to_s will return. 不是friends.to_s返回的内容。 In ruby: 在红宝石中:

[1,2,3].to_s => "[1,2,3]"

That is, brackets instead of braces. 也就是说,用括号代替大括号。 You'll have to do the conversion yourself. 您必须自己进行转换。

However I'd much rather rely on ActiveRecord serialize (see serialize ). 但是,我宁愿依赖ActiveRecord进行序列化(请参阅序列化 )。 The database does not need to know that the value is actually an array, that's your domain model leaking into your database. 数据库不需要知道该值实际上是一个数组,这就是您的域模型泄漏到数据库中。 Let Rails do its thing and encapsulate that information; 让Rails做事并封装这些信息。 it already knows how to serialize/deserialize the value. 它已经知道如何对值进行序列化/反序列化。

Note: This response is applicable to Rails 3, not 4. I'll leave here in case it helps someone in the future. 注意:此响应仅适用于Rails 3,而不适用于Rails4。我将留在这里,以防将来对某人有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM