2012-02-04 14 views
5

Tengo un archivo de gran capacidad que decide qué es exactamente lo que los usuarios pueden hacer al buscar desde una tabla de 'Roles'. Cada función corresponde a algo que un usuario en particular puede hacer, por ejemplo, poder agregar un proyecto o poder editar el registro principal de la compañía.Reducción de la carga de ability.rb en cancan

Por el momento, cada acción del controlador que se ejecuta load_and_authorize_resource pasa a través de> 30 declaraciones como:

ability.rb (>30 times) 
Role.where("user_id = ? AND role = ? AND roleable_type = ? AND roleable_id IS NULL", user.id, "delete", "task").last.present? ? (can :destroy, Task) : nil 

Ésta es una solución terriblemente ineficiente debido a que el servidor está en funcionamiento> 30 consultas antes de que incluso hace nada.

La mejor manera de hacer esto sería ejecutar las consultas que necesitan ejecutarse según lo que requieren el controlador y la vista. ¿Hay alguna forma de hacer esto?

+0

Uh oh, voy a tener que auditar mi propio uso de cancan. Por curiosidad, ¿lo hace tanto en entornos de desarrollo como de producción? – miked

+0

Es difícil para mí asimilar todo lo que sucede en tus asociaciones con esa línea. Pero tal vez podría desear cargar todas las funciones de un usuario con algo como 'User.includes (: roles) .find (@ user.id)'. Entonces, una consulta SQL mantendrá las funciones del usuario en la memoria para que pueda procesarlas. – danneu

+0

@danneu - Probaré su sugerencia y veré si reduce el número de consultas. Básicamente, cada 'función' le otorga a un usuario un permiso específico: esto permite que las habilidades del usuario sean infinitamente personalizables (pero, como puede ver, da como resultado algunas situaciones de desempeño difíciles). – sscirrus

Respuesta

4

Es en parte la forma en que escribiste las pruebas de roles. En lugar de escribir> 30 veces:

Role.where("user_id = ? AND role = ? AND roleable_type = ? AND roleable_id IS NULL", user.id, "delete", "task").last.present? ? (can :destroy, Task) : nil 

su lugar, puede consultar a todos a los roles de los usuarios a la vez:

@user_roles = user.roles.all 

continuación, prueba de forma individual para cada función:

can :destroy, Task if @user_roles.detect {|u| u["role"] == "delete" && u["roleable_type"]=="task" } 

Debido a que todos los roles se leen en la memoria en una sola consulta, no tiene 30 consultas.

+0

Caché variable. Definitivamente. No solo por cancan ... – pduersteler

Cuestiones relacionadas