Registration Form Debug & Post Issues - ruby-on-rails

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'

Related

Rendering 'new' leads to a different url

When handling validation errors in a User form on my rails project, I have the instruction render 'new' if the user is not valid.
However, when this occurs, the url in the search bar changes.
Originally, it's https://localhost:3000/signup but when the user submit the forms and the render 'new' occurs, the URL becomes https://localhost:3000/users
Why is that?
Here's my routes.rb
Rails.application.routes.draw do
# Resources
resources :users, only: [ :new, :create ]
# Application root
root 'static_pages#home'
# Static pages
get '/help', to: 'static_pages#help'
get '/contact', to: 'static_pages#contact'
# Users
get '/signup', to: 'users#new'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Thanks,
In the Rails REST conventions you use different URI's to display the form to create a resource and for the forms action attribute which you POST to.
Lets say you have:
resources :pets
This gives us:
GET /pets/new => pets#new
POST /pets => pets#create
We then have a typical form:
# posts to /pets
<%= form_for(#pet) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
And a run of the mill controller:
class PetsController < ApplicationController
def new
#pet = Pet.new
end
def create
#pet = Pet.new(pet_params)
if #pet.save
redirect_to #pet
else
render :new
end
end
# ...
end
So when the user visits /pets/new and fills in the form the browser url should read /pets if the form is invalid. This is the intended behavior - posting to a different URL avoids a myriad of cache and history related issues.
From a restful standpoint its also correct - you're no longer viewing the new action - you're viewing the results of attempting to create a resource. The former is idempotent - the latter is not.
You need to recognize that the line render :new is short for render template: 'pets/new'. It does not redirect and it does not call the new action in the controller. It simply renders the template and returns it as the response to the current request.
The reason this is happening is because of the way Rails handles routes. Most likely, the form on your signup page has something like:
<?= form_for #user do |f| ?>
If you look at the generated HTML you'll notice that the form is POSTing to the url '/users'. So when the signup form is submitted, the app is going to redirect you to /users.
This is the normal behavior in Rails. (see Rails Guides)
If you want the URL to look like /signup you can add a named route for it:
# Users
get '/signup', to: 'lead_magnets#new'
post '/signup', to: 'lead_magnets#create'
Then in your signup form you'll need to explicitly reference the new signup path:
<?= form_for #user, url: signup_path do |f| ?>
The generated HTML should look like
<form class="new_user" id="new_user" action="/signup" method="post">
You need to add
post '/signup', to: 'users#new'
Did you try to include recognize path?
Rails.application.routes.recognize_path
The reason for this is because when you submit your form, you're submitting it to some action from your new view. The action that the form submits to has a path, and you can see what the path is by typing:
rake routes
in your console and searching for the create action. When your validation fails in the create action, you call render 'new'.
When you render a template, the url of the page being rendered will be the url / path of the controller action that rendered the template.
In your case, whatever action you have that calls render 'new' will be the one determing the url once your template is rendered.

Unfamiliar error: ActionController::RoutingError at /show uninitialized constant UserController?

I am getting this error:
ActionController::RoutingError at /show
uninitialized constant UserController
I have checked my routes, and controller several times and they seem fine so I will post them below
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:image, :name)
end
end
the route:
get 'index' => 'users#index'
get 'show' => 'user#show'
the attempted link to the show page from the index view:
<h4 class="media-heading"><%= link_to user.name, show_path %></h4>
Thanks for the help, will gladly post more info if needed.
You have an error in routes:
get 'show' => 'user#show' should be get 'show', to: 'users#show'
You don't have show action in your controller
I would use RESTful routes, which is simply:
resources :users # this will generate routes for you
You can specify which actions you want, or which you want to restrict using only or except options as #D-Side says in comments

Route to a different controller when a user is signed in using omniauth in Rails 4?

How do you route to a different controller and page when a user is signed in using Omniauth (no devise) and rails 4?
Current my code is:
root to: 'dashboards#home', :constraints => lambda{|req| !req.session[:user_id].blank?}
root to: 'visitors#home'
And I get the error:
"Invalid route name, already in use: 'root' You may have defined two routes with the same name using the :as option, or you may be overriding a route already defined by a resource with the same naming."
You could do it in the view:
<% if signed_in? %>
<%= render 'dashboards/home' %>
<% else %>
...whatever the non-signed in person sees
<% end %>
Then you only have one root that can lead to two different pages whether the user is logged in or not.
root to: 'vistors#home'
match '/dashboard', to: 'dashboards#home', via: 'get
I usually just do this in the controller. For example, root all to dashboard:
root to: 'dashboards#home'
Then in the DashboardController:
def home
if session[:user_id].blank?
redirect_to controller: 'visitors', action: 'home'
end
end
I haven't found a graceful way to do conditional routing in rails, unfortunately.

Rails 4 - No route matches PATCH on custom route

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.

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