Nenhuma rota corresponde aos trilhos de criação “/ users / sign_out” 3

386

Instalei o dispositivo no meu aplicativo e apliquei o seguinte no meu application.html.erbarquivo:

<div id="user_nav">
    <% if user_signed_in? %>
        Signed in as <%= current_user.email %>. This cannot be cheese?
        <%= link_to 'Sign out', destroy_user_session_path %>
    <% else %>
        <%= link_to 'Register', new_user_registration_path %> or <%= link_to 'Sign in', new_user_session_path %>
    <% end %>
</div>

Corri rake routese confirmei que todas as rotas são válidas.

Além disso, no meu routes.rbarquivo eu tenho devise_for :userse root :to => "home#index".

Recebo o seguinte erro de roteamento ao clicar no link "Sair":

No route matches "/users/sign_out"

Alguma idéia do que está causando o erro?

vich
fonte
11
Você reiniciou o aplicativo depois de adicionar as rotas? As alterações de rota só se tornam efetivas na inicialização.
Thilo-Alexander Ginkel
2
Sim. Só fiz de novo para estar seguro. Além disso, eu li em outro lugar no Stack que poderia ser um problema com a nova gema de desenvolvimento não compatível com o Rails 3.0.3, então tentei mudar minha gema de desenvolvimento de 1.4.2 para gem 'devise', :git => 'git://github.com/plataformatec/devise.git'. Isso não fez nada.
vich
Alterar a entrada no Gemfile não oferece uma versão cada vez mais nova do Devise? Você já tentou especificar um número de versão inferior?
Leo Cassarani
Você poderia postar o arquivo routes.rb
felix
11
A segunda resposta de Jessie abaixo funcionou perfeitamente.
vich

Respostas:

568

Eu acho que o caminho para sair é um DELETEmétodo. Isso significa que seu link de saída precisa ter a seguinte aparência:

<%= link_to "Sign out", destroy_user_session_path, :method => :delete %>

O seu não inclui a :method => :deleteparte. Além disso, observe que, para que isso funcione, você também deve incluir <%= javascript_include_tag :defaults %>no seu arquivo de layout ( application.html.erb).

Jessie Dedecker
fonte
3
Posso dizer com segurança que nunca tive que fazer isso em nenhum dos meus aplicativos Rails. link_to "Sign out", destroy_user_session_pathsempre foi bom o suficiente para mim.
Leo Cassarani
8
Eu fiz o teste e funciona para mim. Não esqueça que as coisas mudam de uma versão para outra (seja no Rails ou no Devise). Além disso, sair é um comportamento de mudança de estado que não deve ser feito usando os métodos GET (na minha humilde opinião).
Jessie Dedecker
23
Para obter mais informações, a razão pela qual isso foi alterado na versão mais recente do Devise é descrita aqui e aqui .
Jessie Dedecker
6
Encontrei esse mesmo problema e a sugestão de Jessie funcionou para mim. Espero que qualquer um que está sendo executado através do railscast legado para, eventualmente, acabam por aqui devido a esta mudança ...
johnnygoodman
2
você também pode digitar isso no console da web para testá-lo $("<a href='/users/sign_out' data-method='delete'>Sign out</a>").appendTo('body');- se o jQuery estiver carregado na página.
Mraroncruz
133

Eu mudei esta linha no devise.rb:

config.sign_out_via = :delete

para

config.sign_out_via = :get

e começou a trabalhar para mim.

kitdesai
fonte
22
A maneira como foi feito antes foi sair usando "GET / users / sign_out", mas eles foram alterados para "DELETE" para torná-lo mais RESTful. O autor explicou que um GET não deve fazer alterações no servidor, como sair.
Jonathan Allard
2
isso funcionou para mim. Embora eu aprecie que não seja uma prática recomendada, as outras respostas falharam. Não vejo por que !!
Fuzz suave
8
Também é possível usar uma matriz se você deseja suportar vários métodos. Por exemplo: config.sign_out_via = [ :post, :delete ]ou devise_for :users, :sign_out_via => [ :post, :delete ], conforme descrito em devise / rails / routes.rb .
Hosam Aly
2
Eu não usaria uma solicitação GET para sair, pois abre o usuário para um ataque XSRF. (O hacker cria um site com uma tag de imagem com src = " foo.com/users/sign_out ", o usuário o visita e é desconectado).
Ryan Doherty
11
@RyanDoherty Id Não me engano, o XSRF ainda é possível (o invasor só precisa usar um formulário com action = "DELETE" no URL de destino e enviá-lo automaticamente no carregamento da página).
Maël Nison 11/03/2013
60

