And*_*eis 1 ruby postgresql cancan ruby-on-rails-4
我有一个具有一系列角色的用户模型.
从我的schema.db:
create_table "users", force: true do |t|
t.string "roles", array: true
Run Code Online (Sandbox Code Playgroud)
我的模型看起来像这样:
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
Run Code Online (Sandbox Code Playgroud)
问题是当我尝试从控制台添加另一个角色时,例如user.roles <<"new_role",然后是user.save!说是真的,并要求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"]
Run Code Online (Sandbox Code Playgroud)
更换整个阵列时,它可以按我的意愿工作:
user.roles
=> ["superadmin"]
user.roles = ["superadmin", "secretary"]
user.save!
=> true
user.roles
=> ["superadmin", "secretary"]
User.find(<user_id>).roles
=> ["superadmin", "secretary"]
Run Code Online (Sandbox Code Playgroud)
我正在使用rails 4和postgresql,角色是cancancan gem.
更改其他字段,如user.name,以便预期使用.我在谷歌上做了很多挖掘,但没有帮助.
活动记录跟踪哪些列已更改,并仅将这些列保存到数据库.此更改跟踪通过挂钩到setter方法来工作 - 未检测到对位置变异.例如
user.roles << "superuser"
Run Code Online (Sandbox Code Playgroud)
不会被检测为更改.
有两种方法可以解决这个问题.一个是永远不会改变任何Active Record对象属性.在你的情况下,这将意味着轻微的笨拙
user.roles += ["superuser"]
Run Code Online (Sandbox Code Playgroud)
如果你不能/不会这样做,那么你必须告诉Active Record你做了什么,例如
user.roles.gsub!(...)
user.roles_will_change!
Run Code Online (Sandbox Code Playgroud)
让Active Record知道roles属性已更改并需要更新.
如果Active Record更好地处理这个问题会更好 - 当数组列中的更改跟踪不受支持时(当时mysql占据了大部分注意力)
另一种方法是将这些列标记为始终需要保存(非常类似于序列化属性所发生的那样),但是您需要为此修补补丁activerecord.