Rendering Actions with Custom Routes - ruby-on-rails

I am trying to maintain a pretty URL when having a user register with failed validation
I have a routes file that looks like the following:
map.resources :users
map.signup '/signup', :controller => "users", :action => "new"
This works well enough, except that if a user enters invalid information during registration then the create method does the following:
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = "Successfully Registered."
redirect_to root_url
else
render :action => 'new'
end
end
This works, but if the information is correct it switches the URL to domain.com/users. If I switch it to redirect_to '/signup' it works, but all the previous information that was entered is lost, and I would ideally like to maintain that.
Is there any way to keep my nice urls during a failed validation?

You'll need to add conditions to your routes:
# Routes files
map.resources :users
map.signup "/signup", :controller => "users", :action => "new", :conditions => { :method => :get }
map.signup "/signup", :controller => "users", :action => "create", :conditions => { :method => :post }
Then, you'll need to make sure your controller and view handle them correctly:
# Controller
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = "Successfully registered."
redirect_to root_url
else
render "new"
end
end
# new.html.erb
<% form_for #user, :url => signup_path do |form| %>
....
<% end %>

Try adding to routes:
map.signup_post '/signup', :controller => "users", :action => "create", :method => :post
And in your form:
<%= form_for #user, :url => signup_post_path do |f| %>

Related

Method is not being called, but is defined in controller and model

