Я использую гем devise для организации авторизации...

Creato il: 5 giugno 2025

Risposto usando O4 Mini High da Chat01

Domanda

изображение.pngизображение.png

Я использую гем devise для организации авторизации в моем rails приложении. При нажатии на кнопку log out у меня возникает такая ошибка

<nav class="navbar navbar-expand-lg"> <div class="container"> <h1 class="navbar-brand text-white fs-4 fw-bold"><%= t('application.header.title') %></h1> <div class="d-flex justify-content-end"> <%= render partial: 'layouts/partials/language_dropdown' %> <% if user_signed_in? %> <%= link_to current_user.name, edit_user_registration_path, class: "btn btn-lightpink me-2" %> <%= link_to t("application.header.menu.log_out_button"), destroy_user_session_path, method: :delete, class: "btn btn-darkpink me-2" %> <% else %> <%= link_to t("application.header.menu.sign_up_button"), new_user_registration_path, class: "btn btn-lightpink me-2" %> <%= link_to t("application.header.menu.log_in_button"), new_user_session_path, class: "btn btn-darkpink me-2" %> <% end %> </div> </div> </nav>

routes.rb

frozen_string_literal: true

Rails.application.routes.draw do
devise_for :users

Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.

Can be used by load balancers and uptime monitors to verify that the app is live.

get 'up' => 'rails/health#show', as: :rails_health_check

Render dynamic PWA files from app/views/pwa/*

get 'service-worker' => 'rails/pwa#service_worker', as: :pwa_service_worker
get 'manifest' => 'rails/pwa#manifest', as: :pwa_manifest

get '/', to: redirect('/en')

scope '(:locale)', locale: /en|ru/ do
root 'pages#home'
end

Defines the root path route ("/")

root "posts#index"

end
в config/initializers/devise.rb есть строка config.sign_out_via = :delete
Как исправить

Pensiero

Diagnosing routing issue

I’m looking at an error where Rails doesn’t match the DELETE method route for signing out because a GET request is being sent instead. This might be attached to the issue of missing JavaScript, since Rails’ link_to with method: :delete requires UJS (Unobtrusive JavaScript). If JavaScript isn’t loaded properly, it defaults to GET, causing the error. The fix? Make sure the Rails UJS is properly included in your application.js file (either //= require rails-ujs or import Rails from '@rails/ujs'; Rails.start() for Webpacker).

Thought for 7 seconds

Risposta

Ошибка возникает из-за того, что Devise по умолчанию ожидает, что запрос на выход будет отправлен методом DELETE, а ваша ссылка без подключённого JS отправляет его как GET. В результате Rails пытается обработать GET-запрос на «/users/sign_out», а такого маршрута нет (см. destroy_user_session_path в rake routes — он настроен только на DELETE).

Способы решения

  1. Убедиться, что Rails UJS (или jquery-ujs) действительно подключён и работает

    Devise-овская ссылка:

    erb
    <%= link_to t("application.header.menu.log_out_button"), destroy_user_session_path, method: :delete, class: "btn btn-darkpink me-2" %>

    рассчитывает на то, что через JavaScript (Rails UJS) будет сгенерирован настоящий DELETE-запрос. Если на странице не подключён или не инициализируется rails-ujs (или, в старых версиях Rails, jquery-ujs), браузер просто отправляет обычный GET, и вы получаете «No route matches [GET] "/users/sign_out"».

    Проверьте в app/views/layouts/application.html.erb, что у вас есть:

    erb
    <head> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track": "reload" %> <%= javascript_include_tag "application", "data-turbolinks-track": "reload" %> </head>

    и в app/javascript/packs/application.js (или app/assets/javascripts/application.js, в зависимости от того, чем вы собираете ассеты):

    js
    // Для Rails 6+ (Webpacker + rails-ujs): import Rails from "@rails/ujs" Rails.start() // (Если используете Turbolinks, то затем import "turbolinks"; Turbolinks.start(); и т.д.)

    или (для старых версий Rails с Sprockets):

    js
    //= require rails-ujs //= require turbolinks //= require_tree .

    После этого перезапустите сервер и проверьте в браузере в консоли разработчика, что на странице загружен rails-ujs и что при клике на ссылку «Выход» срабатывает JavaScript (метод должен меняться на DELETE). Если JS не грузится — браузер будет делать GET.

  2. (Менее предпочтительный вариант) Сменить способ выхода на GET

    Если по каким-то причинам вы не хотите (или не можете) подключать UJS, можно заставить Devise принимать выход по GET-запросу. Для этого в файле config/initializers/devise.rb замените строку:

    ruby
    config.sign_out_via = :delete

    на

    ruby
    config.sign_out_via = :get

    После этого ссылка

    erb
    <%= link_to t("...log_out_button"), destroy_user_session_path, class: "btn btn-darkpink me-2" %>

    без method: :delete будет работать как GET, и Rails найдёт маршрут. Но этот способ менее безопасен (CSRF-уязвимость), поэтому рекомендуется всё же сделать первый пункт.


Итого: наиболее корректный путь — убедиться, что в вашем проекте подключён и инициализируется rails-ujs (или jquery-ujs), чтобы link_to ... method: :delete действительно посылал DELETE-запрос. Если же вы не хотите/не можете подключать JS-обработку, можно временно поменять config.sign_out_via на :get, но помните о рисках.

Condividi questa Q&A