Rails 4 - No route matches PATCH on custom route - ruby-on-rails

I need a page for changing Profile of current user, it's weird if the url is /user/:id, so I map it to /settings
get "/settings", to: "users#edit", as: "settings_user"
But when I submit the form I got this error:
Routing Error
No route matches [PATCH] "/settings"
The weird part is if I press back and re-submit the form, it will submit just fine.
If I go to another page then back to the form, it will get error on first try but works fine on second try onward.
My controller:
class UsersController < ApplicationController
...
def edit
#user = current_user #this is the cache of currently logged in user
end
def update
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to settings_user_path, notice: "Profile has been saved"
end
end
private
def user_params
params.require(:user).permit(:id, :name, :email, :bio)
end
end
My view:
<%= form_for #user do |f| %>
...
<% end %>
Note:
Other page that are using the default route like my Product page works fine, so it's not the Rails config problem.

Devise
I guess you're using devise (by how you're using current_user) - so you may wish to look at Devise' custom routing paths. Although this won't provide a routing structure for your user object, it may come in handy some time:
#config/routes.rb
devise_for :users, path: "auth", path_names: { sign_in: 'login', sign_out: 'logout', password: 'secret', confirmation: 'verification', unlock: 'unblock', registration: 'register', sign_up: 'cmon_let_me_in' }
--
Routes
If you want to manage your user object, you'll be best using the resources route definition:
#config/routes.rb
resources :users, only: [], path: "" do
collection do
get :settings, action: :edit
match :settings, action :update, via: [:patch, :put]
end
end
The problem you have is your form is thinking it should send your update request to /settings too:
No route matches [PATCH] "/settings"
The way around this is to either provide a route for patch (as demonstrated above), OR define the url parameter of the form:
<%= form_for #user, url: your_update_path do |f| %>
--
Hope this helps?

This issue only occur on Chrome 37 Beta. I reverted back to Chrome 36 Release and everything works fine.
I guess I won't use the beta version for daily use ever again.

Related

Registration Form Debug & Post Issues

So I'm going to try and explain this to the best of my ability. I am taking a Rails tutorial and am a little stuck on the POST and Debug sections.
1st Question: I created a registration form. The tutorial said to click the "Register!" button to see what happens. Apparently nothing is supposed to happen except when I click the "Register!" button I get an error No route matches [POST] "/register". How do I fix that?
2nd Question:
We then added a debug function in the application.html.erb section which looks like this:
<% if ENV['RAILS_ENV'] == 'development' %>
<%= debug(params) %>
<% end %>
They said to try and create a user with the username: foo password: baz email: bar and see what happens. Apparently when I click register it's supposed to not change the page but just show some stuff in the debug function?
My debug function shows this until I click the register button and then it gives me the error No route matches [POST] "/register".
--- !ruby/hash:ActionController::Parameters
controller: users
action: register
when in the book it shows that you don't get the error No route matches [POST] "/register" but instead you get this text in your debug function...
--- !ruby/hash:HashWithIndifferentAccess
user: !ruby/hash:HashWithIndifferentAccess
screen_name: foo
password: baz
email: bar
commit: Register!
action: register
controller: users
Anyone have any idea what's going on here?
Just incase you want to know some of my code here it is:
Routes.rb
Rails.application.routes.draw do
get '/users', to: 'users#index'
get 'register', to: 'users#register'
get '/site', to: 'site#index'
get '/about', to: 'site#about'
get '/help', to: 'site#help'
resources :users, only: %w(index) do
get :register, on: :collection
end
root 'site#index'
Users.controller.rb
class UsersController < ApplicationController
def index
end
def register
#title = 'Register'
if request.post? and params[:user]
#user = User.new(params[:user])
if #user.save
render :text => 'Welcome to WorkLink!'
# Output goes to log file (log/development.login development mode)
logger.info params[:user].inspect
end
end
end
end
You did wrong with routing. You declare get method for register. But it should be post method.
You have to change your route to
post 'register', to: 'users#register'