Você provavelmente não incluiu o arquivo jquery_ujs javascript. Verifique se você está usando a versão mais recente do jquery-ujs: https://github.com/rails/jquery-ujs e os últimos arquivos disponíveis:

rails generate jquery:install

Você não deve ter mais nenhum arquivo rails.js. Se você o fizer, provavelmente está desatualizado. Verifique também se este arquivo está carregado com padrões, em config / application.rb

config.action_view.javascript_expansions[:defaults] = %w(jquery.min jquery_ujs)

(Novamente, você não deve ter o arquivo rails.js aqui). Por fim, adicione o link conforme documentado no wiki do Devise (estilo haml):

= link_to('Logout', destroy_user_session_path, :method => 'delete')

E tudo ficará bem.

Gravis
fonte
8
Eu tinha: method => 'delete' no meu link_to, o problema não foi incluído no jquery_ujs, esta solução resolveu o meu problema. Lembre-se de colocar gem 'jquery-rails' no seu arquivo de gemas.
Rob Bazinet
2
Graças isso funcionou para mim. Em vez de usar o padrão, você também pode usarjavascript_include_tag "jquery_ujs"
Bnicholas
Boa captura, obrigado! Estou usando o require.js para carregar arquivos de forma assíncrona e esqueci de exigir o jquery_ujs.
Dan Fairaizl
Eu assumi que "u" significava descompactado e removi esta linha de application.js. Má suposição, suponho. Obrigado.
Jeff
Esse problema surgiu (no meu 100º aplicativo baseado em dispositivos) depois de alterar a inicialização do twitter de menos para sass e eu esqueci de adicionar novamente o // = require jquery_ujs no meu application.js.
22415 Joe
31

A capacidade de fazer do Logout vincular uma chamada DELETE RESTful requer um atributo html data-method = "delete"usando o código rails= link_to('Logout', destroy_user_session_path, :method => :delete) .

No entanto, se você não possui a gema jquery-ujsinstalada ou não está chamando o javascript resultante em seu application.html via= javascript_include_tag "application" , a resposta será enviada como uma solicitação GET e a rota falhará.

Você tem algumas opções se não deseja usar jquery-ujsou não consegue encontrar uma maneira de fazê-lo funcionar:

  1. Altere config.sign_out_viapara igual :getdentro devise.rb(não recomendado, pois DELETE é a consulta RESTful apropriada)
  2. OU Mude link_topara = button_to('Logout', destroy_user_session_path, :method => :delete). O button_toRails fará o trabalho pesado ao fazer a chamada DELETE adequada. Você pode estilizar o botão para parecer um link, se desejar.
Will Nathan
fonte
A mudança de link_to para botão_ funcionou para mim, mas eu realmente não entendo o porquê? O que exatamente mudou além do html / css?
Spyros Mandekis
11
Tem a ver com a 'mágica' dos trilhos que gera automaticamente html a partir de funções como button_to e link_to. Acontece que a mágica dos trilhos para button_to especifica a chamada RESTful DELETE adequada e o link_to não. Se eu tivesse que adivinhar, diria que o motivo é que os elementos do botão html podem manipular uma chamada DELETE (ou agrupar com um campo oculto especificando a ação) enquanto os links regulares não.
Will Nathan
Obrigado por isso. Eu configurei meu aplicativo para manipular manualmente o jquery, para não ter o jquery-ujs. Instalar com caramanchão ou empacotador e incluir a linha apropriada para o pipeline de ativos corrige o problema.
Jrhorn424 9/09/2013
11
Esta me parece a solução mais segura e portátil.
Sobre button_to, o Rails gera um formpara toda a ação. É por isso que é possível usar o :deletemétodo com button_toe não com link_to, basta ver o HTML gerado.
Fernando Fabreti
25

