9

Tengo un problema al obtener Devise para que funcione de la manera que me gustaría con la herencia de tabla única.Rieles: Uso de Devise con herencia de tabla única

que tienen dos tipos diferentes de cuenta organizados de la siguiente manera:

class Account < ActiveRecord::Base 
    devise :database_authenticatable, :registerable 
end 

class User < Account 
end 

class Company < Account 
end 

Tengo las siguientes rutas:

devise_for :account, :user, :company 

Los usuarios se registren en /user/sign_up y las empresas se registren en /company/sign_up. Todos los usuarios inician sesión usando un único formulario en /account/sign_in (Account es la clase principal).

Sin embargo, iniciar sesión a través de este formulario solo parece autenticarlos para el alcance Account. Las solicitudes posteriores a acciones como /user/edit o /company/edit dirigen al usuario a la pantalla de inicio de sesión para el alcance correspondiente.

¿Cómo puedo lograr que Devise reconozca la cuenta 'tipo' y las autentique para el alcance correspondiente?

Cualquier sugerencia muy apreciada.

Respuesta

8

Acabo de encontrarme con el escenario exacto (con nombres de clase cambiado) como se indica en la pregunta. Aquí está mi solución (2.2.3 Idear, rieles 3.2.13):

en config/routes.rb:

devise_for :accounts, :controllers => { :sessions => 'sessions' }, :skip => :registrations 
devise_for :users, :companies, :skip => :sessions 

en app/controllers/sessions_controller.rb:

class SessionsController < Devise::SessionsController 
    def create 
     rtn = super 
     sign_in(resource.type.underscore, resource.type.constantize.send(:find, resource.id)) unless resource.type.nil? 
     rtn 
    end 
end 

Nota : dado que su clase Accounts seguirá siendo: registrable, los enlaces predeterminados en views/idear/shared/_links.erb intentarán emitirse, pero new_registration_path (Accounts) no funcionará (lo omitiremos en el dibujo de la ruta) y causará un error. Deberá generar las vistas de diseño y eliminarlas manualmente.

Sombrero-punta a https://groups.google.com/forum/?fromgroups=#!topic/plataformatec-devise/s4Gg3BjhG0E para señalarme en la dirección correcta.

+0

Lo usé y obtengo el error NoMethodError (método indefinido 'tipo' ... En la línea sign_in (resource.type ... ¿Qué debo hacer para cambiar esto? – Kevin

+0

Supongo que solo hago una columna de cadena en el tipo de nombre de la cuenta? Y configurarlo para el nombre del modelo? – Kevin

+0

Eso sería mi suposición también. ActiveRecord STI espera que. –

0

tratar de cambiar las rutas de este modo:
devise_for: cuentas,: usuarios,: empresas
porque Diseñar usa nombres plurales de sus recursos

Por favor, hágamelo saber si le puede ayudar

+0

Gracias por su sugerencia. Desafortunadamente, esto no resolvió el problema. Iniciar sesión mediante '/ accounts/sign_in' todavía no me permite acceder a'/users/edit' o '/ companies/edit'. – gjb

1

No creo que esto sea posible sin anular el controlador de sesiones. Cada página de inicio de sesión tiene un alcance específico que el dispositivo se autenticará según lo definido por sus rutas.

Puede ser posible utilizar la misma página de inicio de sesión para múltiples ámbitos de usuario utilizando la función devise_scope en su archivo de rutas para obligar tanto a usuarios como a empresas a utilizar la misma página de inicio de sesión (se puede encontrar un instructivo) here), pero estoy bastante seguro de que tendría que modificar su controlador de sesiones para hacer alguna lógica personalizada para determinar qué tipo de usuario inicia sesión.

+0

@gjb ¿Cómo fue capaz de manejar esto? ¿Has encontrado una mejor solución? –

15

Hay una manera fácil de manejar STI en las rutas.

Digamos que usted tiene los siguientes modelos: ITS

def Account < ActiveRecord::Base 
# put the devise stuff here 
devise :database_authenticatable, :registerable, 
    :recoverable, :rememberable, :trackable, :validatable 
end 

def User < Account 
end 

def Company < Account 

Un método que se suele pasar por alto es que se puede especificar un bloque en el método autenticado en su archivo routes.rb:

## config/routes.rb 

devise_for :accounts, :skip => :registrations 
devise_for :users, :companies, :skip => :sessions 

# routes for all users 
authenticated :account do 
end 

# routes only for users 
authenticated :user, lambda {|u| u.type == "User"} do 
end 

# routes only for companies 
authenticated :user, lambda {|u| u.type == "Company"} do 
end 

Para obtener los diversos métodos de ayuda como "usuario_actual" y "usuario_auténtico". ("Current_account" y "authenticate_account!" Ya están definidos) sin tener que definir un método independiente para cada uno (que rápidamente se convierte en imposible de mantener a medida que se añaden más tipos de usuarios), puede definir los métodos de ayuda dinámicos en su ApplicationController:

## controllers/application_controller.rb 
def ApplicationController < ActionController::Base 
    %w(User Company).each do |k| 
    define_method "current_#{k.underscore}" do 
     current_account if current_account.is_a?(k.constantize) 
    end 

    define_method "authenticate_#{k.underscore}!" do 
    |opts={}| send("current_#{k.underscore}") || not_authorized 
    end 
    end 
end 

Así es como resolví los raíles idear el problema de las ITS.

+0

No debería: usuario ser: empresa en esta línea de código? '' '# rutas solo para empresas authenticated: user, lambda {| u | u.type == "Company"} do end '' ' – MDekker

Cuestiones relacionadas