BB500
BB500

Reputation: 559

Rails 4 Devise Routing Error on user action

I have Devise authentication setup and working, and I've redirected the user to the user's own show page immediately after sign up or login. The user show page and user edit page can be accessed successfully in the browser at:

myapp.com/users/1 and myapp.com/users/1/edit

since I've setup a Users Controller - Now I need to simply take the action in devise that normally occurs at myapp.com/users/edit

edit_user_registration GET /users/edit(.:format)  devise/registrations#edit

...which is essentially the edit user account functionality, and I need to make it occur instead at users/:id/edit. When I access the users/1/edit page for my user and update the email or password and click 'update'...the url changes to myapp.com/users/update_account and I get the following error:

Unknown action
The action 'update' could not be found for UsersController

config/routes.rb

devise_for :users

  resources :users

  resources :users, only: [:edit] do
    collection do
      patch 'update'
    end
  end

  root                'static_pages#home'

  get '/users/:id', :to => 'users#show'
  get '/users/:id/edit', :to => 'users#edit'

  get '/help',    to: 'static_pages#help'
  get '/about',   to: 'static_pages#about'

rake routes provides:

Prefix Verb   URI Pattern                    Controller#Action
        new_user_session GET    /users/sign_in(.:format)       devise/sessions#new
            user_session POST   /users/sign_in(.:format)       devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)      devise/sessions#destroy
           user_password POST   /users/password(.:format)      devise/passwords#create
       new_user_password GET    /users/password/new(.:format)  devise/passwords#new
      edit_user_password GET    /users/password/edit(.:format) devise/passwords#edit
                         PATCH  /users/password(.:format)      devise/passwords#update
                         PUT    /users/password(.:format)      devise/passwords#update
cancel_user_registration GET    /users/cancel(.:format)        devise/registrations#cancel
       user_registration POST   /users(.:format)               devise/registrations#create
   new_user_registration GET    /users/sign_up(.:format)       devise/registrations#new
  edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit
                         PATCH  /users(.:format)               devise/registrations#update
                         PUT    /users(.:format)               devise/registrations#update
                         DELETE /users(.:format)               devise/registrations#destroy
                   users PATCH  /users/update(.:format)        users#update
                         GET    /users(.:format)               users#index
                         POST   /users(.:format)               users#create
                new_user GET    /users/new(.:format)           users#new
               edit_user GET    /users/:id/edit(.:format)      users#edit
                    user GET    /users/:id(.:format)           users#show
                         PATCH  /users/:id(.:format)           users#update
                         PUT    /users/:id(.:format)           users#update
                         DELETE /users/:id(.:format)           users#destroy
                    root GET    /                              static_pages#home
                    help GET    /help(.:format)                static_pages#help

My Header Links to the user profile and account settings pages:

views/layouts/_navigation_links.html.erb

<% if user_signed_in? %>
<div class="dropdown"">
  <li class="dropdown-toggle" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
   <%= current_user.email %>
   <span class="caret"></span>
  </li>
  <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
         <li><%= link_to 'My Profile', user_path %></li>
    <li><%= link_to 'Account Settings', edit_user_path %></li>
    <li><a href="#">Edit Profile</a></li>
    <li role="separator" class="divider"></li>
        <li><%= link_to 'Log out', destroy_user_session_path, method: :delete %></li>
  </ul>
</div>
<% elsif %>
    <li><%= link_to "Sign Up", new_user_registration_path %></li>
    <li><%= link_to "Sign In", new_user_session_path %></li>
<% end %>

My Users Controller:

class UsersController < ApplicationController
  before_filter :authenticate_user!

  def edit
    @user = current_user
  end

  def update
    @user = User.find(current_user.id)
    if @user.update_with_password(user_params)
    # Sign in the user by passing validation in case their password changed
      sign_in @user, :bypass => true
      redirect_to @user
    else
      render "edit"
    end
  end

    private

    def user_params
      params.require(:user).permit(:email, :password, :password_confirmation, :current_password)
    end

end

My Views/Users/Edit.html.erb

<% provide(:title, "Edit user") %> 

  <div class="container middle">

    <!-- SideBar NEED TO REFACTOR TO A USER LAYOUT FILE -->
    <div class="sidebar col-md-3">
    </div>

    <div class="main-content col-md-9">

      <div class="main-breadcrumb">
        Some Content
      </div>

      <div class="section_header">
          <h3>Edit Account</h3>
      </div>

      <div class="row-fluid">
        <div class="col-md-6">
        <%= form_for(@user, :url => { :action => "update" } ) do |f| %>

          <div class="field">
            <%= f.label :email %><br />
            <%= f.email_field :email, autofocus: true %>
        </div>

         <div class="field">
           <%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
           <%= f.password_field :password, autocomplete: "off" %>
         </div>

        <div class="field">
           <%= f.label :password_confirmation %><br />
           <%= f.password_field :password_confirmation, autocomplete: "off" %>
        </div>

         <div class="field">
           <%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
           <%= f.password_field :current_password, autocomplete: "off" %>
          </div>

          <div class="actions">
           <%= f.submit "Update" %>
          </div>
        <% end %>

        <h3>Cancel my account</h3>
         # I removed the devise 'cancel account' functionality for now

        <%= link_to "Back", :back %>
        </div>
      </div>

    </div><!-- end main content section -->

  </div><!-- end Container -->

Any help on how to fix this error would be appreciated.

Upvotes: 0

Views: 563

Answers (1)

PJSCopeland
PJSCopeland

Reputation: 3006

The browser is sending PATCH /users/update_account, which looks like what you want. However, the first line in rake routes that matches is:

PATCH  /users/:id(.:format)  users#update

... which is not what you want.

You've got resources :users twice in config/routes.rb; you should only have it once. Try this:

resources :users do
  collection do
    patch 'update_account'
  end
end

This will generate all the standard routes for users, as your top line currently does, but also /users/update_account - I think before all the standard ones.

Upvotes: 1

Related Questions