Concevoir un formulaire dans un contrôleur différent

129

J'utilise un joyau de devise pour les procédures sign_in / sign_out.

J'ai généré des fichiers de vues à partir de l'appareil, en utilisant rails g devise views

J'ai vu qu'il y avait un fichier devise / sessions / new.html.erb qui contenait un formulaire pour sign_in.

J'ai créé un autre fichier devise / sessions / _form.html.erb et l'ai fait <%= render 'form' %>dans un fichier new.html.erb, et cela a très bien fonctionné.

Maintenant, je voulais inclure ce formulaire des différents contrôleurs. Donc, dans un contrôleur appelé «main», (en particulier, dans la page de vue) «mains / index.html.erb» j'ai inclus le <%= render 'devise/sessions/form' %>fichier. Il semble que l'inclusion a bien fonctionné, mais j'obtiens l'erreur suivante.

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: 

Il semble que la partie form_for (resource, ...) soit à l'origine du problème (ce qui fonctionne bien si je suis sur la page sign_in du périphérique d'origine ... Comment puis-je résoudre ce problème de manière rails?

Personnellement, je préfère utiliser la fonction «render» pour inclure le formulaire, plutôt que d'écrire des codes html en ligne.

Dois-je spécifier quelque chose (ressource) dans le contrôleur «principal»?

J'apprécierai votre aide. Je vous remercie.

user482594
la source
Y-a-t'il une solution...? Depuis le 16 novembre, je n'ai pas vraiment la solution utilisant le rendu .. bien que si je
saisis
Avez-vous trouvé une solution pour cela ?
neebz
Oui, j'ai choisi la réponse qui résout mon problème. C'était plus simple que je ne l'avais pensé.
user482594

Réponses:

241

Comme le dit Andres, le formulaire appelle des helpers qui sont spécifiés par Devise et qui ne sont donc pas présents lorsque vous accédez à un formulaire Devise à partir d'un contrôleur non-Devise.

Pour contourner ce problème, vous devez ajouter les méthodes suivantes à la classe d'assistance du contrôleur sous lequel vous souhaitez afficher le formulaire. Alternativement, vous pouvez simplement les ajouter à votre assistant d'application pour les rendre disponibles n'importe où.

  def resource_name
    :user
  end

  def resource
    @resource ||= User.new
  end

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

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

Rupert Madden-Abbott
la source
6
Excellent. Assurez-vous qu'il va dans l'assistant, pas dans le contrôleur. En outre, cela peut entraîner d'énormes problèmes si vous avez d'autres ressources (par exemple des entreprises qui peuvent également se connecter) et que vous souhaitez charger leur formulaire. Assurez-vous de redéfinir les noms, et le routage pourrait également devenir un problème.
Michael Schmitz
1
La mauvaise chose à propos de cette solution est qu'elle casse inherited_resources.
jrhorn424
6
Pour limiter la portée de ces méthodes (et éviter les conflits d'espace de noms avec d'autres gemmes, par exemple), essayez d'ajouter les méthodes ci-dessus au contrôleur lui-même, avec helper_method :resource_name, :resource_class, :resource, :devise_mapping(cela :resource_classsemble être une exigence dans les nouvelles versions de Devise).
spume le
1
Quelle solution devrait être si nous avons peu de modèles de conception?
yozzz
J'ai deux modèles Devise et j'ai besoin d'une connexion pour les deux sur la page d'accueil. Une idée de comment faire quelque chose de similaire à votre réponse?
DR_
8

Peut essayer ceci aussi ... cochez cette question .

La source

<%= 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
la source
N'est-ce pas la meilleure pratique de toutes les réponses?
allegutta
4

Le formulaire que vous avez créé fonctionne lorsqu'il est rendu à partir d'un contrôleur Devise car la "ressource" est définie via Devise. Jetez un œil à l'implémentation de Devise SessionsController - d'après ce que je comprends, vous essayez de répliquer la "nouvelle" action. La méthode "build_resource" est probablement ce que vous recherchez.

La gemme Warden est la provenance des objets «ressources». Si vous souhaitez creuser plus profondément, ce serait l'endroit où chercher.

Andres Freyria
la source
Je viens d'appeler 'build_resource' avec dans un main_controller, mais cela appelle une erreur [variable locale non définie ou méthode `build_resource ']. J'ai essayé d'inclure un assistant interne de conception en insérant 'include Devise :: Controllers :: InternalHelpers' en haut de 'mains_controller' mais cela appelle également une erreur avec 'AbstractController :: ActionNotFound'
user482594
3

Pour affiner la réponse acceptée, nous utilisons cet assistant pour autoriser différents types de ressources:

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

admin_controller?est quelque chose d'avant dans la ApplicationControllergestion des redirections de connexion:

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

J'obtenais la même erreur que undefined local variable or method "resource"vous décrivez de l'un de mes contrôleurs, car ma classe de base de contrôleur manquait ce qui suit (Rails-API ActionController :: API était en faute):

include ActionController::Helpers

Ainsi, les méthodes d'assistance de Devise n'ont pas pu être résolues dans la vue.

Pour que Devise fonctionne avec Rails-API, je devais inclure:

class ApplicationController < ActionController::API

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