2011-09-03 18 views
6

Soy nuevo en los rieles, y estoy trabajando en mi segunda aplicación de rieles.Estructura de modelo de rieles para usuarios

La aplicación tendrá diferentes roles para los usuarios, pero algunos usuarios tendrán múltiples roles.

Cada usuario del sitio será un artista. Algunos usuarios tendrán el rol de moderador.

¿Cómo estructuraría esto? En algunas aplicaciones PHP que he usado, solo hay un usuario, y luego una columna de base de datos para is_admin, etc. Pero he consultado la fuente de las aplicaciones de rails y he visto modelos separados para Usuario y Administrador, etc. aunque No estoy seguro por qué.

Entonces, ¿debería tener un único modelo de usuario con un atributo de función, que podría ser Moderador, y luego simplemente llamar a los usuarios "Artistas" en mis vistas, rutas, etc.?

¿O debería tener un modelo de usuario, un modelo de moderador que herede de él y un modelo de artista que pertenezca al usuario?

Estoy muy confundido.

Respuesta

7

Puedes buscar gemas Devise y CanCan. Este par es una combinación realmente poderosa. Esto hace que dos modelos sean Usuario y Rol. En Role puede crear nuevos roles, sin crear nuevos modelos para ellos. Aunque crea la capacidad del modelo, aquí puede definir las reglas de acceso para los roles.

Manual: http://www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and-cancan-customizing-devise-controllers/

Aquí puede encontrar las fuentes y wikies de ingenio y CanCan de:

https://github.com/plataformatec/devise

https://github.com/ryanb/cancan

Mis modelos se ve así:

papel.rb

class Role < ActiveRecord::Base 
    has_and_belongs_to_many :users 
end 

User.rb

class User < ActiveRecord::Base 
    has_many :accounts 
    has_and_belongs_to_many :roles 

    # Include default devise modules. Others available are: 
    # :token_authenticatable, :confirmable, :lockable and :timeoutable 
    devise :database_authenticatable, 
     :recoverable, :rememberable, :trackable, :validatable 

    # Setup accessible (or protected) attributes for your model 
    attr_accessible :email, :username, :password, :password_confirmation, :remember_me, :role_ids 

    def role?(role) 
    return !!self.roles.find_by_name(role.to_s.camelize) 
    end 

end 

Ability.rb

class Ability 
    include CanCan::Ability 

    def initialize(user) 
    user ||= User.new # guest user 

    if user.role? :administrator 
     can :manage, :all 
    elsif user.role? :operator 
     can :read, Account 
     can :read, Server 
    elsif user.role? :customer 
     can :manage, Account 
     can :read, Server 
    end 
    end 
end 

En el controlador debe agregar sólo estas dos líneas:

class YourController < ApplicationController 
    before_filter :authenticate_user! 
    load_and_authorize_resource 

    ... 

end 
+0

Esto hubiera sido mi sugerencia. Lo que me gusta de este enfoque es que fomenta la separación de la política comercial del resto de la lógica de la aplicación. –

+0

Sí, esta separación brinda buenas y flexibles habilidades. Lo utilicé en el único proyecto, donde los desarrolladores crearon un sistema de autenticación muy incómodo, donde para agregar nuevos roles y habilidades tuve que escribir mucho código en cada controlador y modelo. Pasé mucho tiempo eliminando el viejo sistema y cerca de dos horas para instalar y configurar Devise y CanCan. Ahora estoy feliz. Y cuando tenga tiempo libre, planeo escribir una interfaz de usuario para administrar roles y habilidades. Con estos sistemas, esta tarea se ha vuelto sencilla. –

+0

lo hemos usado en varias aplicaciones y también encontramos que la combinación de idear-cancán es el enfoque 'mejor de las razas'. Se está adoptando rápidamente por muchas organizaciones como estándar de este año para autenticación/autorización. –

2

Creo que no tiene que crear modelos diferentes porque no tiene campos específicos para cada uno. Entonces solo tienes que establecer el "papel" de cada Usuario. Dos opciones: crear una tabla de roles o agregar un campo de roles en la tabla Usuario. Ambas soluciones funcionan, la segunda es más flexible pero menos optimizada.

Pero, en su caso particular, no tiene una administración de funciones compleja para que pueda encontrar una solución más simple. Si todos sus usuarios son artistas, no tiene que especificar esto en su código, está contenido en la descripción implícita de lo que es un usuario. Así que solo tiene que guardar si un usuario es administrador o no y creo que la mejor solución es crear un campo booleano "is_admin".

Después de eso, tendrá que crear algún before_filter en sus controladores protegidas, así:

before_filter => :authorize, :only => :new, :edit, :create, :update, :destroy 

def authorize 
    redirect_to :root if not current_user.is_admin? 
end 

Y usted puede tener peticiones simples como que:

@artists = User.all 
@moderators = User.where(:is_admin => true) 

Si usted busca una mayor complete el sistema de autorización puede verificar esta pequeña joya: https://github.com/ryanb/cancan

Pero creo que no es el caso por el momento. Si tiene un problema simple, busque una solución simple.

