giant robots smashing into other giant robots

We are thoughtbot. We make web & mobile apps.

Tagged:

Comments (View)

Always remember me

Clearance now uses only cookies with a long expiration as its default. The effect is always remembering the user unless they ask to be signed out.

“I’ll never let go, Jack! I’ll never let go!”

The only place to go after the Care Bears is the Titanic.

A better “remember” default

A couple of weeks ago, I asked how Clearance should handle “remember me”

PJ Hyett’s argument won the day:

Assuming people using shared computers can’t remember to log out is insulting at best and annoying to everyone else that has exclusive access. Cookies with long expirations should always be the default.

Clearance, as of today’s 0.8.2 release, works exactly this way.

Cleaner under the hood

Fewer conditionals. No special cases. Just do one thing well.

       def current_user
-        @_current_user ||= (user_from_cookie || user_from_session)
+        @_current_user ||= user_from_cookie
       end

       def user_from_cookie
         if token = cookies[:remember_token]
-          return nil  unless user = ::User.find_by_remember_token(token)
-          return user if     user.remember?
+          ::User.find_by_remember_token(token)
         end
       end

If you look through the recent commits, it’s a glorious sea of red as lines of code were removed.

Deprecations of shoulda macros

Originally, we had between a dozen and two dozen shoulda macros. They’re almost all deprecated now, continuing a trend over the last six months. The macros that have survived are:

sign_in_as(Factory(:email_confirmed_user))
sign_in
sign_out
should_deny_access
should_forbid

Want to upgrade?

You’ll want to:

  • migrate your schema
  • watch out for a cookies gotcha
  • regenerate Cucumber features
  • remove the “remember me” checkbox!

Migrate your schema

If you decide to upgrade, you’ll need to migrate your database schema, as we also finally addressed the “double duty” that token/token_expires_at used to play. It is now split into a confirmation_token and a remember_token.

Cookies gotcha

Like most things in software, this decision comes with a tradeoff. When cookies are set, they are not available until the next request.

So be careful with functional tests that depend that cookies. Try to use the current_user method where possible.

Cucumber features

This is a minor change. They mostly combine “remember me” scenarios into the basic scenario. If you don’t want to run the generator again, you can probably figure out what needs to be altered on your own.

Issues

As always, if you find any issues, please report them at Github Issues. Thanks and happy coding!

Tagged:

Comments (View)

Blossom the lovely stars, the forget-me-nots of the angels

“Silently, one by one, in the infinite meadows of Heaven, Blossom the lovely stars, the forget-me-nots of the angels.” Evangeline by Henry Wadsworth Longfellow

You’re writing a Rails app. You want users to be able to sign in.

You decide to use Clearance.

How do you expect it to handle “remember me” out of the box?

Remember unchecked by default

Basecamp:

Basecamp

Gmail:

Gmail

Remember me checked by default

Eventbrite:

Eventbrite

No remember me, automatically sets a cookie

Github:

Github

Tumblr:

Tumblr

What should an authentication framework prefer?

Right now, Clearance comes with remember unchecked by default. I’m leaning towards changing it to checked by default.

What do you think?

Tagged:

Comments (View)

Clearance: Rails authentication for developers who write tests

Authentication is a common pattern in Rails apps. Thus, there have been many authentication plugins. We’ve tried acts_as_authenticated and restful_authentication over the years.

We found that user authentication is hard to generalize. Most abstracted authentication plugins had both too much and too little for us.

We then tried writing authentication from scratch on our clients’ Rails apps for about a year. We felt better about test coverage but it was still a pain to re-write similar code. App after app, we talked about extracting common code into a library. Each time we resisted.

After a while, we made the decision that maybe 60% of authentication could be re-used. We extracted Hoptoad’s authentication at last year’s Lone Star Ruby Conference, then merged code from two of our clients’ apps. We named the gem Clearance.

On the first attempt, we went overboard on re-use. We backed off and Mike wrote hooks in places we were finding logical extension points. For the past few months, patches have trickled in from Github and we’ve carefully included code that fits in the “60%”.

We recently started a new project. In the process, we’ve polished the gem and are happy to announce its official release.

Clearance

  1. Sign up
  2. Confirm email
  3. Sign in
  4. Sign out
  5. Reset password