Tente adicionar uma nova rota para criar / sessões # destruir e vincular a ela. Por exemplo:

routes.rb
devise_for :users do
  get 'logout' => 'devise/sessions#destroy'
end

Visão:

<%= link_to "Logout", logout_path %>
Kevin Tsoi
fonte
Obtendo o mesmo erro que mmichael. Este teste acima funciona para mim.
Rtfminc
11
Eu também tive o mesmo erro que mmichael. A solução acima funcionará, mas não é como deveria ser corrigida. As rotas padrão no Devise já incluem a rota de saída como um método DELETE. Normalmente, você não precisa alterar as rotas padrão. É por isso que você pode corrigi-lo simplesmente adicionando um parâmetro separado à link_tochamada, conforme descrito na outra resposta.
Jessie Dedecker
Você não precisa adicionar uma rota ao arquivo route.rb, o devise permite alterar o método no devise.rb, que está no diretório / confit / initializers /.
Travis Pessetto 29/07
6
Nunca tenha o caminho de logout como GET.
Jagira
@Jagira why? Por que não DELETE e GET?
Hdwdmrbl 22/10/12
14

Use-o no seu arquivo routes.rb:

devise_for :users do
    get '/users/sign_out' => 'devise/sessions#destroy'
end
Uma Maheswararao
fonte
13

Eu tive o mesmo problema com o rails 3.1.0 e resolvi adicionar no arquivo as seguintes linhas:

app/assets/javascripts/application.js
//= require_tree
//= require jquery
//= require jquery_ujs
gringo
fonte
Se estiver usando o bower, tente // = exigir jquery-ujs.
monteirobrena
10

Com uma exceção, a resposta de Jessie funcionou para mim:

<%= link_to "Sign out", destroy_user_session_path, :method => :delete %>

mudança:

:delete

... para:

'delete'

Portanto, o código que funcionou para mim é:

<%= link_to "Sign out", destroy_user_session_path, :method => 'delete' %>
Galen
fonte
Obrigado por postar este snippet de código, o sign_out funciona para mim agora.
Buk
9

Muitas respostas para a pergunta já. Para mim, o problema era duplo:

  1. quando eu expandir minhas rotas:

    devise_for :users do 
       get '/users/sign_out' => 'devise/sessions#destroy'
    end
  2. Eu estava recebendo um aviso de que isso é depreciado, então substituí-o por:

    devise_scope :users do
       get '/users/sign_out' => 'devise/sessions#destroy'
    end
  3. Eu pensei em remover meu jQuery. Má escolha. O Devise está usando o jQuery para "falsificar" a solicitação DELETE e enviá-la como GET. Portanto, você precisa:

    //= require jquery
    //= require jquery_ujs
  4. e, claro, o mesmo link que muitos mencionados anteriormente:

    <%= link_to "Sign out", destroy_user_session_path, :method => :delete %>
Lukasz Muzyka
fonte
você pode explicar 3ª point..i foi uma vítima dela e eu quero entendê-la mais
Rahul Dess
11
Certamente. Seu site não está realmente enviando solicitações DELETE. Francamente, ele usará apenas GET e POST. Como na comunidade Rails, foi acordado que (por boas razões) queremos excluir registros ao enviar a solicitação DELETE, precisamos usar um pequeno truque. No ERB, você especifica o método:: delete rails que o converterá em tag HTML5: data-method = "delete" e o enviará como GET. Agora, é aqui que entram o jQuery-ujs e o jQuery. Eles permitem que o aplicativo reconheça que é isso que você está fazendo. Para que sua solicitação possa corresponder à ação do controlador.
Lukasz Muzyka
sem essas jóias, isso não vai funcionar. Obviamente, você pode alterar as configurações do dispositivo (no inicializador do dispositivo) e solicitar que ele use GET em vez de DELETE.
Lukasz Muzyka
7

Adicionar:

  <%= csrf_meta_tag %>  and 
  <%= javascript_include_tag :defaults %>  to layouts