I have a method to toggle a user between admin or not-admin. When I click the link I am placed back in the User index with the following in my address bar: http://localhost:3000/users?id=1&method=toggle_admin. As far as I can tell, I have the appropriate code to run the method. Can anyone see a mistake?
Here's the view link_to method:
<%= link_to 'Toggle Admin', { :controller => :users, :method => :toggle_admin, :id => user.id} %>
Here's the routes.rb statement:
match 'users/:id/toggle_admin' => 'users#toggle_admin'
The controller method:
def toggle_admin
#user = User.find(params[:id])
User.toggle_admin(#user)
respond_to do |format|
format.html { redirect_to #users }
end
end
The model method:
def toggle_admin(user)
if user.is_admin.nil or user.is_admin = ''
user.is_admin = false
end
user.toggle is_admin
user.save
end
Trying using :action instead of :method. :method should be used with HTTP verb (i.e GET, PUT and so on)
<%= link_to 'Toggle Admin', { :controller => :users, :action => :toggle_admin, :id => user.id} %>

routing error showing that No route matches [POST] "/admin/locations/1"

I am new to ROR when i edit my location it will gives me following error
No route matches [POST] "/admin/locations/1"
here i am using rails 3.2.12
this is my location controller
class Admin::LocationsController < ApplicationController
def index
#location= Location.order("location desc")
end
def new
#location=Location.new
end
def create
#location = Location.new(params[:location])
if #location.save
# flash[:notice] = 'Location is successfully added in to list.'
redirect_to :action => 'index'
else
render :action => 'new'
end
end
def edit
#location = Location.find(params[:id])
end
def update
#location = Location.find(params[:id])
if #location.update_attributes(params[:location])
#flash[:notice] = 'Category is successfully updated.'
redirect_to :action => 'index'
else
render :action => 'index'
end
end
end
this is my edit.html.erb
<h2>Edit Location</h2>
<%= simple_form_for(:location, :url => {:action => 'update', :id => #location.id}) do |f| %>
<%= render(:partial => 'form', :locals => {:f => f}) %>
<%= submit_tag("Update",) %> <%= link_to("cancle", {:action => 'index'} )%>
<%end%>
and this is my route.rb
GuestHouse::Application.routes.draw do
devise_for :customers
namespace :admin do
resources :locations
end
and in my index.html.erb as
<%= link_to("Edit", {:action => 'edit', :id => location.id}, :class => 'btn btn-info')%>
<%= simple_form_for(:location,
:url => {:action => 'update', :id => #location.id},
:method => 'put' ) do |f| %>
Pass method in simple_form_for
For an edit form, you likely want to be using the PUT method instead of POST. It looks like you are using [SimpleForm][1], though, which normally would handle constructing the path for a given model for you. Is there any reason you are not passing your Location instance in your call to simple_form_for? I would expect something like the following:
<%= simple_form_for #location do |f| %>
...
Here your routes for admin/location like the following.
admin_locations GET /admin/locations(.:format) admin/locations#index
POST /admin/locations(.:format) admin/locations#create
new_admin_location GET /admin/locations/new(.:format) admin/locations#new
edit_admin_location GET /admin/locations/:id/edit(.:format) admin/locations#edit
admin_location GET /admin/locations/:id(.:format) admin/locations#show
PUT /admin/locations/:id(.:format) admin/locations#update
DELETE /admin/locations/:id(.:format) admin/locations#destroy
so if you want to send the form to 'update' action, you should mention the path like below.
<%= simple_form_for #location, :url => admin_location_path(#location),:html => { :method => "post"} do |f| %>

Matching paths in rails 3 using form_tag

I am trying to follow the tutorial of making a twitter clone in ruby on rails (http://www.youtube.com/watch?v=oXr1jAsBlPI&feature=relmfu). Unfortunately for me he is doing it in Rails 2.x.x and I am having some trouble keeping up. I am currently 41:34 when he is defining the paths in routes.rb.
I am getting this problem when I enter my 'show' page:
"Routing Error No route matches {:action=>"show",
:controller=>"toggle_follow"} Try running rake routes for more
information on available routes."
This is what I have in the relevant files:
routes.rb
match '/:username', :controller => 'home', :action => 'show'
match '/:username/toggle_follow', :controller => 'home', :action => 'toggle_follow'
show.html.rb
<% if current_user.is_friend? #user %>
<%= submit_tag "Following", :class => "button" %>
<% else %>
<%= submit_tag "Stop following", :class => "button" %>
<% end %>
home_controller.rb
def show
#user = User.find_by_username(params[:username])
#flits = #user.all_flits
end
def toggle_follow
#user = User.find_by_username(params[:username])
if current_user.is_friend? #user
flash[:notice] = "You are no longer following ##{#user.username}"
current_user.remove_friend(#user)
else
current_user.add_friend(#user)
flash[:notice] = "You are following ##{#user.username}"
end
redirect_to user_flits_path(#user.username)
end
...
Thanks in advance
Ok I solved it...
in routes you have to enter:
routes.db
match '/:username', :to => 'home#show', :as => 'user_flits'
match '/:username/toggle_follow', :to => 'home#toggle_follow', :as => 'toggle_follow'

Rails Routing Error

In routes.rb I have:
get "survey/show" => "survey#show"
post "survey/step_2" => "survey#step_2"
post "survey/step_3" => "survey#step_3"
And in step_2.html.erb I have:
<%= form_for #result, :url => { :controller => 'survey', :action => 'step_3' } do |f| %>
And in survey_controller.rb I have:
def step_2
#result = Result.new(params[:result])
if #result.save
session[:result_id] = #result.id
render :action => "step_2"
else
render :action => "show"
end
end
def step_3
#result = Result.find(session[:result_id])
if #result.update_attributes(params[:result])
render :action => "step_3"
else
render :action => "step_2"
end
end
And when I submit the form on step_2 I get the following error:
No route matches "/survey/step_3"
I believe Rails form_for method may be making that a PUT request, since the #result object has an id. I believe you should change your form_for line to:
<%= form_for #result,
:url => { :controller => 'survey', :action => 'step_3' },
:html => { :method => :post} do |f| %>
or change the route type to put in routes.rb
You have to use match.
match 'survey/step_3' => 'survey#step_3', :via => 'post'
I might be wrong about the :via, but it's something like that.

Rails Route that Updates or Redirects

Im not sure if I'm doing this right. I have an action that I would like to either copy, create, and save a new object if a user is logged in, or redirect if they are not logged in. Im not using a form here because I am using a stylized button with an image that looks like this:
<a href="/lists/add/<%= #list.id %>" class="button">
<span class="add_list">Learn these words</span>
</a>
and the action looks like this:
def add
if is_logged_in?
list = logged_in_user.copy_list(params[:id])
if list.save
flash[:notice] = "This list is now in your stash."
redirect_to stash_zoom_nav_quiz_path(list, "zoomout", "new", "quizoff")
else
flash[:notice] = "There was a problem adding this list."
redirect_to :back
end
else
redirect_to :controller => "users", :action => "signup_and_login", :list_id => params[:id]
end
end
map.resources :lists, :collection => {:share => :get, :share_callback => :get, :add => :put}
I have added this action as a :put in my routes and I'm not sure if this is right or if the other stuff is the right way to even do it for that matter. Any help is appreciated.
The specific answer to your question is
map.resources :lists, :collection => { :share => :get, :share_callback => :get }, :member => { :add => :put }
add action works on a member, not on a collection.
But there are other problems in your code. First, you should always use Rails helpers to generate the URLs. In fact, the path /lists/add/<%= #list.id %> is wrong. It should be /lists/<%= #list.id %>/add
Change
<a href="/lists/add/<%= #list.id %>" class="button">
<span class="add_list">Learn these words</span>
</a>
to
<% link_to add_list_path(#list), :class => "button" do %>
<span class="add_list">Learn these words</span>
<% end %>
The controller can be simplified. Move the is_logged_in? check in a before filter.
class MyController < ActionController::Base
before_filter :require_logged_user, :only => %w( add )
def add
list = logged_in_user.copy_list(params[:id])
if list.save
flash[:notice] = "This list is now in your stash."
redirect_to stash_zoom_nav_quiz_path(list, "zoomout", "new", "quizoff")
else
flash[:notice] = "There was a problem adding this list."
redirect_to :back
end
end
protected
def require_logged_user
if !is_logged_in?
redirect_to :controller => "users", :action => "signup_and_login", :list_id => params[:id]
end
end
end
Try this in your routes.rb:
map.resources :lists, :member => {:add => :put}, :collection => {:share => :get, :share_callback => :get}
:member - Same as :collection, but for actions that operate on a specific member.

Resources