如何让专家政策更干?
How to make pundit policies more DRY?
在我的一个项目中,我开始使用专家 gem,我有一个非常简单的策略,如下所示:
class CompanyPolicy < ApplicationPolicy
def index?
true if user.is_a? Administrator
end
def new?
true if user.is_a? Administrator
end
def create?
new?
end
def edit?
true if user.is_a? Administrator
end
def update?
edit?
end
end
问题是我怎样才能避免重复这个:
true if user.is_a? Administrator
我实际上认为您不需要删除它。通过重复这一点,您明确表示该用户必须是管理员才能访问该方法。如果你确实想要,你可以创建一个私有方法。
class CompanyPolicy < ApplicationPolicy
def index?
admin?
end
def new?
admin?
end
def create?
new?
end
def edit?
admin?
end
def update?
edit?
end
private
def admin?
user.is_a? Administrator
end
end
我猜这是个人喜好问题。
我的技巧是这样的:
class ApplicationPolicy
private
def self.permit_owner_to(*actions)
actions.each do |action|
define_method("#{action}?") do
owner?
end
end
end
def owner?
# owner logic
end
end
并在其他政策中使用
class ItemPolicy < ApplicationPolicy
permit_owner_to :show, :update, :destroy, :confirm
end
你可以使用 alias_method
.
class CompanyPolicy < ApplicationPolicy
def index?
user.is_a? Administrator
end
alias_method :create?, :index?
alias_method :update?, :index?
end
您有一个基础 class ApplicationPolicy
,它可能已经包含:
def new?
create?
end
def edit?
update?
end
所以你不需要在你的子程序中重复这些方法class。
.is_a?
returns true
或 false
所以不需要明确 return true if true
.
这样简洁多了是吗? :)
我结合上面的答案得出以下结论:
class ApplicationPolicy
attr_reader :user
def initialize(user)
@user = user
end
def self.permit(roles, options)
return if options[:to].none?
options[:to].each do |action|
define_method("#{action}?") do
return @user.roles? Array.wrap(roles) if options[:when].blank?
send(options[:when]) and @user.roles? Array.wrap(roles)
end
end
end
end
允许这样使用它:
class CommentPolicy < ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@record = record
super(user)
end
permit %i[admin member], to: %i[show edit destroy update], when: :created_by_user
def created_by_user
@record.user == @user
end
end
和
permit :admin, to: %i[index update edit]
同样有效
我在 user
模型中的角色方法如下所示:
def roles?(user_roles)
user_roles.each do |role|
return true if role?(role)
end
false
end
def role?(role)
roles.any? { |r| r.name.underscore.to_sym == role }
end
在我的一个项目中,我开始使用专家 gem,我有一个非常简单的策略,如下所示:
class CompanyPolicy < ApplicationPolicy
def index?
true if user.is_a? Administrator
end
def new?
true if user.is_a? Administrator
end
def create?
new?
end
def edit?
true if user.is_a? Administrator
end
def update?
edit?
end
end
问题是我怎样才能避免重复这个:
true if user.is_a? Administrator
我实际上认为您不需要删除它。通过重复这一点,您明确表示该用户必须是管理员才能访问该方法。如果你确实想要,你可以创建一个私有方法。
class CompanyPolicy < ApplicationPolicy
def index?
admin?
end
def new?
admin?
end
def create?
new?
end
def edit?
admin?
end
def update?
edit?
end
private
def admin?
user.is_a? Administrator
end
end
我猜这是个人喜好问题。
我的技巧是这样的:
class ApplicationPolicy
private
def self.permit_owner_to(*actions)
actions.each do |action|
define_method("#{action}?") do
owner?
end
end
end
def owner?
# owner logic
end
end
并在其他政策中使用
class ItemPolicy < ApplicationPolicy
permit_owner_to :show, :update, :destroy, :confirm
end
你可以使用 alias_method
.
class CompanyPolicy < ApplicationPolicy
def index?
user.is_a? Administrator
end
alias_method :create?, :index?
alias_method :update?, :index?
end
您有一个基础 class ApplicationPolicy
,它可能已经包含:
def new?
create?
end
def edit?
update?
end
所以你不需要在你的子程序中重复这些方法class。
.is_a?
returns true
或 false
所以不需要明确 return true if true
.
这样简洁多了是吗? :)
我结合上面的答案得出以下结论:
class ApplicationPolicy
attr_reader :user
def initialize(user)
@user = user
end
def self.permit(roles, options)
return if options[:to].none?
options[:to].each do |action|
define_method("#{action}?") do
return @user.roles? Array.wrap(roles) if options[:when].blank?
send(options[:when]) and @user.roles? Array.wrap(roles)
end
end
end
end
允许这样使用它:
class CommentPolicy < ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@record = record
super(user)
end
permit %i[admin member], to: %i[show edit destroy update], when: :created_by_user
def created_by_user
@record.user == @user
end
end
和
permit :admin, to: %i[index update edit]
同样有效
我在 user
模型中的角色方法如下所示:
def roles?(user_roles)
user_roles.each do |role|
return true if role?(role)
end
false
end
def role?(role)
roles.any? { |r| r.name.underscore.to_sym == role }
end