Category Archives: programming

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.

How am I supposed to do my cargo cult encapsulation in AngularJS?

A computer science degree and years of engineering best practices have given me a very specific anxiety disorder. Whenever I see a public member variable, I feel intense distress. Something like:

public class Coordinate {
    double x;
    double y;
}

makes me physically ill. You know that study where the MIT Professor asked people to do mean things to Furbies?

...in a small experiment conducted for the radio show Radiolab in 2011, Freedom Baird of MIT asked children to hold upside down a Barbie doll, a hamster and a Furby robot for as long as they felt comfortable. While the children held the doll upside down until their arms got tired, they soon stopped torturing the wriggling hamster, and after a little while, the Furby too. They were old enough to know the Furby was a toy, but couldn’t stand the way it was programmed to cry and say “Me scared”.

-- Would you murder a robot?

That's how I feel about making things public that can be made private. Stop doing that to that poor class! Stop it!

Most of my work now is in AngularJS. If you're not familiar, the 101 of it is that if you want to display something, or have a form, you use a special syntax in a template and all the changes will be magically wired together and appear.

<div ng-controller="MadeUpCtrl">
 <form>
   <input type="text" ng-model="MadeUpCtrl.text">
 </form>
 <div>
   {{MadeUpCtrl.text}}
 </div>
</div>

When you type things in the form, they display in the div below without any real effort. You do have to have a variable named text in the controller, even if it has no value. (You can do {{text}} but there a lot of reasons not that I find too boring to explain now).

But wait, you conveniently ask, isn't that mucking around with some other object's internal variables? Yes, yes it is. "text" is a public member variable and we are doing terrible, terrible things to it.

The problem is that there's no real way around this. The usual getText() setText() monstrosity won't work -- it has to be a value, not a function that returns a value. How does Angular know getText() will return something different? Well, you'd have to tell it.

That creates a disaster like this. Template:

<div ng-controller="MadeUpCtrl2">
 <form>
   <input type="text" ng-model="MadeUpCtrl2.exportText">
 </form>
 <div>
   {{MadeUpCtrl2.exportText}}
 </div>
</div>

Controller:

MadeUpCtrl2 = function($scope) {
  this.text_ = "";
  this.exportText = "";
  var self = this;
  // this fires when exportText changes
  $scope.$watch(this.exportText, function(exportText) {
    self.setText(exportText);
  });
}
 
MadeUpCtrl2.prototype.setText(text) {
  this.text_ = text;
}
 
MadeUpCtrl.prototype.getText() {
  return this.text_;
}

The problem is that this is awful. If you want to do anything interesting in setText, let's say escape some html, you're going to have to push it back to exportText to make it visible, and then that's going to trigger another $watch...

Looks like I just have to live with it.