Use essas tags link_to

 link_to 'Sign out', destroy_user_session_path, :method => :delete

  or

 link_to 'Sign out', '/users/sign_out', :method => :delete

Em rotas, adicione:

  devise_for :users do
    get '/users/sign_out' => 'devise/sessions#destroy'
  end
Amal Kumar S
fonte
7

Outra opção é configurar o logout para ser um GET em vez de um DELETE, você pode fazer isso adicionando a seguinte linha em /config/initializers/devise.rb

config.sign_out_via = :get

Mas, como Steve Klabnik escreveu em seu blog (http://blog.steveklabnik.com/2011/12/11/devise-actioncontroller-routingerror-no-route-matches-get-slash-users-slash-sign-out.html) ) tente usar DELETE devido à semântica deste método.

Rodrigo Flores
fonte
Somente esta resposta funcionou para mim para Devise 3.5.1 e Rails 4.2.3
sagar junnarkar
Não se esqueça de reiniciar o servidor :)
jackmin
6

Se você estiver usando o Rails 3.1, verifique se o logout application.html.erb se parece com:

<%= link_to "Sign out", destroy_user_session_path, :method => :delete %>

E que sua linha de inclusão javascript se parece com a seguinte

<%= javascript_include_tag 'application' %>

Meu palpite é que algumas gemas substituem a nova estrutura do local default.js.

StlTenny
fonte
Obrigado! Isso estava me deixando louco!
Dorian
5

Bem, pessoal para mim foi apenas remover o: method =>: delete

<%= link_to('Sign out', destroy_user_session_path) %>
sonhador
fonte
5

Isso significa que você não gerou os arquivos jquery depois de instalar o gem jquery-rails. Então, primeiro você precisa gerá-lo.

rails generate devise:install

Primeira opção:

Isso significa que você deve alterar a seguinte linha em /config/initializers/devise.rb

config.sign_out_via =: apague para config.sign_out_via =: obtenha

Segunda opçao:

Você altera apenas esta linha <%= link_to "Sign out", destroy_user_session_path %>para <%= link_to "Sign out", destroy_user_session_path, :method => :delete %>no arquivo de exibição.

Normalmente :method => :deletenão é gravado por padrão.

Deepak Lamichhane
fonte
5

Quero acrescentar isso, mesmo que seja um pouco antigo.

o link "sign_out" não funcionou, apesar de ter: method =>: delete.

O comentário indicando que <%= javascript_include_tag :defaults %>deve ser incluído me lembrou que eu adicionei recentemente o script java JQuery e usei <script src=""/>tags simples para incluí-las.

Quando os mudei de após os padrões: para antes, o sign_out começou a funcionar novamente.

Espero que isso ajude alguém.

Greg
fonte
5

A maioria das respostas é parcial. Eu bati esse problema muitas vezes. Duas coisas precisam ser abordadas:

<%= link_to(t('logout'), destroy_user_session_path, :method => :delete) %>

o método de exclusão precisa ser especificado

Em seguida, o devise usa jquery, então você precisa carregar aqueles

   <%= javascript_include_tag "myDirectiveJSfile" %> 

e verifique se AMBOS jquery e jquery-ujs estão especificados em myDirectiveJSfile.js

//= require jquery
//= require jquery_ujs
Jerome
fonte
5

Não esqueça de incluir a seguinte linha no seu application.js (Rails 3)

//= require_self
//= require jquery
//= require jquery_ujs

Incluir jquery_ujsno meu aplicativo de trilhos e ele funciona agora.

The Lazy Log
fonte
4

Se você estiver usando HTTPS com dispositivo , ele será interrompido se o link de logout for para a versão não segura. No back-end, ele redireciona para a versão segura. Esse redirecionamento é um GET, que causa o problema.

Verifique se o seu link usa HTTPS. Você pode forçá-lo protocol: "https"no seu auxiliar de url (certifique-se de usar o auxiliar de url e não o auxiliar de caminho).

<%= link_to "Sign out", destroy_user_session_url(protocol: "https"), method: :delete %>
Tyler Collier
fonte
4
  devise_for :users
  devise_scope :user do
    get '/users/sign_out' => 'devise/sessions#destroy'
  end
