Rails form issuing GET request instead of POST request - ruby-on-rails

I am making a Rails 3.1 app and have a signup form that was working fine, but I seemed to have changed something to break it.. I'm using Twitter bootstrap and twitter_bootstrap_form_for gem. I made some change that messed with the formatting of the form fields, but more importantly, when I submit the Sign Up form to create a new User, the information is showing up in the URL and looks like this:
EDIT: This is happening in the latest versions of Chrome and Firefox
http://localhost:3000/?utf8=%E2%9C%93&authenticity_token=UaKG5Y8fuPul2Klx7e2LtdPLTRepBxDM3Zdy8S%2F52W4%3D&user%5Bemail%5D=kevinc%40example.com&user%5Bpassword%5D=testing&user%5Bpassword_confirmation%5D=testing&commit=Sign+Up
Here is the code for the form:
<div class="span7">
<h3 class="center" id="more">Sign Up Now!</h3>
<%= twitter_bootstrap_form_for #user do |user| %>
<%= user.email_field :email, :placeholder => 'me#example.com' %>
<%= user.password_field :password %>
<%= user.password_field :password_confirmation, 'Confirm Password' %>
<%= user.actions do %>
<%= user.submit 'Sign Up' %>
<% end %>
<% end %>
</div>
Here is the code for the UsersController:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to about_path, :notice => "Signed up!"
else
render 'new'
end
end
end
Not sure if there is more you need but if so let me know! Thank you!
Edit: For debugging I tried specifying :post and also using a plain form_for
<%= form_for(#user, :method => :post) do |f| %>
<div class="field">
<%= f.label :email %>
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<div class="actions"><%= f.submit "Sign Up" %></div>
<% end %>
This gives me the same problem as above.
Adding routes.rb:
Auth31::Application.routes.draw do
get "home" => "pages#home"
get "about" => "pages#about"
get "contact" => "pages#contact"
get "help" => "pages#help"
get "login" => "sessions#new", :as => "login"
get "logout" => "sessions#destroy", :as => "logout"
get "signup" => "users#new", :as => "signup"
root :to => "pages#home"
resources :pages
resources :users
resources :sessions
resources :password_resets
end

The problem was that I was specifying the HTML form tag when Rails form_for generates its own. See below to add a class to a form:
<%= form_for(#user, :html => { :class => "form-stacked"} ) do |f| %>
This worked fine. I'm still not sure why having 2 tags would generate a GET request.

It looks like your for is sending a GET request, rather that a POST request. I'm not sure why this is happening (have you tried using plain form_for for debugging purposes?), but you should be able to fix it my explicitly setting the method:
<%= twitter_bootstrap_form_for(#user, :method => :post) do |user| %>

Related

NoMethodError in UserController#new

I keep getting the following error on my app from 7.2.1 on Michael Hartl Ruby Rails tutorial. For some reason it is not accepting a nil #user field in the signup form.
undefined method `users_path' for #<#<Class:0x007ff87141aef8>:0x007ff870cf0d30>
new.html.erb
<% provide(:title, "Sign up") %>
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
User_controller.rb
class UserController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
end
Routes.rb
Rails.application.routes.draw do
resources :user
get 'user/new'
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'user#new'
You need to change resources :user to resources :users and define the index action in the controller by adding
def index
end

Why my code takes me to different URL?

First of all, My resource is nested using to_param for slug at Community model.
I'm at example.com/shop/walmart/topic/14/edit .
If I press update without captcha input, it obviously should take me back to edit page again with flash error message.
However it takes me to example.com/shop/14/topic/14/edit . <= it's taking the same parameter. it should take 'walmart' which is community_name for first argument, and :id for topic.
All the fields are set the same with what I typed in at the previous page.
How can I avoid this? it should redirect to the same url as previous page.
routes.rb
resources :communities, :path => "shops", do
resources :community_topics, :path => "topics"
end
controller
def simple_captcha_check
if !simple_captcha_valid?
flash[:error] = 'Wrong Captcha!'
if request.put? # We came from an edit request
#community_topic = CommunityTopic.find(params[:id])
#community_topic.attributes = params[:community_topic]
render :action => :edit
elsif request.post? # We came from a new request
#community_topic = CommunityTopic.new params[:community_topic]
render :action => :new
end
end
end
models/community.rb Note that I use slug here
def to_param
"#{community_name}"
end
views/community_topics/_form.html.erb
<%= form_for #community_topic, :html => { :class => 'form-horizontal' } do |f| %>
<div class="control-group">
<%= f.label :title, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :title, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :body, :class => 'control-label' %>
<div class="controls">
<%= f.text_area :body, :class => 'text_area' %>
</div>
</div>
<div class="control-group">
<div class="controls">
<%= show_simple_captcha(:label => "human authentication") %>
</div>
</div>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
community_topic_index_path, :class => 'btn' %>
</div>
<% end %>
rake routes | grep community_topic
community_community_topics GET /shops/:community_id/topics(.:format) community_topics#index
POST /shops/:community_id/topics(.:format) community_topics#create
new_community_community_topic GET /shops/:community_id/topics/new(.:format) community_topics#new
edit_community_community_topic GET /shops/:community_id/topics/:id/edit(.:format) community_topics#edit
community_community_topic GET /shops/:community_id/topics/:id(.:format) community_topics#show
PUT /shops/:community_id/topics/:id(.:format) community_topics#update
DELETE /shops/:community_id/topics/:id(.:format) community_topics#destroy
By the way, my index action in controller is just like this, and it's working fine!
community_topics_controller.rb #index
def index
#community = Community.find_by_community_name(params[:community_id])
#community_topics = #community.community_topics
respond_to do |format|
format.html # index.html.erb
format.json { render json: #community_topics }
end
end
I don't see your controller actions, and don't know names of variables, but anyway in case of nested routes you have to define all urls precisely with named routes, or with polymorphic helper (as i do).
So your form helper must be looking as next:
<%= form_for([#community, #community_topic], :html => { :class => 'form-horizontal' }) do |f| %>
it have to send request to /shop/walmart/topic/14/update (or 'new' if #community_topic is a new record)
community.rb:
you can just
def to_param
community_name
end
routes.rb:
resources :communities, :path => "shop", do
resources :community_topics, :path => "topic"#, :as => :'topic' *
end
# * named route 'community_topic' can conflict with 'community_topics' of standalone route for CommunityTopic. Let it be by default: 'community_community_topic'.

How to put a login form in the header for Devise and Rails

I want to put a login form in the header of my website. I use Rails 3.2.8 and the latest Devise. In the app/views/devise/sessions/new.html.erb file a login form is created with:
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => {:class => 'main'}) do |f| %>
<div><%= f.label :login %> <%= f.text_field :login, :placeholder => 'Enter username' %></div>
<div><%= f.label :password %> <%= f.password_field :password, :placeholder => 'Enter password' %></div>
<% if devise_mapping.rememberable? -%>
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
<% end -%>
<%= f.submit "Go" %>
<% end %>
If I try to copy that code and put it in my application.html.erb, I get an error regarding that resource variable referenced above:
undefined local variable or method `resource' for #<#<Class:0x3cb62c8>:0x3c73b00>
So can I just use a normal rails form with /users/sign_in as the action? How do I tell devise where to redirect to after logging in?
We have a wiki page for that on the Devise wiki:
https://github.com/plataformatec/devise/wiki/How-To:-Display-a-custom-sign_in-form-anywhere-in-your-app
Enjoy!
You have to include #user = User.new in all the controller actions that will display the header with the login form.
For example, say you have a Pages controller with Home action. And you want to display the login form in the navigation of application layout.
class PagesController < ApplicationController
def home
#user = User.new
end
end
On the application.html.haml, you'd have something like
- if user_signed_in?
= link_to "sign out", destroy_user_session_path, method: :delete
- else
= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => {:class => 'main'}) do |f|
...

No Route Matches in Ruby on Rails

In my ruby on rails project, I am using devise as the authentication plugin. Now I have added the change password functionality to the project and when submit the form, I'm getting an error No route matches "/users/update_password"
This is my update password code
def update_password
#user = User.find(current_user.id)
if #user.update_attributes(params[:user])
# Sign in the user by passing validation in case his password changed
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
This is my route details
resources :users, :only => [] do
collection do
get 'current'
get 'edit'
post 'update_password'
end
end
and this is my edit form
<div id="loginForm">
<div id="loginHeader"><h3>Change Password</h3></div>
<div id="loginContent">
<%= form_for(#user, :url => { :action => "update_password" }) do |f| %>
<p><%= f.password_field :current_password, :class => "login_txt", :placeholder => "We need your current password to confirm your changes", :autocomplete => "off" %></p>
<p><%= f.password_field :password, :class => "login_txt", :placeholder => "New password", :autocomplete => "off" %></p>
<p><%= f.password_field :password_confirmation, :class => "login_txt", :placeholder => "Confirm password", :autocomplete => "off" %></p>
<p>
<input id="user_submit" name="commit" type="submit" value="Update Password" class="login_btn" />
</p>
<% end %>
</div>
</div>
Can anyone help me how to fix this issue
Thanks a lot
In your routes.rb you define update_password as a POST action on the collection (/users/update_password), but in your form you are implicitly defining it as a PUT action when you pass #user to form_for, since #user already exists.
I haven't tested this, but I believe that changing your route on the collection from a POST to a PUT should fix this:
resources :users, :only => [] do
collection do
get 'current'
get 'edit'
put 'update_password'
end
end
See also: Rails 3.0.10, customer routes, post and form_for tag

Sign up/Login Routing error

Sorry for the novice question but I am trying to get to grips with RoR. I have a very basic sign up and login process in place but am having some difficulty getting the routing correct. I am also unsure whether I am actually being logged out successfully when I push my logout button because it isn't then displaying the login button as it should.
My setup is as follows on Rails 3.1:
Sessions Controller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, :notice => "Logged in!"
else
flash.now.alert = "Invalid email or password!"
render "signup"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Logged Out!"
end
end
User Controller
class UserController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new (params[:user])
if #user.save
redirect_to root_url, :notice => "Signed Up!"
else
render "user/new"
end
end
end
User Model
class User < ActiveRecord::Base
has_secure_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email, :on => :create
end
Sessions/new.html.erb
<h1>Log In</h1>
<%= form_tag login_path do %>
<div class="field">
<%= label_tag :email %>
<%= text_field_tag :email, params[:email] %>
</div>
<div class ="field">
<%= label_tag :password %>
<%= password_field_tag :password %>
</div>
<div class="actions"><%= submit_tag "Log in" %></div>
<%end%>
User/new.html.erb
<% if session[:user_id] %>
<!-- user is logged in -->
<%= link_to logout_path %>
<% else %>
<!-- user is not logged in -->
<%= link_to login_path %>
<% end %>
<h1>Sign Up</h1>
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class = "field">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<div class = "field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class = "field">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<div class="actions"><%= f.submit %></div>
<% end %>
Finally my Routes file
MadeByV2::Application.routes.draw do
controller :user do
get "signup" => "user#new"
end
resources :users
controller :sessions do
get "login" => "sessions#new"
post "login" => "sessions#create"
delete "logout" => "sessions#destroy"
end
root :to => "user#new"
end
Sorry for the extensive use of code in this post but I figure it's best to give a well rounded view of everything so people can see where I am going wrong.
Any help you can offer really would be much appreciated because I don't seem to be getting it myself
Thanks,
Tom
Your code looks fine, but your routes look a little strange.
I'd try something like this:
resources :users
resources :sessions
match 'login' => 'sessions#new', :as => :login
match 'logout' => 'sessions#destroy', :as => :logout
Then I think everything you've currently got should work.

Resources