+1

Los valores booleanos en AR producen métodos 'foo?' Que son geniales para los condicionales, y Ruby tiene un mejor 'si no' en la forma de' a menos'. Combinando los dos juntos: 'redirect_to: root a menos que current_user.is_admin?' – coreyward

+0

¡Buen comentario para el ayudante de ActiveRecord, no lo sabía! –

+0

+1 para soluciones simples. Lo bueno de ruby ​​es que puedes usar el campo booleano y mantener la interfaz 'is_admin?' Cuando cambias a un modelo de rol separado o algo más. –

2

Si usted necesita tener un código que sea específico y un rol o tal como un administrador o moderador, otra solución sería crear un modelo de usuario base del que todas las otras clases heredan. Luego puede crear una clase Admin y una clase Moderador que hereden del modelo de Usuario. Esto significa que puede evitar comprobar constantemente el rol de los usuarios en su código, p. current_user.do_some_admin_thing if current_user.is_admin?. Sus clases se vería algo como esto

class User < ActiveRecord::Base 
    # base user methods in here 
end 

class Moderator < User 
    def do_moderator_thing 
    # perform a moderator task 
    end 
end 

class Admin < Moderator 
    def do_admin_thing 
    # perform an admin task 
    end 
end 

En este caso, la clase de usuario tiene los privilegios más básicas, los moderadores pueden hacer los usuarios todo lo que pueden más los métodos y los administradores específicos de moderador pueden hacer los usuarios de todo y los moderadores pueden más el administrador específicos métodos.

Todas las diferentes funciones de usuario utilizarían la misma tabla en la base de datos, pero sus preocupaciones están claramente separadas en clases que evitan condicionamientos excesivos a través de su código comprobando qué función tiene el usuario todo el tiempo.

Crear usuarios nuevos sería sencillo también Admin.new :name => 'bob' La clase Admin se ocupa de cómo un usuario se define como un administrador que proporciona una interfaz agradable donde no necesita conocer el funcionamiento interno del sistema de roles para interactuar con usuarios.

+0

Edite su pregunta para que sea explícito sobre el hecho de que esto está usando herencia de tabla única y enlace a la documentación oficial de rieles. –

+0

La pregunta no habla sobre el comportamiento diferente para diferentes usuarios, solo diferentes autorizaciones para hacer cosas diferentes. A menos que la instancia de los modelos de Usuario realmente se comporte de manera diferente, es demasiado complejo crear diferentes subclases. El uso excesivo de la herencia es un antipatrón. – Winfield

1

Aunque estoy de acuerdo, la combinación de Devise y CanCan es potente y funciona. Veámoslo con una perspectiva diferente teniendo en cuenta la Asociación y la Delegación.

Asociación: En la programación orientada a objetos, asociación define una relación entre clases de objetos que permite a un objeto ejemplo para causar otro para realizar una acción en su nombre.

Delegación: La delegación permite que el comportamiento de un objeto sea definido en términos del comportamiento de otro objeto. El término 'delegación' se refiere a la delegación de responsabilidades. El principal énfasis de la delegación está en el mensaje que pasa donde un objeto podría delegar la responsabilidad de un mensaje que no podría manejar a los objetos que potencialmente podría (sus delegados).

Con eso, qué pasa si diseñamos nuestro Usuario y Funciones de esta manera. No existe una clase de Rol y el Usuario no hereda ni especializa una clase en particular (Artista, Administrador) sino que toda la clase (Función) contiene el objeto Usuario y delega. La forma en que estoy pensando y forma de implementar con Carriles es algo como esto:

class User < AR::Base 
    def user_method 
    end 
end 

class Artist < AR::Base 
    has_one :user 

    def artist_method 
    # perform an admin task 
    end 
end 

class Admin < AR::Base 
    has_one :user 

    def admin_method 
    # perform an admin task 
    end 
end 

Este role class model se describe por Francis G. Mossé en su artículo sobre Roles de modelado.

1

Esta es la configuración básica, para la gema declarative authorization, que uso. Pero podría usar esto como está sin la gema, si sus requisitos de autorización no son más que pedir el tipo de Roles que tiene el Usuario.

Requiere una tabla roles, y tal, para que no sea realmente su fantasía.

class Role < ActiveRecord::Base 
    belongs_to :user 
end 

class User < ActiveRecord::Base 
    has_many :roles 

    def role_symbols 
    roles.map { |r| r.title.to_sym } 
    end 

    def admin? 
    has_role?(:admin) 
    end 
    # include more role booleans or write some ruby magic to be DRY 
    # ... 

    def has_role?(r) 
    role_symbols.include?(r.to_sym) 
    end 
end 

# give or take 
user = User.new 
user.roles << Role.new :title => "admin" 
user.roles << Role.new :title => "artist" 

user.role_symbols # => [:admin, :artist] 
user.admin? # => true 
user.has_role?(:artist) # => true 
0

Puede tener dos modelos Usuario y Rol. Y el rol pertenece al usuario.

Especifique el rol de los usuarios (como admin, moderador) en el modelo de rol.

Cuestiones relacionadas