1

I'm working on the Ruby on Rails Tutorial by Michael Hartl (I'm a noob).

In the application I want to delete a micropost, but whenever I try to execute it in the browser, it tells me that there is Routing Error. "No route matches [GET] "/microposts/3"

This is the code that I have in _micropost.html.erb

<tr>
    <td class="micropost">
        <span class="content"><%= micropost.content %></span>
        <span class="timestamp">
            Posted <%= time_ago_in_words(micropost.created_at) %> ago
        </span>
    </td>
    <% if current_user?(micropost.user) %>
    <td>
        <%= link_to "delete", micropost, :method => :delete,
                                         :confirm => "You sure?",
                                         :title => micropost.content %>
    </td>
    <% end %>
</tr>
</tr>

I already have the Javascript code that fakes the request according to the book

<head>
  <title><%= title %></title>
  <%= csrf_meta_tag %>
  <%= render 'layouts/stylesheets' %>
  <%= javascript_include_tag :all %>
</head>

and this is part of my routes.rb

Rails.application.routes.draw do

  get 'sessions/new'

  resources :users
  resources :sessions, :only => [:new, :create, :destroy]
  resources :microposts, :only => [:create, :destroy]

  match '/signup', :to => 'users#new', via: [:get, :post]
  match '/signin', :to => 'sessions#new', via: [:get, :post]
  match '/signout', :to => 'sessions#destroy', via: [:get, :post]
  match '/contact', :to => 'pages#contact', via: [:get, :post]
  match '/about', :to => 'pages#about', via: [:get, :post]
  match '/help', :to => 'pages#help', via: [:get, :post]
  match '/:id', :to => 'users#show', via: [:get, :post]

  root :to => 'pages#home'

Here is the application.js

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

And the micropost_controller.rb

class MicropostsController < ApplicationController

    before_filter :authenticate, :only => [:create, :destroy]
    before_filter :authorized_user, :only => :destroy

    def create
        @micropost = current_user.microposts.build(micropost_params)
        if @micropost.save
            flash[:success] = "Micropost created!"
            redirect_to root_path
        else
            @feed_items = []
            render 'pages/home'
        end
    end

    def destroy
        @micropost.destroy
        redirect_back_or root_path
    end

    private
        def micropost_params
            params.require(:micropost).permit(:content)
        end

        def authorized_user
            @micropost = Micropost.find(params[:id])
            redirect_to root_path unless current_user?(@micropost.user)
        end
end

I've founded this answer, but the "button_to" method doesn't seem to solve my problem: Delete link sends "Get" instead of "Delete" in Rails 3 view

Thank you very much in advance for any answer.

Community
  • 1
  • 1
seque90
  • 181
  • 2
  • 13
  • 1
    Do you have method `destroy` in `MicropostsController` ? – Grych Jan 21 '15 at 15:09
  • What does your controller code look like? Have you tried adding logging with `logger.info "abcde"` to see what's happening? The request might be getting as far as the controller, before it is redirected somewhere else. Also, I'm not sure why Javascript has any relevance here? – GoBusto Jan 21 '15 at 15:09
  • 2
    Paste your controller method. Looks like you are trying to render after destroy. – Jorge de los Santos Jan 21 '15 at 15:25
  • I've just pasted the MicropostController. – seque90 Jan 21 '15 at 19:49
  • Hmm... I was originally thinking that this might be a controller problem, but everything that you've posted here seems to be fine. I'd say that the answer given by @glyuck is probably right about this - make sure that you have Javascript enabled in your browser (don't forget about extensions such as NoScript!) and check your browser console for errors. You can see the console by pressing F12 in most browsers - just be aware that you might need to press F5 to refresh in order to see anything if you open the console *after* navigating to the page. – GoBusto Jan 22 '15 at 08:45

1 Answers1

4

Make sure you have

//= require jquery
//= require jquery_ujs

in your application.js. Also review browser's javascript console after page loaded. Maybe there are some javascript errors, they can block jquery_ujs from working.

Also, note that you need to change :confirm => "You sure?" to :data=> {:confirm => "You sure?"}

Explanation: RUBY is trying to be RESTful, so it's sending PATCH requests for edit action, DELETE requests for destroy action. But most browsers can only submit GET and POST forms. Hyper-links are always opened via GET (and link_to generates <a href=...> tag). So rails do some hackery and "emulate" DELETE, PUT and PATCH requests.

form_tag helper creates additional hidden input: <input name="_method" type="hidden" value="delete" />, then Rails parses requests parameters and assumes that it's DELETE request. You can read about it in documentation.

link_to 'delete', '/some/url', :method => :delete, in its turn, will generate following html: <a href="/some/url/" data-method="delete">delete</a>. Then jquery_ujs javascript intercepts all clicks on links with data-method attribute and creates hidden form with method="POST" and, yes, hidden input with name="_method" value="delete", then this form is submitted. Take a look at jquery_ujs source code, it's rather straightforward.

SO if you see GET request in server console after clicking link with method: :destroy, most likely, there are some problems with javascript.

glyuck
  • 3,367
  • 18
  • 14
  • If this is a routing error (`Routing Error. "No route matches [GET] "/microposts/3"`) then it's probably a server-side problem, not a browser-side one. – GoBusto Jan 21 '15 at 15:14
  • 1
    Why downvote? It's definitely javascript issue. `:delete` links should not be opened via GET. jquery_ujs creates hidden POST form with `` and submits it. Also, note that you need to change `:confirm => "You sure?"` to `:data=> {:confirm => "You sure?"}` – glyuck Jan 21 '15 at 15:20
  • The OP code includes `<%= link_to "delete", micropost, :method => :delete` so Rails should treat it as a DELETE request (rather than a GET) even if the *actual* HTTP method differs. – GoBusto Jan 21 '15 at 15:32
  • @GoBusto, try to remove `jquery_ujs` from your `application.js` and follow link with `:method => :delete`. Surprisingly you browser will send GET request. FYI, without javascript most browsers can only send GET and POST requests. Please, read more here: http://guides.rubyonrails.org/form_helpers.html#how-do-forms-with-patch-put-or-delete-methods-work-questionmark and here: https://github.com/rails/jquery-ujs/blob/master/src/rails.js#L170 – glyuck Jan 21 '15 at 15:37
  • Ah, sorry, I misunderstood what you were saying - I thought that you were suggesting that it was an AJAX-related problem, rather than a fake-the-HTTP-verb-with-Javascript one. (I did know that most browsers only support GET and POST, incidentally - this is what I was referring to in my `:method => :delete` comment). Anyway, consider my downvote rescinded! – GoBusto Jan 21 '15 at 15:49
  • In fact, now that the controller code has been posted, I'm thinking that this is probably going to be the correct answer, so I'll replace that downvote with an upvote by way of apology. :) – GoBusto Jan 22 '15 at 08:48