Rails Route that Updates or Redirects - ruby-on-rails

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.

Related

link_to redirects me to index action and not to the :action one

In my redmine plugin view, I've got this link:
<%= link_to "Add", :controller => "important_user", :action => "u_edit", :u_id => user.id, :p_id => #project.id, :method => :post %>
routes.rb:
resources :important_user do
collection do
post :u_edit
end
end
and controller:
class ImportantUserController < ApplicationController
def u_edit
puts 'edit!'
end
def index
puts 'ciao'
puts params[:p_id]
puts params[:u_id]
end
end
In spite of calling the expected u_edit action, clicking on the link calls the index method (I created in a second moment to avoid the AbstractController::ActionNotFound (The action 'index' could not be found for ImportantUserController) error). I've also tried using this sort of link:
<%= link_to 'Add', { :action => 'create', :u_id => user.id, :p_id => #project.id}, :method => :post %>
But it didn't work either, returning a projects?p_id=1&u_id=1 GET 404. How could I make it call the desired u_edit action?

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} %>

Making a link in Ruby on Rails

I'm really really newbie in Ruby on Rails...
I'm trying to make a link to another page in my project, where it's listed the posts that belong to an escuela.
This is what I did:
In posts_controller.rb I wrote:
def postesc
#posts = Post.where(:escuela_id => params[:id])
respond_to do |format|
format.html # postesc.html.erb
format.json { render json: #posts }
end
end
In config/routes.rb I wrote:
match 'postesc' => 'posts#postesc'
In view/escuelas/listaesc.html.erb I wrote the link:
<%= link_to "Escuelas", :controller => "posts", :action => "postesc" %>
And in view/escuelas/postesc.html.erb I want to make a list of the matching posts.
But this page appears just blank, with only the layout.
Please, some help?
First make the association between post and escuela, then you can find it just by
Escuela.find(params[:id]).posts
Change your routes to -
resources :posts do
get 'postesc', :on => :collection
end
View :
<%= link_to "List posts", postesc_posts_path %>
make a change in routes.rb as
get 'postesc' => 'posts#postesc'
try...<%= link_to "Escuelas", postesc_path %>
OR
<%= link_to "Escuelas", { :controller => "posts", :action => "postesc" } %>
you're missing to add an ID for the Escuela to be selected - as you're doing in your Controller#postesc Action (as in words: where: escuela_id => params[:id]).
<%= link_to "Escuela", :controller => "posts", :action => "postesc", :id => 1 %>
but you could use the object-link method using the following syntax (by changing your routes a litte):
# in routes.rb
match 'postesc' => 'posts#postesc', on: :collection, as: 'esc_index'
# in your view
<%- for escuela in #escuelas do %>
<%= link_to "Escuela", esc_index(escueal) %>
<% end %>

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'

Rendering Actions with Custom Routes

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| %>

Resources