Get version 0.4.5 on Github.

Modules, Shoulda, & Factory Girl

Clearance is focused on maintainability of your application’s authentication code.

  • Include comprehensive Shoulda & Factory Girl tests in your Rails app’s test suite.
  • Encapsulate authentication logic in modules which are included in your controllers, models, & tests.

This approach keeps your Rails application’s code clean and alerts you if you ever break your authentication code.

Due to the work we’ve been doing to make Shoulda test framework-agnostic, you will be able to use RSpec in the 0.5.0 release of Clearance.

Test::Unit and Cucumber features are already supported:

script/generate clearance
script/generate clearance_features

Conventions

To keep our approach simple, we made a series of design decisions:

  • User model required.
  • User model uses attr_accessible.
  • Authenticate by email (not username) & password.
  • Users must be confirmed via email.
  • Vocabulary restricted to Trinity of Signs: “sign up”, “sign in”, “sign out”

Beyond

Clearance does not try to be a Swiss Army knife but it does have some hooks if you want admin roles, sign up and sign in by username in addition to email, or something else.

Please report bugs and request features on Clearance’s Lighthouse account.

There is also a mailing list for questions.

Tagged:

Comments (View)

The Emerging Standards Bureau

So I’ve been trying to enforce some halfway-arbitrary-but-plausibly-correct standards in my own code lately. Specifically, I’ve been looking at a certain class of helper method naming patterns we’ve been using for a while, and thinking about how to be most consistent across some different scenarios.

I’m pretty sure that the pattern leading up to this decision is actually pretty well known and well followed, but I’ll pretend I don’t know that, and walk through the evolution of how I got to where I am, so you’ll understand what’s keeping me up at night.

Let’s say you have an application with posts. They’re probably written by users. I bet they’re all about interesting things, too. But, you’ve got to get them!

First you do something like this…


class PostsController < ApplicationController

  def show
    @post = Post.find params[:id]
  end

end

Ok, that’s fine. This uses a normal rails route, will raise (and be caught for a 404) if it doesn’t exist, etc. Let’s say v1 of this app launches to great acclaim, as the entire internet embraces the interesting stuff you say in your posts.

Ok, requirements change – posts#show needs to be scoped to the user who is logged in. Not only that, but lots of other stuff in v2 of the app is going to need to know about the user who is logged in, and the design team wants some way to refer to this user in the views.

So you do this in the application controller…


class ApplicationController < ActionController::Base
  
  before_filter :load_user
  
  protected
  
  def load_user
    @user = User.find_by_id session[:user_id]
  end

end

Ok, great. Now the entire application can refer to @user and know what it means. Also, if it’s nil, designers can do something special to not refer to the user.

Now you can do this in your posts_controller, which will scope the Post that gets loaded on #show to only load if it’s owned by the logged in user.


class PostsController < ApplicationController

  def show
    @post = @user.posts.find params[:id]
  end

end

Great, the requirements are met. Version 2 launches to even more critical acclaim, as all site users applaud your efforts to only show them their own posts.

Now the business team gets together and they want site users to be able to view other users and then be frustrated when they can’t view their posts. So you set about implementing the users_controller and a new set of views for it. But wait! What about the users_controller’s #show action!?


class UsersController < ApplicationController

  def show
    @user = User.find params[:id]
  end

end

Thats not gonna fly. We’re already setting @user up at the global level. Maybe that was a bad idea. Yup, that was a bad idea. We can’t hold our actions responsible for things they didn’t do, can we?

Let’s refactor that into a method instead of a before_filter in the application controller…


class ApplicationController < ActionController::Base
  
  protected
  
  helper_method :current_user
  def current_user
    @_current_user ||= User.find_by_id session[:user_id]
  end

end

…and now change your posts controller as well…


class PostsController < ApplicationController

  def show
    @post = current_user.posts.find params[:id]
  end

end

Thats much better. We satisfy all the requirements, and now the users controller can use @user until the cows come home. Version 3 is wildly popular, since the egomaniacal user base that’s been reading their own posts for so long turns out to really love the opportunity to see other users whose posts they cannot read!

