Rails 4 - How to route delete path - ruby-on-rails

I have been using Rails 3 and am trying to use Rails 4. I am following a ToDo tutorial here: http://www.codelearn.org/ruby-on-rails-tutorial/introduction-views-layouts-helpers-assets-pipeline
I am trying to delete the ToDo item using the Rails 'link_to' helper method, and have been looking up online and have not been able to get it to work for the past 90 minutes so I decided to ask for help.
Here is the error message I am getting:
Routing Error
No route matches [DELETE] "/todos/delete_path"
Here is my 'rake routes' from the terminal:
Prefix Verb URI Pattern Controller#Action
todos_index GET /todos/index(.:format) todos#index
todos_delete DELETE /todos/delete(.:format) todos#delete
Here is the 'link_to' helper method from inside of the:
index.html.erb
<%= link_to 'Delete last todo', 'delete_path', method: :delete %>
Here is my:
routes.rb
Rails.application.routes.draw do
get 'todos/index'
# get 'todos/delete'
match 'todos/delete' => 'todos#delete', via: :delete
Here is my:
todos_controller.rb
class TodosController < ApplicationController
def index
# #todo_array = ['Buy Milk', 'Buy Soap', 'Pay bill', 'Draw Money']
#todo_items = Todo.all
render :index
end
def delete
#put delete logic here
#todo_items = Todo.last
#todo_items.destroy
end
end
Thank you for taking the time to look at my problem!

This is how you would write a destroy method:
def destroy
#todo = Todo.last
#todo.destroy
redirect_to todos_index_path #or wherever you want to redirect user after deleting the tod
end
Also, I would simply use RESTful routes:
Rails.application.routes.draw do
resources :todos, only: %i(index destroy)
end

Related

Routing error for rails - uninitialized constant SubscribersController

I have a Subscriber model that takes in a "phone_number" and a "visit" integer. I have two controllers Subscribers and Visits(super and sub) I have never worked with nested controllers before and I'm having some issues with namespace I believe. Because I getting back the uninitialized constant error. Basically the subscriber controller signs up a subscriber and the visit controller counts the amount of times they've visited by user input of their phone_number. Why am I getting this error? I'll show my code for clarity.
CONTROLLERS
class Subscribers::VisitsController < ApplicationController
def new
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.find_by_phone_number(params[:phone_number])
if #subscriber
#subscriber.visit += 1
#subscriber.save
redirect_to subscribers_visits_new_path(:subscriber)
else
render "new"
end
end
end
class SubscribersController < ApplicationController
def index
#subscriber = Subscriber.all
end
def new
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.create(subscriber_params)
if #subscriber.save
flash[:success] = "Subscriber Has Been successfully Created"
redirect_to new_subscriber_path(:subscriber)
else
render "new"
end
end
ROUTES
Rails.application.routes.draw do
devise_for :users
resources :subscribers, except: :show
get '/subscribers/visits/new', to: 'subscribers/visits#new'
root "welcomes#index"
VIEWS
<h1>hey</hey>
<%= form_for #subscriber do |form| %>
<div class="form-group">
<p>
<%= form.label :phone_number %>
<%= form.text_field :phone_number %>
</p>
<% end %>
ERROR
Hmm, my guess is you are trying to route url subscriber/visits/new to new action in VisitsController?How about changing this line:
get '/subscribers/visits/new', to: 'subscribers/visits#new'
to:
namespace :subscribers do
get '/visits/new', to: 'visits#new'
end
Also try to move this block above resources :subscribers, except: :show if you still get the error.
Cheers
You probably do not need to inherit one controller from another. Simply define the controllers as you normally would:
app/controllers/subscribers_controller.rb
class SubscribersController < ApplicationController
# methods for Subscribers
end
in app/controllers/visits_controller.rb
class VisitsController < ApplicationController
# methods for Visits
end
Note that these must to be located in separate files, so that Rails can find the correct source file by the name of the object that it's looking for. This is a Rails naming convention.
Regarding your routes, you'll need to change to use one of 4 route formats. Reading the section on Adding More RESTful Actions in the Rails Routing from the Outside In guide might help.
1) To route visits as a nested resource, which is what it appears you're actually trying to do, you would use this:
resources :subscribers, except: :show do
resources :visits
end
This will produce these routes:
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
GET /subscribers/:id/visits/new
POST /subscribers/:id/visits
GET /subscribers/:id/visits
GET /subscribers/:id/visits/:id
GET /subscribers/:id/visits/:id/edit
PATCH /subscribers/:id/visits/:id/update
DELETE /subscribers/:id/visits/:id/destroy
This is the typical route structure for nested resources and separate controllers.
2) To make visits#new a simple collection (non-member) action in the VisitsController, then you likely want this:
resources :subscribers, except: :show do
collection do
get 'visits/new', to 'visits#new'
post 'visits', to 'visits#create'
end
end
This will produce these routes:
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
GET /subscribers/visits/new
POST /subscribers/visits
This is typically used to add new top-level routes in an existing resource and controller.
3) To construct visits as member actions, use this:
resources :subscribers, except: :show do
member do
get 'visits/new', to 'visits#new'
post 'visits', to 'visits#create'
end
end
This will produce these routes:
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
GET /subscribers/:id/visits/new
POST /subscribers/:id/visits
This is normally used to add new member routes in an existing resource and controller.
4) To simply make visits routes appear to be included in subscribers, you could use this:
get '/subscribers/visits/new', to: 'visits#new'
post '/subscribers/visits', to: 'visits#create'
resources :subscribers, except: :show
This will produce these routes:
GET /subscribers/visits/new
POST /subscribers/visits
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
This may be used to make arbitrary routes appear to be included in an existing resource, when they really may be independent.

