Devise render sign => up/in form partials elsewhere in code
E

3

6

I'm just starting with Devise and Rails3. I have the Authenetication down and working and understand the basics.

As of now in my Home Controller that represents my Home/Front Page i have two links one that links to Register => sign_up and one that changes depending on login/logout => sign_in/sign_out.

However i dont want to redirect my user to login page. Instead i want to display my login form on my front page. So i have seperated the devise/session/new template int to a view and a _form.html.erb partial.

And now in my home view i render the login form as so:

<% if user_signed_in? %>
    Welcome: <b><%= current_user.username %> (<%= current_user.group.name %>)</b>
    <%= link_to "Logout", destroy_user_session_path, :method => 'delete' %>
<% else %>
    <%= render 'devise/sessions/form' %> // Rendering the partial here
    <%= link_to "Login", new_user_session_path %>
<% end %>
<hr>

This is the code of the partial:

<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
  <div><%= f.label :email %><br />
  <%= f.email_field :email, :autofocus => true %></div>

  <div><%= f.label :password %><br />
  <%= f.password_field :password %></div>

  <% if devise_mapping.rememberable? -%>
    <div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
  <% end -%>

  <div><%= f.submit "Sign in" %></div>
<% end %>

My error is as follows:

NameError in Home#index

Showing devise/sessions/_form.html.erb where line #1 raised:

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

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

I understand why the error happens. It's because the partial it not being given the resource attribute. I used dump(resource) and it turns out it's a User model/object So i added the following before it:

<% if @user %>
   <% resource = @user %>
<% end %>

And added following to my Home controller index method:

def index
   @user = User.new
end

However after that i get resource_name error that turns out to simply be :user and if i set that then i get a problem because of devise_mapping.rememberable? which i dont know how to provide.

I want to do this properly so i want to avoid messy and unlogical approach that i started.

Eldrida answered 11/3, 2013 at 20:55 Comment(0)
J
20

Take a look at the answer to this question: Devise form within a different controller

The form you are attempting to render with your Home controller relies on helpers defined by Devise that are not accessible from a non-Devise controller.

Adding the necessary helpers to your home_helper.rb should solve your problem:

def resource_name
:user
end

def resource
@resource ||= User.new
end

def devise_mapping
@devise_mapping ||= Devise.mappings[:user]
end
Jumbo answered 11/3, 2013 at 22:1 Comment(0)
O
4

I'm using Devise 3.5.1 and I had to add resource_class as well to get the login form working on a different controller.

I added it to application_helper.rb so it applies to all of my controllers.

def resource_name
  :user
end

def resource
  @resource ||= User.new
end

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

def resource_class
  devise_mapping.to
end
Onetime answered 30/7, 2015 at 12:59 Comment(0)
G
0

I can't comment on the accepted answer due to low rep, but I just uncovered a gnarly bug with that approach (Rails 7.1.3 with Devise 4.9.3). If you define resource like the answer states in your application_helper.rb, it will hide Devise's implementation of

def resource
  instance_variable_get(:"@#{resource_name}")
end

In most cases this will still work. In my use case, it created a major bug with users signing up, in that the flow creates a new user instance, but does NOT store it in the instance variable (self.resource) that DeviseControllers all rely on.

This will most likely manifest with a "Email can't be blank" or "Password can't be blank" error on the front end, even though you can see your params being passed in and filtered correctly before Devise tries to build_resource(sign_up_params) and then very oddly comes through with resource being there structurally, but all its fields are empty.

Removing the resource helper define solved this. I actually removed all the helpers with the exception of

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

The @devise_mapping ||= request.env["devise.mapping"] used in Devise's code also didn't work for me outside of a DeviseController, so I stuck with the static hardcoded approach.

Took me two days to figure this out.

However, now you have another possible problem. let's say you have a sign in form in a partial (such as a nav bar on a landing page which is a very common design pattern) that is not rendered by a DeviseController. This will then error in the erb syntax without resource in your helper.

In my case, I solved this by just "hard coding" my resource and resource_name in that partial's form, because I can't use a DeviseController inheritance for the main site controller.

Gon answered 23/1 at 20:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.