dipole_moment
fonte
3

O problema começa com o rails 3.1 ... /app/assets/javascript/basta procurar pelo application.js.

Se o arquivo não existir, crie um arquivo com esse nome, não sei por que meu arquivo desapareceu ou nunca foi criado "rails new app"....

Esse arquivo é a instância para jquery....

rome3ro
fonte
3

Muitas soluções estão lá. mas principalmente usa isso,

<%= link_to 'Sign out', destroy_user_session_path, method: :delete %>

ou config devise.rb com o método sign_out apropriado

Em devise.rb

config.sign_out_via = :delete ( or  :get which u like to use.) 
Jon Snow
fonte
3

use :gete :deletemétodo para o seu caminho:

devise_scope :user do
  match '/users/sign_out' => 'devise/sessions#destroy', :as => :destroy_user_session, via: [:get, :delete]
end
Zakaria
fonte
Nota: deve haver devise_for: users declarado separadamente disso. veja a resposta de dipole_moment.
Taylored Websites
2

Em suas rotas.rb:

 devise_for :users do
    get '/sign_out' => 'devise/sessions#destroy'
    get '/log_in' => 'devise/sessions#new'
    get '/log_out' => 'devise/sessions#destroy'
    get '/sign_up' => 'devise/registrations#new'
    get '/edit_profile' => 'devise/registrations#edit'
 end

e no seu application.html.erb:

<%if user_signed_in?%>
          <li><%= link_to "Sign_out", sign_out_path %></li>
<% end %>
Matz Heri
fonte
11
A sintaxe é agora: devise_for: usuários, em seguida, o obtém deve ser colocado em devise_scope: user fazer NOTA: singular: usuário para devise_scope
taylored Sites Web
2

Foi o que fiz (com o Rails 3.0 e o Devise 1.4.2):

  1. Verifique se sua página carrega rails.js
  2. Use este parâmetro: 'data-method' => 'delete'
  3. Boa ideia para adicionar este parâmetro:: rel => 'nofollow'
Larry
fonte
1

Veja se o seu routes.rb possui um "resource: users" antes de um "devise_for: users" e tente trocá-los:

  1. Trabalho

    • devise_for: usuários
    • recursos: usuários
  2. Falha

    • recursos: usuários
    • devise_for: usuários
Charles Magid
fonte
1

o ':method => :delete'na página é' data-method="delete"', portanto, sua página deve ter jquery_ujs.js, ela enviará o link com o método delete e não o método get

user1599712
fonte
1

Eu sei que essa é uma pergunta antiga baseada no Rails 3, mas acabei encontrando e resolvendo-o no Rails 4.0.4. Então, pensei em explicar como o corrigi para qualquer pessoa que encontre esse problema com esta versão. Sua milhagem pode variar, mas eis o que funcionou para mim.

Primeiro, verifique se você tem as gemas instaladas e execute a instalação do pacote.

gem 'jquery-rails'

gem 'turbolinks'

gem 'jquery-turbolinks'

No application.js, verifique se tudo é necessário, como abaixo.

Cuidado se isso pegar : é //= require jquery.turbolinkse não//= require jquery-turbolinks

//= require jquery
//= require jquery_ujs
//= require jquery.turbolinks
//= require turbolinks
//= require_tree .

Em seguida, adicione os links apropriados no cabeçalho de application.html.erb.

<%= javascript_include_tag  "application", "data-turbolinks-track" => true %>
<%= javascript_include_tag :defaults %>

Parece haver muitas variações de como implementar o método delete, que eu assumo depende da versão do Rails que você está usando. Essa é a deletesintaxe que eu usei.

<p><%= link_to "Sign Out", destroy_user_session_path, :method => 'delete' %></p>

Espero que ajude a tirar alguém desse buraco muito frustrante!

mikeym
fonte
0

Em geral, quando você obtém "Nenhuma rota correspondente", mas acha que tem essa rota definida, verifique o método http verb / request (seja obtendo, colocando, postando, excluindo etc.) dessa rota .

Se você executar rotas rake, verá o método esperado e poderá compará-lo com o log de solicitações.

Muntasim
fonte