rubyで初心者が間違いそうな間違いしてしまった(まぁ、初心者みたいなもんだけど)
あるあるなのかもしれないけどやってしまった。
RailsでUserモデルがあって、そこにenumでrolesみたいなのを定義している。
しかし、roles内にあるadmin権限は我々スーパー管理者しか触れないようにしたい。
なので、一般ユーザーには目に触れもしないようにしたいため、こうしていた。
%tr - User.roles.delete(:admin) %th= f.label :role, "Role" %td= f.select :role, User.roles.map{|r| [r[0], r[0]]}
が、しかしこれをするとUserモデルのrolesから:adminから消し去ってしまって、二度と出て来ない。
つまり、スーパー管理者の編集画面ですら:adminの設定が見えなくなってしまって、admin権限を持つユーザーを作成することができなくなってしまった。
さすがにこれはまずい、と以下のように修正した。
%tr - roles = User.roles - roles.delete(:admin) %th= f.label :role, "Role" %td= f.select :role, roles.map{|r| [r[0], r[0]]}
が、問題は解決されない。
で、なんだろうと思ったがこれにも問題があった。
User.roles.object_id roles.object_id
と調べてみると同じobject_idを保有している。ので、deleteをrolesにかけたところでUser.rolesから:adminが消え去る現象は改善されない。
つまり同じオブジェクトに操作していることになっているので、cloneする必要があるので以下のようにした。
%tr - roles = User.roles.dup - roles.delete(:admin) %th= f.label :role, "Role" %td= f.select :role, roles.map{|r| [r[0], r[0]]}
が、実はこれにも問題(以下略
結論から言うと、今回はこれでOKなんだけども、
User.roles[:admin].object_id roles[:admin].object_id
は同じなので、実はまだヤバい。
rolesの中から(インデックスとして)消し去るだけなら良いんだけど、:adminの持つ値を自体を変えるとUser.rolesの中の:adminの値まで変わってしまうことになるっぽい。
%tr - roles = Marshal.load(Marshal.dump(User.roles)) - roles.delete(:admin) %th= f.label :role, "Role" %td= f.select :role, roles.map{|r| [r[0], r[0]]}
じゃあ、どうすんだよ!って話なんだけど、こうすると良いっぽい。
参考はこちら