Tag Archives: ruby on rails

How to authenticate one scope from another with Devise

My app has multiple kinds of users, some of which belong to others. It's a result of having many disparate login systems, one per community, and offering the ability to merge them together. This is how I auth the One True account from the local account.

I banged my head on this for a while: what I wanted to do was to just take the

user.one_true_master_account

model and go from there, but the current_#{scope} helpers aren't available in a devise strategy. So I did some digging and figured out how to do it with warden without dragging in more than I had to. (this is in config/devise.rb)

FromUserAuthentication
  class FromUserStrategy < Devise::Strategies::Authenticatable
    def valid?
      # I'd have to authenticate to figure out if it's valid anyway, but I'd
      # rather run it in the devise auth chain 
      true
    end

    def mapping
      Devise.mappings[:one_true_master_account]
    end

    def authenticate!
      # env here is provided in the superclass, it's that enormous hash that 
      # gets passed to middlewares
      user = env['warden'].authenticate(scope: :one_true_master_account)
      if user
        one_true_master_account = user.one_true_master_account
        success!(one_true_master_account)
      end
    end
  end
end

Then I registered it with the various subsystems that needed to know about it

Warden::Strategies.add :from_user_authentication,
                       FromUserAuthentication::FromUserStrategy
Devise.add_module :from_user_authentication, strategy: true

Then I added it as a default strategy for that scope.

Devise.setup do |config|
  config.warden do |manager|
    manager.default_strategies(:some_other_auth_strategy, :another_auth_strategy,
                               :from_user_authentication,
                               scope: :one_true_master_account)
  end
end

This last one is necessary only because of a quirk in our system. Warden can look at the mapping function to figure out which strategies are appropriate in most other situations, but we wanted to have our strategies in different orders for different models.

The Open Source Soap Opera

There's a mildy famous aphorism that "Starting Rails today is like starting to watch a soap opera in the 7th season." It applies to other technology, too, which is why I was totally at a loss when I tried to figure out a client Javascript framework to start refactoring a jungle of custom routes and hand-rendering code. Of course, you can't just Google for the answer to what-should-I-use kinds of questions because you'll just wind up on an article titled Knockout vs Backbone vs Ember vs Angular vs Dart vs Clojurescript vs Twelve Other Things that doesn't actually recommend anything but just throws up it's hands and says "Why don't you try them all, and see what works for you!"

(If you're thinking about writing a comparison article, you should know that the cop-out is same as telling the reader to go fuck themselves. I don't want to try them all, I want to ship the damn thing.)

I started doing Rails at Castle Ridge Media because I got to pick and I knew that I should either learn Rails or Django. I'd heard Rails was better, but I knew numpy was better than anything in ruby, and my choice ultimately came down to avoiding the soap opera around the transition from python 2 to 3, which, by the way, is still going on, and now I'm two years into a web tech and the stats libraries are atrocious. There are many alleged options, some of which don't compile through gem because they're too special and others that, while technically working, are just c wrappers, and a few others that I've forgotten. All the Google searches for problems with any of them tend to turn up "Problems with x, you should be using y!" kind of answers, which would be great except that all the answers for y tell you to use z or x. Arg, can't get it right either way.

(As I don't like telling people to fuck themselves, I went with Ruby::GSL)