Criar formulário dentro de um controlador diferente


128

Estou usando uma gema de projeto para procedimentos sign_in / sign_out.

Gerei arquivos de visualizações a partir do dispositivo, usando rails g devise views

Vi que havia um arquivo devise / sessions / new.html.erb que continha um formulário para sign_in.

Criei outro arquivo devise / sessions / _form.html.erb e o fiz <%= render 'form' %>dentro de um arquivo new.html.erb, e isso funcionou muito bem.

Agora, eu queria incluir este formulário do controlador diferente. Assim, em um controlador chamado 'main', (especificamente, na página de visualização) 'mains / index.html.erb', incluí o <%= render 'devise/sessions/form' %>arquivo. Parece que a inclusão funcionou bem, mas estou recebendo o seguinte erro.

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 a parte form_for (resource, ...) está causando o problema (o que funciona bem se eu estiver na página original de sign_in do dispositivo ... Como posso resolver esse problema de maneira rails?

Pessoalmente, prefiro usar a função 'render' para incluir o formulário, em vez de escrever códigos html embutidos.

Preciso especificar algo (recurso) dentro do controlador 'principal'?

Agradeço sua ajuda. Obrigado.


Existe alguma solução ...? A partir de novembro / 16, eu realmente não tenho a solução usando render .. embora se eu apenas digitar o código embutido, ele funciona bem, parece ...
user482594

Você encontrou uma solução para isso ?
neebz

Sim, escolhi a resposta que resolve o meu problema. Era mais simples do que eu pensava.
user482594

Respostas:


240

Como Andres diz, o formulário chama os auxiliares especificados pelo Devise e, portanto, não estão presentes quando você acessa um formulário do Devise a partir de um controlador não-Devise.

Para contornar isso, você precisa adicionar os seguintes métodos à classe auxiliar do controlador em que deseja exibir o formulário. Como alternativa, você pode adicioná-los ao auxiliar de aplicativos para disponibilizá-los em qualquer lugar.

  def resource_name
    :user
  end

  def resource
    @resource ||= User.new
  end

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

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


6
Excelente. Verifique se ele entra no auxiliar, não no controlador. Além disso, isso pode levar a problemas enormes se você tiver outros recursos (por exemplo, empresas que também podem fazer login) e desejar carregar o formulário. Certifique-se de redefinir os nomes, e o roteamento também pode se tornar um problema.
Michael Schmitz

1
O ruim dessa solução é que ela quebra inherited_resources.
Jrhorn424 #

6
Para limitar o escopo desses métodos (e evitar conflitos de namespace com outras gemas, por exemplo), tente adicionar os métodos acima ao próprio controlador, juntamente com helper_method :resource_name, :resource_class, :resource, :devise_mapping(o que :resource_classparece ser um requisito nas versões mais recentes do Devise).
spume 03/02

1
Qual solução deveria ser se tivermos poucos modelos de dispositivos?
yozzz

Eu tenho dois modelos Devise e preciso fazer login para ambos na página inicial. Alguma idéia de como fazer algo semelhante à sua resposta?
DR_

8

Pode tentar isso também ... verifique esta pergunta .

Fonte

<%= 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 %> 

Essa não é a melhor prática de todas as respostas?
allegutta

4

O formulário que você criou funciona quando renderizado a partir de um controlador Devise porque "recurso" é definido por meio do Devise. Dê uma olhada na implementação do Devise SessionsController - pelo que entendi, você está tentando replicar a "nova" ação. O método "build_resource" é provavelmente o que você está procurando.

A gema Warden é a origem dos objetos "recursos". Se você quiser ir mais fundo, esse seria o lugar para procurar.


Acabei de chamar 'build_resource' com em um mains_controller, mas ele chama [variável local indefinida ou método `build_resource '] de erro. Tentei incluindo conceber auxiliar interno através da inserção de 'incluem conceber :: Controllers :: InternalHelpers' no topo do 'mains_controller', mas ele também chama de erro com 'AbstractController :: ActionNotFound'
user482594

3

Para refinar a resposta aceita, usamos esse auxiliar 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

onde admin_controller?está algo que temos de antes no ApplicationControllerpara lidar com redirecionamentos de login:

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

2

Eu estava recebendo o mesmo erro que undefined local variable or method "resource"você descreveu em um dos meus controladores, porque estava faltando na minha classe base do controlador (Rails-API ActionController :: API estava com falha):

include ActionController::Helpers

Portanto, os métodos auxiliares do Devise não puderam ser resolvidos na exibição.

Para fazer o Devise funcionar com a API do Rails, eu precisava incluir:

class ApplicationController < ActionController::API

  include AbstractController::Rendering
  include AbstractController::Layouts
  include ActionController::MimeResponds
  include AbstractController::Translation
  include ActionController::ImplicitRender
  include ActionController::Helpers
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.