0

I have Devise 4.2.1 and Rails 5.0.1. I'm trying to use Devise sign_in in a controller other than registrations. There were a bunch of methods that weren't defined, so I had to add them as helpers:

module ApplicationHelper
  def resource_name
    :user
  end

  def resource
    @resource ||= User.new
  end

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

  def build_resource(hash=nil)
    self.resource = resource_class.new_with_session(hash || {}, session)
    # ^the source of the error^
  end

  def resource_class
    devise_mapping.to
  end
end

But now I'm getting the following error:

NoMethodError in Static#show
undefined method 'resource=' for (class)

I don't have "resource=" written anywhere in my code, certainly not on the line the error points to (marked above). Where is my server getting that error from?


Also, I think I'm just using the standard sign_in code:

<%
build_resource({})
set_minimum_password_length
yield resource if block_given?
respond_with self.resource
%>

<% form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>
  ...
Joe Morano
  • 1,715
  • 10
  • 50
  • 114

1 Answers1

3

I believe that your question has 2 answers: Why this error is happening, and how to have a sign_in partial to use on all your controllers:

Creating the sign_in partial

First of all, the sign_in method belongs to sessions, not registrations be careful to not replace the wrong controller :)

And you just added a few more code than needed for what you want. To create a partial sign_in to use anywhere, just use the default Devise form in it:

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

  <%= f.label :password %><br />
  <%= f.password_field :password, autocomplete: "off" %>

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

  <%= f.submit "Log in" %>
<% end %>

That part with build_resource({}) isn't needed, as it'll be handled by Devise itself when you submit the form. And since build_resource isn't needed, you just need the following code on your ApplicationHelper:

module ApplicationHelper
  def resource_name
    :user
  end

  def resource
    @resource ||= User.new
  end

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

This should be enough to have a sign_in form in any controller view. If you need more control over the login flow, you can check the Configuring Controller section on Devise Readme for more information on how to create a customizable controller.

Why your code throws a NoMethodError error

Your code throws an NoMethodError because you haven't defined a setter for the @resource instance variable. It should be either:

def resource=(value)
  @resource = value
end

or with attr_writer :resource

I recommend this question for more info on the topic: Why use Ruby's attr_accessor, attr_reader and attr_writer?

Community
  • 1
  • 1
Leonardo Prado
  • 598
  • 5
  • 12
  • As for me. When I added resource setter then application didn't recognise that. It treated that as normal local variable. Solution that works for me it is simply assignment `@resource = user` – mike927 May 10 '17 at 12:54