heartcombo / devise

Flexible authentication solution for Rails with Warden.
http://blog.plataformatec.com.br/tag/devise/
MIT License
23.89k stars 5.54k forks source link

default_strategies empty in production #1139

Closed adamcrown closed 13 years ago

adamcrown commented 13 years ago

I've been dealing with a strange issue recently. I have a custom Devise extension that I've been using for some time. All of the sudden on a deploy to a new server (Ubuntu 10.04.2, RVM ruby-1.9.2-p180, Rails 3.0.8) it's not working in production mode. But works fine in development.

The only strange thing about this app is that all of the devise functionality is contained inside the manage namespace. We're using the same extension on multiple other sites but not namespaced and it works fine in production. We're also running the same app on an old CentOS server (Ruby 1.8.7) and it works fine being namespaced in production. So I don't think it's really a problem with my extension but I'm not 100% sure.

I've fond a work-around which is to set this in my config/initializers/devise.rb file.

config.warden do |manager|
  manager.default_strategies(:scope => :manage_user).unshift :netid_authenticatable
end

And that's fine but it seems like there is a deeper issue that should be addressed. After digging around the code for a while the real problem seems to be that Devise.warden_config[:default_strategies] returns {:manage_user=>[]} in production and {:manage_user=>[:netid_authenticatable, :rememberable]} in development.

I've tried to figure out where default_strategies is being set by digging around in Warden and Devise but I'm at a loss. I'm willing to continue debugging this issue myself but I need some insight into where to look in the Devise and/or Warden code.

josevalim commented 13 years ago

Can you isolate this issue in an application that you could upload to Github? If so, it would help us investigate the problem!

adamcrown commented 13 years ago

Okay, so I started to put together a new Rails app from scratch to reproduce the issue and everything worked fine on the new app. So I dug a bit deeper and it turns out that the issue has something to do with ThinkingSphinx. One of the engines in my app has an initializer that does a class_eval on a model that includes a define_index call. If I comment out the class_eval line in my engine or the define_index line in the model, everything works.

I'm still not sure what the underlining issue is though. I'll see if I can get thinking_sphinx added to my example app so that the issue can be explored further.

josevalim commented 13 years ago

Any news? Do you think you can push the sample app to Github?

adamcrown commented 13 years ago

I finally got around to throwing together an example app.

I've added a readme but basically the master branch is broken and there are three fixed branches. I found that the best fix for the issue is to specify the models you want indexed in config/sphinx.yml.

I found a very similar issue on Stack Overflow that led me to the sphinx.yml fix.

One thing to note is that in development you'll get routing errors. I didn't see them because I unknowingly had settings for development in my sphinx.yml file but not for production. In production you won't get the routing errors but you still won't be able to login.

So there's definitely some weird stuff going on. In the end the sphinx.yml is an easy fix. But it would be nice to see Devise and Thinking Sphinx work better together to avoid any pain for anybody else down the road.

Thanks for all your help on this, Jose. I really appreciate it. And let me know if there's anything else I can do to help.

josevalim commented 13 years ago

Maybe, if you don't specify the models you want indexed, thinking sphinx will load all models very early, busting devise? /cc @freelancing-god

pat commented 13 years ago

Thanks for the note, Jose. I'll investigate further, just bundling the test app now - but I've used Devise and Thinking Sphinx together on a couple of (Rails 3) apps without problems.

pat commented 13 years ago

Just reporting back on what I've found so far... it is a load issue problem - your engine's initializer causes TS to load models earlier than it normally would, and Devise hasn't loaded at that point, so the ActiveRecord::Base.devise method doesn't yet exist.

Jose, you've got a far better understanding of Rails internals (and Devise) than I do - when is that method added? Does it happen when config/initializers/devise.rb is loaded? Should engine initializers get loaded before the app's own?

Adam, what happens in your app if you call Devise (just to load it) in your engine's initializer, to make sure it's in play before Thinking Sphinx is?

josevalim commented 13 years ago

@freelancing-god nice, thanks for debugging it. Two short questions: do you know which Devise initializer is forcing it to load too early? Also, where in TS you are loading the models? Thanks man!

pat commented 13 years ago

It's the engine initializer that Adam added that's causing the problem - see vendor/plugins/test_engine/config/initializers/break_devise.rb in the example app.

As for Thinking Sphinx loading models, that happens in `ThinkingSphinx::Context#load_models, which is called the first time an index is defined (and thus, when a class with an index is referenced).

josevalim commented 13 years ago

Right, now I see, thanks! @freelancing-god, maybe instead of loading all models in thinking sphinx when the first one is loaded, what if we had a raitie callback that would be more deterministic?