devise: Rails 5 API doesn't work with devise, throws undefined local variable or method `flash'

The new rails 5 API doesn’t work with devise (v4.2.0). To reproduce:

  1. rails new my_api --api
  2. Follow steps of installing devise (adding gem, running rake commands).
  3. Try accessing sign_in with a valid user with something like that: curl -X POST -F "user[email]=example@example.com" -F "user[password]=example" localhost:3000/users/sign_in

It throws an error like this:

NameError (undefined local variable or method `flash' for #<Devise::SessionsController:0x007fb8b8814250>)

Due to this line of code.

Something as simple as this commit, makes it work: https://github.com/johndel/devise/commit/c870213ee57b71ac580784979b46c7aab8863a2a

Update: Seems that if you call it with .json at the end it works (like this curl -X POST -F "user[email]=example@example.com" -F "user[password]=example" localhost:3000/users/sign_in.json).

Update 2: Seems like adding the .json at the end of the sign_in.json url worked, but in other endpoints didn’t, like /password/edit.json.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 15

Commits related to this issue

Most upvoted comments

Found the solution. For a rails --api application, set “config.navigational_formats = []”. Then devise will never attempt to use flash and never throw a 500 error. I suspect this may be a good candidate for adding to the documentation.

As far as my understanding goes, you shouldn’t be using Devise with an API only rails app. Devise depends on session and cookies, and you should not be using those for an API An API is not the use case for Devise so these are really not bugs with the gem

In routes.rb add json format to devise_for: devise_for :users, defaults: { format: :json }

I share @gssbzn 's point of view. However, I have been struggling to find the most concise Authentication implementation for a Rails 5 API.

Some implementations use http_secure_token (or something like that), devise_token_auth, Warden implementations, etc. etc.

Would appreciate any tips on what is the most straightforward way to implement Authentication for Rails 5 API.

I’ve gotten devise working fairly well for an API app; I added JWT tokens as a warden strategy, so a user hits a devise login endpoint, receives a JWT, and subsequently uses that JWT to authorize access to the actual API endpoints. Still need to add token blacklisting (possibly a small memcached store) for logouts and token refreshing, but the rough skeleton is working, and behaving fairly well.

If the PasswordsController gets fixed to respect navigational formats, I don’t necessarily think a new framework is required. Creating some help documentation with pointers on configuring devise for an API-only app would probably help.

I agree with John that this is an issue. The PasswordsController#edit does not respect navigational formats. (I did not check if this concerns other controllers, too.)

This could be fixed by using set_flash_message! instead of set_flash_message here.

Using config.navigational_formats = [] throw an error

<ActionController::UnknownFormat: ActionController::UnknownFormat>

config.navigational_formats = []

Thanks, this worked for me, as well as this one config.navigational_formats = [ :json ] I am using Rails 7.0.3 with Ruby 3.1.1

im agree with @Ikariusrb but use of defaults: { format: :json } also solve my problem in this way

` devise_for :users

namespace :eatery_book do namespace :api , defaults: { format: :json } do namespace :v1 do

  devise_scope :user do
  post "sign_up", to: "registrations#create"
  post "sign_in" , to: "sessions#create"
  delete "log_out", to: "sessions#destroy"

  end`

At risk of stating the obvious, seems Rails 5 API needs a Devise caliber authentication gem, does anyone know of a solution or if anyone is working on one?

Trying to figure out how to best support both a traditional Rails web application with session and cookies (Devise like) and mobile apps (Token auth like) ?

Don’t really want to re-write my web application as a single page web app / Angular or such.

I will chime in that I suspect this is more of an issue that it appears at first blush.

I’m attempting to use devise with a rails --api (5.0.0.1) application, and while it does the correct thing if an end-user submits a request with the correct type, it throws a 500 if a user tries to do a simple html format GET from one of my endpoints without providing authorization, rather than returning a proper 401.

I could limit routes to specific formats (btw, anyone yet figure out how to use route constraints to limit routes to jsonapi format?), which will then throw an unknown route error, but I can’t control what formats users may throw requests at my server in; I’d like to respond appropriately. While attempting to do the right thing based on the requested format makes sense, having to override the entirety of devise error handling in order avoid internal server errors if an end-user fails to set the correct type seems broken.

Perhaps addition config flag to never use flash would be appropriate?