ruby - 将元素添加到 postgres 数组字段失败,同时替换整个数组有效

标签 ruby postgresql ruby-on-rails-4 cancan

我有一个包含一系列角色的用户模型。

来 self 的 schema.db:

create_table "users", force: true do |t|
  t.string   "roles",         array: true

我的模型是这样的:

class User < ActiveRecord::Base
  ROLES = %w(superadmin sysadmin secretary)

  validate :allowed_roles
  after_initialize :initialize_roles, if: :new_record?

  private

  def allowed_roles
    roles.each do |role|
      errors.add(:roles, :invalid) unless ROLES.include?(role)
    end
  end

  def initialize_roles
    write_attribute(:roles, []) if read_attribute(:roles).blank?
  end

问题是当我尝试从控制台添加另一个角色时,例如 user.roles << "new_role"然后 user.save!说 true 并询问 user.roles 给了我想要的输出。但是当我询问 User.find(user_id).roles 时,我得到的是之前的状态,其中没有“new_role”。

例如。

user.roles
  => ["superadmin"]
user.roles << "secretary"
  => ["superadmin", "secretary"]
user.save!
  => true
user.roles
  => ["superadmin", "secretary"]
User.find(<user_id>).roles
  => ["superadmin"]

当替换整个数组时,它如我所愿:

user.roles
  => ["superadmin"]
user.roles = ["superadmin", "secretary"]
user.save!
  => true
user.roles
  => ["superadmin", "secretary"]
User.find(<user_id>).roles
  => ["superadmin", "secretary"]

我正在使用 rails 4 和 postgresql,角色用于 cancancan gem。

更改其他字段,如 ex 的 user.name 会像预期的那样工作。我在谷歌中进行了大量挖掘,但没有任何帮助。

最佳答案

Active Record 跟踪哪些列已更改,并且仅将这些保存到数据库中。这种变化跟踪通过 Hook 到 setter 方法来工作 - 未检测到就地改变对象。例如

user.roles << "superuser"

不会被检测为更改。

有两种解决方法。一种是永远不要就地更改任何 Active Record 对象属性。在你的情况下,这意味着稍微笨拙

user.roles += ["superuser"]

如果你不能/不会这样做,那么你必须告诉 Active Record 你做了什么,例如

user.roles.gsub!(...)
user.roles_will_change!

让 Active Record 知道角色属性已经改变并且需要更新。

如果 Active Record 能更好地处理这个问题会更好 - 当不支持数组列中的更改跟踪时(当时 mysql 受到了最大的关注)

另一种方法是将此类列标记为始终需要保存(很像序列化属性所发生的情况),但您需要为此对 activerecord 进行猴子修补。

关于ruby - 将元素添加到 postgres 数组字段失败,同时替换整个数组有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25142532/

相关文章:

SQL - min() 获得最低值,max() 获得最高值,如果我想要第二个(或第五个或第 n 个)最低值怎么办?

mysql - OpsWorks 部署错误 - Chef::Exceptions::ChildConvergeError

ruby - JRuby 与 Heroku 上的 Sinatra

jquery - ExecJS::RuntimeError:语法错误:意外的标记:运算符 (<)

node.js - Sequelize : relation "<tablename>" does not exist when querying table while seeding

ruby-on-rails - 应该和 before_ 回调

ruby-on-rails - Rails 3.2 在 4.1 发布后是否仍受支持?

ruby-on-rails - Users#show on Rails 项目中的 NoMethodError

ruby-on-rails - 多对多表在 Rails 中有一个额外的列

postgresql - 等同于完美球体上的 PostGIS ST_Project