Routing error after using :path option

I have a model called 'users' that I changed to 'people' in the url.
Routes.rb
resources :users, :path => "people"
Everything works fine except when creating a new user I get a routing error and it redirects to '/users', instead of creating the user and going to '/people/:id'.
No route matches [POST] "/users"
If I take
:path => "people"
out of the routes it works fine.
The form looks like:
<%= simple_form_for(#user) do |f| %>
and here is the controlller:
def create
#user = User.create(user_params)
if #user.save
redirect_to #user
else
redirect_to root_path
end
end
What is happening is in your route file, you are changing what the users route is routing to with your path: 'people' call.
However, since rails sees that the model you're creating is called User, it assumes that it should post that to /users.
While, I'm not completely familiar with simple_form, this works with normal rails:
<%= form_for #user, url: users_path do |f| %>
Notice the url: users_path option, what this does is explicitly link the form to the user path, aka /testers.
--Cheers

How to delete / destroy user in rails app from database?

I recently watched the railscast episode #250 Authentication from Scratch (revised) and I have the signup / login / logout actions working. However I am working on creating an action to delete a user from the database, but I am currently experiencing some errors when I try to delete a user.
The users_controller.rb delete / destroy actions look like the following,
def delete
# the below line calls the destroy method / action
self.destroy
end
def destroy
session[:user_id] = nil
# #user = User.find(params[:id])
#user.destroy
# User.find(parmas[:id]).destroy
# the below line didn't delete the current user :(
# #user = User.destroy
redirect_to :controller=>'users', :action => 'new'
end
The error message I'm getting in the browser when I try to delete a user looks like the following.
The page that contains the delete link looks like the following, index.html.erb
<h1>Welcome
<% if current_user %>
<%= current_user.email %>
<% end %>
</h1>
<p>You have <%= current_user.credit %> credits.</p>
<!-- http://stackoverflow.com/questions/5607155/ -->
<%= link_to('Delete your account', :controller => 'users', :action => 'destroy') %>
routes.rb
Rails.application.routes.draw do
# the below generated route is not necessary
# get 'sessions/new'
# delete user route
#get 'delete' => 'users#delete'
# shortened routes, per railscast comment
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
get 'logout' => 'sessions#destroy'
# get 'signup', to: 'users#new', :as 'signup'
# get 'login', to: 'sessions#new', :as 'login'
# get 'logout', to: 'sessions#destroy', :as 'logout'
resources :users
resources :sessions
root to: 'users#new'
# get 'users/new'
# the below line specifies JSON as the default API format
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
resources :users
end
end
It stands to reason you're getting a NoMethodError, since you've never set the #user variable, that line is commented out:
def destroy
session[:user_id] = nil
# #user = User.find(params[:id]) <-- Commenting out this line was your problem
#user.destroy
Changing to
def destroy
session[:user_id] = nil
#user = User.find(params[:id])
#user.destroy
You should be good to go.
EDIT: one thing you'd probably want to do is change from using the old style of link_to, specifying the controller and action, and change to the new style, using route helpers. In this case, you'd use, i believe, link_to 'Delete your account', current_user, :method => :delete, but you can check by running rake routes, where it will list the helpers available based on your routes.rb file.
Well, I think you should make things a bit simpler and start from the dummiest thing, that works. First of all, if you use your controller as a resource, there would not be a delete action there, only destroy.
def destroy
User.find(params[:id]).destroy
session[:user_id] = nil
redirect_to new_user_path
end
P.S. once again, I assume that you have set resources :users in your routes.rb.
If you have a bunch of get|post|put|delete routes instead, just make sure you point the redirect correctly.

Routing Error - custom controller

I have a has many through association.
Firms have many Users through Follows.
I want Users to be able to Follow Firms. - I am using Devise for the users.
I have the following action in my firms controller.
def follow
#firm.users << current_user
end
in my routes.rb
resources :firms do
post :follow, on: :member
end
and in my firms view
<%= link_to "Follow", follow_firm_path(#firm), method: :post %>
However when I keep getting the following Routing Error in the browser
No route matches {:action=>"follow", :controller=>"firms"}
Rake Routes confirms the following
follow_firm POST /firms/:id/follow(.:format) firms#follow
Any ideas what the problem may be?
Many thanks
Edit: Controller code
class FirmsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
def index
#firm_names = Firm.all.map &:name
direction = params[:direction]
direction ||= "ASC"
#firms = Firm.order("name #{direction}")
respond_to do |format|
format.html # index.html.erb
format.js
end
end
def follow
#firm.users << current_user
end
I am using the follow action in a partial in the index view.
everything looks good and this should work perfectly. Except that I see a typo in the following line
<%= link_to "Follow", follow_firm_path(#firm), method: :post %>
after the :method there should an => not a : . this will make the link a get request not a post request, that might be the issue, try using a simple link and replace post will get in your routes.rb just to test if the issue is arising due to this.
you can also test route methods from the console
rails c
app.follow_firm_path(2)
I noticed you also have an error in your routes, there should be an => not a : after :on
resources :firms do
post :follow, :on => member
end
You should define methods like this...
resources :firms do
collection
post :follow, on: :member
end
end
I think if this method does not create anything its type should be get.
Try it

Rails - Redirecting after Form Errors

I'm very new to rails, so please forgive my limited knowledge.
I have a controller called users. It has two methods: new and create.
When users#new is called, a form is shown to sign up for an account on my site. I have set up a route for this which makes the URL /signup, like so:
match "signup" => "users#new", :as => "signup"
When the user navigates to /signup, I create a new user instance variable and show them the form, like so:
UsersController
def new
#user = User.new
end
New View
<%= form_for #user do |f| %>
<!-- Form code here... -->
<!-- Then at the end: -->
<%= f.submit :value => 'Sign Up' %>
<% end %>
When the user submits this form, it sends the data to users#create.
My code for users#create in UsersController looks like so:
def create
#user = User.new(params[:user])
if #user.save
redirect_to root_url, :notice => 'Signed Up!'
else
render "new"
end
end
The if/else statement is to check if rails was able to create my new user or not. If it was, it redirects to the index no problem.
If it wasn't able to create the user, it renders my new view, and it displays the errors fine.
But, the URL it then gives to us is /users, because when it submits the form it submits to /users. How can I get it so if the signup fails, it will redirect to /signup, and still show the errors that occured?
UPDATE: routes.rb
Flightdb::Application.routes.draw do
get "users/new"
get "home/about"
get "home/index"
root :to => 'home#index'
match 'about' => 'home#about'
match "signup" => "users#new", :as => "signup"
resources :users
end
Well the answer you don't want to hear is that this usually isn't done. The semantics of the URLs aren't ideal either way. /new implies a fresh new form... but a form with errors is sort of a "partially created" user. The user will never need to use the URL in either case, so no functionality is lost.
Also, consider putting registration and authentication actions on an 'account' (singular) resource. the 'users' controller/resource should probably only be for a backend admin interface. if there are public proiles per user, put them on a 'profiles' resource. put the user's dashboard on a 'dashboard' controller (not a resource).
I've come across the very same issue today and based on Alex's and Marian's comments, I ended up with these changes:
1) in form view:
<%= form_for #user, url: signup_path do |f| %>
2) in routes.rb:
get "signup" => "users#new", :as => "signup"
post "signup" => "users#create"
resources :users
root :to => "home#index"
I'm a newbie in RoR so I'd welcome comments if there are any side-effect or issues. Or if there is some better way.
the route is indeed corrected this way, but the context of the corresponding controller action "users#new", such as variables that have been initialized by the action, is lost.
So we end up in a kind of unstable situation where we're neither in the "new" context nor outside of it...
How to control that context is the question ? Maybe through ActiveModel::Validator
I'm not sure where and how to alter this behaviour...

Resources