Routing Error Ruby on Rails -- Voting system

I'm implementing a voting system to my blog's comments, using the acts_as_votable gem.
However, I'm getting a routing error: no route matches. missing required keys: [:id]
#routes.rb
resources :articles do
resources :comments do
member do
put "like", to: "comments#upvote"
end
end
end
# comments controller
def upvote
#comment.upvote
redirect_to :back
end
# comments/show.html.haml
= link_to like_article_comment_path(#comment), method: :put do
= #comment.get_upvotes.size
If you use rake routes | grep like (to fatch that route), you'll get:
like_article_comment PUT /articles/:article_id/comments/:id/like(.:format) comments#upvote
So you're missing the first parametar - :article_id in your link. Should be:
= link_to like_article_comment_path(#article, #comment), method: :put do
= #comment.get_upvotes.size
Also add the #article logic in your upvote method.

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

Link to resource

I have created model, view and controller:
$ rails generate scaffold Post name:string title:string content:text
I run server and I see list of posts if I open in the browser http:\localhost:3000\posts.
Now I need to create link to this page. Something like:
<%= link_to("settings", { :controller => 'groups', :action => 'index'}) %>
But I get error on opening this page:
Couldn't find Group with ID=index
How ca I create link to http:\localhost:3000\posts and which action do I use in this case?
I think the path helpers are excellent in these cases. You could do it like this:
<%= link_to("Posts", posts_path) %>
posts_path in this case will link to http://localhost:3000/posts
When you use use resources :posts in your routes.rb you automatically get a few path helpers. For example:
posts_path # /posts
post_path(#post) # /posts/1
edit_post_path(#post) # /posts/1/edit
new_post_path # /posts/new
If you have a route such as:
resources :groups
In config/routes.rb then you will have the helper groups_path. You can use rake routes to see all of your routes and helpers, but in this case you will have:
groups_path
group_path(#group)
edit_group_path(#group)
Polymorphic Routes Documentation

How to handle multiple HTTP methods in the same Rails controller action

Let's say I want to support both GET and POST methods on the same URL. How would I go about handling that in a rails controller action?
You can check if it was a post using request.post?
if request.post?
#handle posts
else
#handle gets
end
To get your routes to work:
resources :photos do
member do
get 'preview'
post 'preview'
end
end
Here's another way. I included example code for responding with 405 for unsupported methods and showing supported methods when the OPTIONS method is used on the URL.
In app/controllers/foo/bar_controller.rb
before_action :verify_request_type
def my_action
case request.method_symbol
when :get
...
when :post
...
when :patch
...
when :options
# Header will contain a comma-separated list of methods that are supported for the resource.
headers['Access-Control-Allow-Methods'] = allowed_methods.map { |sym| sym.to_s.upcase }.join(', ')
head :ok
end
end
private
def verify_request_type
unless allowed_methods.include?(request.method_symbol)
head :method_not_allowed # 405
end
end
def allowed_methods
%i(get post patch options)
end
In config/routes.rb
match '/foo/bar', to: 'foo/bar#my_action', via: :all
Just need to use this, to use only get and post in the same route
resources :articles do
member do
match 'action_do-you_want', via: [:get, :post]
end
end
you can try this
match '/posts/multiple_action', to: 'posts#multiple_action', via: [:create, :patch, :get, :options]
I would say, the best way is to create separate actions in the controller and state them in routes.
# config/routes.rb
...
get '/my_action' => 'my#my_action_get'
post '/my_action' => 'my#my_action_post'
...
# app/controllers/my_controller.rb
...
def my_action_get
# do stuff like listing smth
end
def my_action_post
# do other stuff
end
In fact, the same logic is used by Rails by default: index and create actions are both called by requests sent to the same paths (e.g. /articles), however, they have different request methods: GET /articles request is redirected to the index action and lists all articles, and POST /articles is redirected to the create action and creates a new article.
This works for me:
In routes.rb
Rails.application.routes.draw do
post '/posts', to: 'posts#create'
get '/posts', to: 'posts#list_all'
end
In posts_controller.rb
class PostsController < ApplicationController
def create
new_post = Post.create( content: params[:content], user_id: params[:user_id] )
render json: { post: new_post }
end
def list_all
request = Post.all
render json: { all_posts: request }
end
end
So each action is referred to a different function

Resources