如何使用Rails #update_attribute与数组字段?

时间:2015-06-15 23:55:06

标签: ruby-on-rails ruby postgresql ruby-on-rails-4 activerecord

每个问题都有一系列标签。

schema.rb:

create_table "questions", force: true do |t|
  t.text     "tags", default: [], array: true

如何以原子方式附加到标签?

如何防止阵列中的重复?

我试过question.update_attribute tags: tags << :ruby,但这不起作用。

Rails 4.17和Postgres。

编辑:这似乎已在Rails 4.2中修复

1 个答案:

答案 0 :(得分:2)

我认为update_attribute不会有用,因为它会用新值替换数组而不是附加到它(但请参阅下面--Update--部分中的更好解释)。

我不确定这里有什么最佳做法,但这应该可以添加一些东西,如果它还没有:

question.tags << :ruby unless question.tags.include?(:ruby)
question.save

我会在Question模型上编写一个自定义方法来管理添加标记和检查唯一性:

def add_tag(tag)
  if tags.include?(tag)
    # do whatever you want to do when tag isn't unique
    p "#{tag} is already in tags!"
  else
    tags << tag
    save
  end
end

然后使用question.add_tag(:ruby)调用它。

--------------------更新-----------------------

如果这不起作用,可能会出现ActiveRecord无法识别字段已更改的问题(虽然它似乎在Rails 4.2中正常工作)。

这些链接解释了这个问题:

New data not persisting to Rails array column on Postgres

http://paweljaniak.co.za/2013/07/28/rails-4-and-postgres-arrays/

正如他们解释的那样,你可以在这里使用update_attribute,但你需要替换整个数组,而不是将值推到它上面,如下所示:

question.update_attribute(:tags, question.tags << tag)

您还应该能够强制ActiveRecord考虑更新属性,方法是包括will_change!,如下所示:

def add_tag(tag)
  if tags.include?(tag)
    # do whatever you want to do when tag isn't unique
    p "#{tag} is already in tags!"
  else
    tags_will_change!
    tags << tag
    save
  end
end