我有一个带有条件的经常性代码,最近添加了新的权限代码。它不是从一开始就设计的,所以它有点混乱:
@usuarios = Usuario.menores_de_edad.con_autorizacion(params[:autorizacion]).con_nombre(params[:nombre])
# master puede ver todos, así que ignora los permisos
if !usuario_actual.es_master?
if usuario_actual.permiso.blank?
# Si es admin y no tiene permisos establecidos
@usuarios = Usuario.where(id: nil)
else
# Lee de que niveles puedes mostrar los usuarios
@usuarios = @usuarios.del_nivel(usuario_actual.permiso.niveles)
end
end
if usuario_actual.es_admin_occ?
@usuarios = @usuarios.de_occ
end
我想以这种方式将其作为范围:
@usuarios = Usuario.menores_de_edad.con_autorizacion(params[:autorizacion]).con_nombre(params[:nombre])
@usuarios = @usuarios.permitibles(usuario_actual)
我怎样才能让它发挥作用?我现在有这个:
class Usuario < ActiveRecord::Base
scope :permitibles, lambda{ |usuario_actual|
# master can see everything, so, don't scope anything at all
if !usuario_actual.es_master?
if usuario_actual.permiso.blank?
# return nothing if you don't have permissions
where(id: nil)
else
# this is a scope
del_nivel(usuario_actual.permiso.niveles)
end
if usuario_actual.es_admin_occ?
# this is a scope
de_occ
end
end
}
end
问题是,在范围内,我不知道如何连接其他范围,我的意思是,&#34; de_occ&#34;必须根据其他条件进行链接,但是现在这将不会按原样运行,因为它只返回一个范围而不是链接&#34; de_occ&#34;到第一个条件。我怎样才能做到这一点?
谢谢!
答案 0 :(得分:1)
好的,通过你的代码对我来说没什么问题。最佳做法是不要使用母语langauge作为模型和方法名称的来源。
您的问题的基本方法是将逻辑移动到方法中并链接范围/ sqls。这是一个概念证明:
scope :menores_de_edad, ->() {where(something: true)}
scope :del_nivel, ->(params) {where(field: param)}
scope :de_occ, ->() { ... }
def self.we_are_chaining_scopes
result = self.scoped
if !usuario_actual.es_master?
if usuario_actual.permiso.blank?
# return nothing if you don't have permissions
result = result.menores_de_edad
else
# this is a scope
result = result.del_nivel(usuario_actual.permiso.niveles)
end
if usuario_actual.es_admin_occ?
# this is a scope
result = result.de_occ
end
end
result
end
您可以通过为此查询创建服务对象来使其更加出色。粗略的例子:
class SpecificQuery
def initialize(relation = Model.scoped)
@relation = relation
end
private
def scoped_to(&block)
@relation = @relation.instance_eval(&block)
end
def scoped_behavior_method_one(param)
scoped_to { where(:something: param) }
end
def scoped_behavior_method_two(param)
scoped_to { ... }
end
end
然后你可以很好地链接范围+你将封装不一定属于你的模型的逻辑。此外,编写规范更容易:)我希望有所帮助。