Well, some time goes by and we introduce commenting. The business team, geniuses that they are, have realized that users who love reading their own posts are really gonna go nuts about commenting to themselves! So we’re Modern Web Designers, and we want to build an application with RESTful urls. For example, the “collection of all comments on a post” page might be something like…

/posts/:post_id/comments

So in the comments_controller we’re going to do…


class CommentsController < ApplicationController

  def index
    @post = Post.find params[:post_id]
    @comments = @post.comments.find :all
  end

end

Well, we had a tight deadline, but we got the feature done. The users of version 4 are happy with their new commenting abilities. But no one likes that code. Why do I need that @post variable? We’re not even using it in the views, it’s there for nothing. What could have been a one line action is a two line action, and that’s one line too many, hence I’m going to be kept up at night until we sort this out in the 4.x series.

While we’re looking at removing that extra line, we realize that using params[:post_id] all over the place is getting a bit tedious as well. Why dont we build another helper method?


class ApplicationController < ActionController::Base
  
  protected
  
  helper_method :current_post
  def current_post
    @_current_post ||= Post.find_by_id params[:post_id]
  end

end

Ok, that works. What does that do to our controller?


class CommentsController < ApplicationController

  def index
    @comments = current_post.comments.find :all
  end

end

Ah, that’s better, isn’t it? We’re back to one line, and our designers can use #current_post in the same way they’ve become accustomed to using #current_user throughout the views. Good job.

Now, in the midst of our refactoring release we find out that the next version is going to use the “account as subdomain” pattern (where http://.someapp.host scopes which account is in use). To solve that problem, we’re going to embrace this pattern again and do something like…


class ApplicationController < ActionController::Base

  protected

  helper_method :current_account
  def current_account
    @_current_account ||= Account.find_by_keyword request.subdomains.first
  end

end

Man, isn’t this great? Our designers have access to #current_user to get the logged in user from the session, #current_post to get the requested post from the params/routes, and #current_account to inspect the subdomain from the hostname and get an account. They’re just giddy, and we can sit back and look at some pretty well organized code.

Our account as subdomain feature release goes really well. The sort of person that loves to comment on their own posts which no one else can see, REALLY likes to get a username.service.host hostname to do this all on!

So now the business team wants to add a bunch of features and we run into a bit of a naming crunch.

  • When they ask to list all posts by a user under an account, we dont know if #current_account means “the account at this subdomain” or “the account from params[:account_id]”
  • When they ask to show the accounts held by a user (yes, a user can have multiple vanity subdomains), we don’t know if #current_user is from the session or the params
  • …etc.

Clearly a big mess, clearly a lot of sleep to lose, clearly some refactoring to be done.

Now, to step back. Remember at the beginning when I said there were some patterns I took for granted. That’s everything up to here. Now is where I introduce some draconian naming policies and insist they always be followed.

This pattern we have is great. We avoid creating more instance variables then we need to, and (in my opinion), the readability of all the #current_* methods is better than having either instance vars or params references everywhere. But now we’re using the same #current_* method naming for three different things…

Get something from the session ie, #current_user based on session[:user_id]
Get something from the routes/path ie #current_post from params[:post_id]
Get something from the hostname ie, #current_account from request.subdomains.first

Having gone through all of that, I’m on a quest for some new naming.

My current thinking is to use ‘session_’, ‘current_’ and ‘request_’ as the method prefixes, to refer to getting something from the session, params and request/host information, respectively. Examples…

#session_user User record based on session[:user_id]
#current_post Post record based on params[:post_id]
#request_site Site record based on request.hostname

Does anyone else use this pattern? Is there a better naming convention to use? Was my story entirely too long to explain a relatively simple question? Inquiring minds want to know.

Tagged:

Comments (View)

Built-in XSS protection in rails will confuse you

If you do rails development of multiple applications simultaneously on a machine that you access with one hostname – but using different ports for the different applications – you might end up with a problem.

The problem will be that you’ll have a cookie set in your browser which ties you into a session for one of the applications, and then you’ll try to hit the second application, and you’ll get an empty screen and a 403 error in the logs, with little else to go on.

This is a little-documented built-in defense against cross site scripting, but you won’t know that when you keep getting empty screens back from your otherwise correct application.

You can solve this by either deleting your cookies for that domain/host, or by deleting the session store for the applications.