Diseñe la forma dentro de un controlador diferente

128

Estoy usando una gema de diseño para los procedimientos de inicio de sesión / inicio de sesión.

Genere archivos de vistas desde el dispositivo, usando rails g devise views

Vi que había un archivo de idear / sessions / new.html.erb que contenía un formulario para sign_in.

Creé otro archivo idear / sessions / _form.html.erb y lo hice <%= render 'form' %>dentro de un nuevo archivo.html.erb, y funcionó muy bien.

Ahora, quería incluir este formulario desde el controlador diferente. Entonces, en un controlador llamado 'main', (específicamente, dentro de la página de vista) 'mains / index.html.erb' incluí el <%= render 'devise/sessions/form' %>archivo. Parece que la inclusión funcionó bien, pero recibo el siguiente error.

NameError in Mains#index

Showing /home/administrator/Ruby/site_v4_ruby/app/views/devise/sessions/_form.html.erb where line #1 raised:

undefined local variable or method `resource' for #<#<Class:0x007f1aa042d530>:0x007f1aa042b870>
Extracted source (around line #1):

1: <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
2:   <p><%= f.label :email %><br />
3:   <%= f.text_field :email %></p>
4: 

Parece que la parte form_for (recurso, ...) está causando el problema (que funciona bien si estoy en la página de inicio de sesión del dispositivo original ... ¿Cómo puedo resolver este problema en forma de rieles?

Personalmente prefiero usar la función 'render' para incluir el formulario, en lugar de escribir códigos html en línea.

¿Tengo que especificar algo (recurso) dentro del controlador 'principal'?

Apreciaré su ayuda. Gracias.

usuario482594
fuente
Hay alguna solución...? A partir de Nov / 16 realmente no he conseguido la solución usar render .. aunque si sólo tiene que escribir el código en línea, que funciona bien parece ..
user482594
¿Encontraste una solución para esto?
neebz
Sí, elegí la respuesta que resuelve mi problema. Era más simple de lo que había pensado.
user482594

Respuestas:

240

Como dice Andrés, el formulario llama a los ayudantes especificados por Devise y, por lo tanto, no están presentes cuando accede a un formulario de Devise desde un controlador que no es Devise.

Para evitar esto, debe agregar los siguientes métodos a la clase auxiliar del controlador en el que desea mostrar el formulario. Alternativamente, puede agregarlos a su aplicación auxiliar para que estén disponibles en cualquier lugar.

  def resource_name
    :user
  end

  def resource
    @resource ||= User.new
  end

  def devise_mapping
    @devise_mapping ||= Devise.mappings[:user]
  end

Fuente: http://pupeno.com/blog/show-a-devise-log-in-form-in-another-page/

Rupert Madden-Abbott
fuente
66
Excelente. Asegúrese de que va en el ayudante, no en el controlador. Además, esto podría generar grandes problemas si tiene otros recursos (por ejemplo, compañías que también pueden iniciar sesión) y desea cargar su formulario. Asegúrese de redefinir los nombres, y la ruta también podría convertirse en un problema.
Michael Schmitz
1
Lo malo de esta solución es que se rompe inherited_resources.
jrhorn424
66
Para limitar el alcance de estos métodos (y evitar conflictos de espacio de nombres con otras gemas, por ejemplo), intente agregar los métodos anteriores al controlador en sí, junto con helper_method :resource_name, :resource_class, :resource, :devise_mapping( :resource_classparece ser un requisito en las versiones más nuevas de Devise).
Espuma
1
¿Qué solución debería ser si tenemos pocos modelos de diseño?
yozzz
Tengo dos modelos de Devise y necesito iniciar sesión para ambos en la página de inicio. ¿Alguna idea de cómo hacer algo similar a tu respuesta?
DR_
8

Puede probar esto también ... verifique esta pregunta .

Fuente

<%= form_for("user", :url => user_session_path) do |f| %>
  <%= f.text_field :email %>
  <%= f.password_field :password %>
  <%= f.check_box :remember_me %>
  <%= f.label :remember_me %>
  <%= f.submit 'Sign in' %>
  <%= link_to "Forgot your password?", new_password_path('user') %>
<% end %> 
jsp
fuente
¿No es esta la mejor práctica de todas las respuestas?
allegutta
4

El formulario que creó funciona cuando se representa desde un controlador Devise porque "recurso" se define a través de Devise. Eche un vistazo a la implementación de Devise SessionsController : por lo que entiendo, está intentando replicar la "nueva" acción. El método "build_resource" es probablemente lo que está buscando.

La gema Warden es de donde provienen los objetos de "recurso". Si desea profundizar, ese sería el lugar para buscar.

Andres Freyria
fuente
Acabo de llamar 'build_resource' con un controlador de red principal, pero indica un error [variable local indefinida o método 'build_resource']. Intenté incluir el asistente interno de diseño insertando 'include Devise :: Controllers :: InternalHelpers' en la parte superior de 'mains_controller' pero también indica un error con 'AbstractController :: ActionNotFound'
user482594
3

Para refinar la respuesta aceptada, utilizamos este ayudante para permitir diferentes tipos de recursos:

def resource_name
  @resource_name ||= if admin_controller?
    :admin_user
  else
    :user
  end
end

def resource
  @resource ||= resource_name.to_s.classify.constantize.new
end

def devise_mapping
  @devise_mapping ||= Devise.mappings[resource_name]
end

¿De dónde admin_controller?es algo que tenemos antes ApplicationControllerpara manejar las redirecciones de inicio de sesión?

def admin_controller?
  !devise_controller? and request.path =~ /^\/admin/
end
helper_method :admin_controller?
bbozo
fuente
2

Recibí el mismo error que undefined local variable or method "resource"usted describe de uno de mis controladores, porque a mi clase base de controlador le faltaba lo siguiente (Rails-API ActionController :: API tenía la culpa):

include ActionController::Helpers

Por lo tanto, los métodos auxiliares de Devise no se pudieron resolver en la vista.

Para que Devise funcione con Rails-API, necesitaba incluir:

class ApplicationController < ActionController::API

  include AbstractController::Rendering
  include AbstractController::Layouts
  include ActionController::MimeResponds
  include AbstractController::Translation
  include ActionController::ImplicitRender
  include ActionController::Helpers
Christopher Oezbek
fuente