Devise form within a different controller
Asked Answered
F

5

131

I am using a devise gem for sign_in/sign_out procedures.

I generated views files from devise, using rails g devise views

I saw there was a devise/sessions/new.html.erb file which contained a form for sign_in.

I created another file devise/sessions/_form.html.erb and did <%= render 'form' %> within a new.html.erb file, and that worked out very fine.

Now, I wanted to include this form from the different controller. So in a controller called 'main', (specifically, within view page) 'mains/index.html.erb' I included <%= render 'devise/sessions/form' %> file. It seems that inclusion worked fine, but I am getting the following 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: 

It seems that form_for(resource,...) part is causing the problem (which works fine if I am on the original devise sign_in page... How can I resolve this problem in rails way?

I personally prefer to use 'render' function to include the form, rather than writing html codes inline.

Do I have to specify something (resource) within the 'main' controller?

I will appreciate your help. Thank you.

Flavoprotein answered 2/11, 2010 at 20:18 Comment(2)
Is there any solution...? As of Nov/16 I haven't really got the solution using render.. although if I just type in inline code, it works fine it seems..Flavoprotein
Yes, I chose the answer which resolves my problem. It was simpler than I had thought.Flavoprotein
T
251

As Andres says, the form calls helpers which are specified by Devise and so aren't present when you access a Devise form from a non-Devise controller.

To get around this, you need to add the following methods to the helper class of the controller you wish to display the form under. Alternatively, you can just add them to your application helper to make them available anywhere.

  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/

Typewriter answered 18/6, 2011 at 0:48 Comment(5)
Excellent. Make sure it goes in the helper, not in the controller. Also, this might lead to huge problems if you have other resources (e.g. companies that can also log in) and you want to load their form. Make sure to redefine the names, and the routing might become a problem as well.Gazo
The bad thing about this solution is that it breaks inherited_resources.Juxtapose
To limit the scope of these methods (and avoid namespace conflict with other gems, for example), try adding the above methods to the controller itself, along with helper_method :resource_name, :resource_class, :resource, :devise_mapping (the :resource_class seems to be a requirement in newer Devise versions).Rushy
What solution should be if we have few devise models?Cappello
I have two Devise models and need login for both on the homepage. Any idea how to do something similar to your answer?Spalla
H
8

Can try this also...check this question.

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 %> 
Harner answered 26/3, 2013 at 2:43 Comment(1)
Isn't this the best practise of all the answers?Putandtake
I
4

The form you created works when rendered from a Devise controller because "resource" is defined through Devise. Take a look at the implementation of the Devise SessionsController - from what I understand, you're attempting to replicate the "new" action. The method "build_resource" is probably what you're looking after.

The Warden gem is where the "resource" objects are coming from. If you wish to dig deeper, that'd be the place to look.

Impulse answered 2/11, 2010 at 22:16 Comment(1)
I just called 'build_resource' with in a mains_controller, but it calls out [undefined local variable or method `build_resource'] error. I tried including devise internal helper by inserting 'include Devise::Controllers::InternalHelpers' at the top of the 'mains_controller' but it also calls out error with 'AbstractController::ActionNotFound'Flavoprotein
C
3

To refine on the accepted answer, we use this helper to allow different types of resources:

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

where admin_controller? is something we have from before in the ApplicationController to handle login redirects:

def admin_controller?
  !devise_controller? and request.path =~ /^\/admin/
end
helper_method :admin_controller?
Colbycolbye answered 16/12, 2015 at 8:6 Comment(0)
J
2

I was getting the same error undefined local variable or method "resource" you describe from one of my controllers, because my controller base class was missing the following (Rails-API ActionController::API was at fault):

include ActionController::Helpers

Thus the helper methods from Devise could not be resolved in the view.

To make Devise work with Rails-API I needed to include:

class ApplicationController < ActionController::API

  include AbstractController::Rendering
  include AbstractController::Layouts
  include ActionController::MimeResponds
  include AbstractController::Translation
  include ActionController::ImplicitRender
  include ActionController::Helpers
Janitress answered 21/4, 2015 at 22:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.