Necesito ayuda para diseñar permisos de usuario complejos dentro de una base de datos de Postgres. En la aplicación my Rails, cada usuario podrá acceder a un conjunto único de funciones. En otras palabras, no hay "roles" predefinidos que determinen a qué funciones puede acceder un usuario.
En casi todos los controladores/vistas, la aplicación verificará si el usuario actual tiene o no acceso a diferentes funciones. Idealmente, la aplicación proporcionará ~100 funciones diferentes y admitirá más de 500k usuarios.
Por el momento, estoy considerando tres opciones diferentes (¡pero bienvenidas las alternativas!) y me gustaría saber qué opción ofrece el mejor rendimiento. Gracias de antemano por cualquier ayuda/sugerencia.
Al construir una relación de muchos a muchos entre la tabla User y la tabla de funciones, la aplicación podría verificar si un usuario tiene acceso a una Feature determinada consultando la tabla de combinación.
Por ejemplo, si hay un registro en la tabla de combinación que conecta user1 y feature1 , entonces user1 tiene acceso a feature1 .
La aplicación podría representar cada característica como una columna booleana en la tabla User . Esto evitaría consultar varias tablas para verificar los permisos.
Por ejemplo, si user1.has_feature1 es verdadero, entonces user1 tiene acceso a feature1 .
La aplicación podría almacenar funciones como cadenas en una columna de matriz (¿indexada por GIN?) en la tabla User . Luego, para verificar si un usuario tiene acceso a una función, buscaría en la columna de la matriz la función dada.
Por ejemplo, si user1.features.include? 'feature1' es verdadero, entonces user1 tiene acceso a feature1 .
Las relaciones de muchos a muchos son la única opción viable aquí. Hay una razón por la que lo llaman una base de datos relacional.
¿Por qué?
class Feature has_many :user_features has_many :users, through: :user_features end class UserFeature belongs_to :user belongs_to :feature end class User has_many :user_features has_many :features, through: :user_features def has_feature?(name) features.exist?(name: name) end end