我有一个包含一系列角色的用户模型。
来 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/