Support Rails's `attribute` in Cancancan's `permitted_attributes`
TLDR: Cancancan does not "see" non-database backed attributes, so they are missing in permitted_attributes.
Steps to reproduce
Rails 7.1.2 application with a basic user model with the database fields email and password_digest, with the important parts from the model being:
class User < ApplicationRecord
has_secure_password
With the god-ability:
class Ability
include CanCan::Ability
attr_reader :user
def initialize(user)
return if user.blank?
can :manage, :all
end
end
Now run: Ability.new(User.first).permitted_attributes(:edit, User.first)
Expected behavior
[:email, :password_digest, :password, :password_confirmation]
Actual behavior
[:email, :password_digest]
-> Cancancan misses out on the password attributes. The same problem can be reproduced by using Rail's attribute method, i.e.
class MyModel < ApplicationRecord
attribute :foo # Cancancan will miss this
end
System configuration
Rails version: 7.1.2
Ruby version: 3.2.2
CanCanCan version 3.4.0
I guess this also interferes with other Gems such as active_type or any custom accessor logic using virtual fields using attribute.
I hope the examples above are useful to you. Let me know if I can help you enlighten this further.
Best, Kalsan
I have created pull request #839 to address this. This pull request fixes the core issue where cancancan misses attribute :foo in general.
Rail's method has_secure_password is still missed, because for some reason, Rails does not declare an explicit attribute for password and password_confirmation. I don't think there is a simple way to detect those (and hardcoding a search for those two methods is likely a terrible idea), so I'd suggest mentionning in the documentation that for this particular case, cancancan can be brought to "see" the extra attributes by typing:
class User < ApplicationRecord
has_secure_password
attribute :password # perhaps, add additional arguments such as the type (string)
attribute :password_confirmation # as above
end
Looking forward to hear what you think :-)