Adding Authentication with Sorcery to a Rails app using Test Driven Development (Part 1)

sorcery

sorcery is a gem for adding authentication to your Rails application. I like it. It’s not a rails engine, like devise; after you add it to your Gemfile and run the generator, you still need to set it up. That’s the great part: you need to set it up, but you then have an authentication system that you can (hopefully) understand completely, and you decide for yourself how everything should work.

I started playing around with a new Rails 4 app, and I decided to try to TDD my whole way through a sorcery setup. As I started, it seemed like it would make a good blog post, so, here it is.

To start, let’s make a new rails app.

Now we’ll just add the gem ‘sorcery’ to Gemfile.

Let’s go ahead and add gem 'capybara' to the :development, :test groups, too.

Now bundle install

The README gives a pretty good description of the various submodules that sorcery has. For now, I’m just going to add the reset_password and activity_logging modules.

We need to run sorcery’s generator. run bin/rails g sorcery:install --help to see some options (this same text is also within the README)

This creates some migrations and updates some files:

Great! Now we just need to run bin/rake db:migrate

Okay. Now what? We want to TDD this. We have a good idea how logging in and signing up to an app should work, so let’s start with some integration tests.

We need to edit our test/test_helper.rb: we’ll add require 'capybara/rails' somewhere right after the other require statements, and we’ll need to add:

Okay. Now, open test/integration/authentication_test.rb

Cool. A few things about this:

  • Now we know that an app with authentication should redirect us to the login page if we try to access a page which is not ‘public’. So we’re assuming that the root_path is protected, and we’re asserting that after we visit it, our current path is not, in fact ‘/’, but ‘/login’.
  • Capybara doesn’t have access to the session or request, and access to the response is limited. So we can’t assert here that we’ve actually been redirected. However, in a sense, we don’t care. We care that, when we tried, as a non logged in user, to reach ‘/’, we wound up on ‘/login’ instead.

Let’s run the test. First run the migrations for the test env:

Now you can run just our integration test with:

Whoops:

That’s not what we were expecting. Well, I guess we need to edit config/initializers/sorcery.rb

There’s a line for this in the initializer already; let’s just uncomment it, and add a name for our Mailer:

Now, testing again, we get: NameError: uninitialized constant ResetPasswordMailer

Oh. You mean the mailer really has to exist? Okay.

Great, now the mailer exists. We’ll think about it later. Run the tests again.

Well, that was unexpected. Why are we trying to put anything into the database?! Turns out, it’s our fixtures. They look like this:

This is because when the model was first created by sorcery’s generator, it was generated without migrations. So the fixture is empty. When you run your tests, the fixtures are loaded into the test database. Sorcery (if we had read the migrations it generated) makes the email field have the db constraint NOT NULL. So trying to load an empty fixture raises and the ActiveRecord::StatementInvalid: SQLite3::ConstraintException that we just saw. We might decide to use our fixtures, so let’s fix them.

Now test again. Hm:

We need a root_url. Let’s open config/routes. The root url is defined like

Well. Let’s see. We know our app will have users. Why don’t we assume that the root url will just be the user’s profile page.

Sure, why not. Let’s test.

Bummer. OKAY. We need a users controller. Let’s make it.

Now, we could scaffold a controller here… but we’re TDDing. We don’t want a whole bunch of code in our controllers that we haven’t thought testing. Scaffolding can be fine, but in this exercise, let’s try to write our own tests, first (I know, scaffolding will also generate tests for you…)

Great. we have a controller.

Test again aaaaand:

That makes sense. The controller is empty. Let’s add the action:

That was painless. Test again, and:

Okay. We need a view, as well. Let’s just, make sure it’s there.

Okay. Now, finally we see:

Great! An actual failure. And we see that we maybe should have provided a message to our assert. Let’s do that. Actually, we can just improve the sort of assertion we’re using:

And, testing again, we see:

Cool. So, now we have a real failing test. Now what? Wellllll…

We could just have the action redirect to ‘/login’! That will make the test pass, right?

Nope. Nope, nope, nope. Hm, well, we can add the route, but we need to point it somewhere. What controller will handle the ‘/login’ route? Well. Logging in is creating a new user session. Let’s make a UserSessions controller, and have the login url go to the :new action.

Cool. And we’ll need that route:

Let’s test again. Wait; we’ve been here before, recently. We know we’re about to see that the new action is missing, and then that the new template is missing. Okay. Let’s make them. If it makes you feel better, you can run the tests inbetween each step to see the errors that are raised.

and

Okay, test again.

Okay, test again.

Hey! It worked. Our first passing test. Great. What next? Well, let’s write our next test.

[SIDEBAR!]

Wait, you cry. But that is wrong! The show view can’t just redirect to login. That’s not right! What about when the user is logged in? We want to see our user profile. What is the meaning of this!!!
Well, we’re letting the tests drive. We’re making our test green the simplest way possible. We’ll write other tests that flush out these errors, and then we’ll change our code in such a way that our first test still passes, as well as our new test. Hang on.

[/SIDEBAR!]

Okay, here’s our next test.

So, we want to get to /login, and we hope there will be a link to sign up (we can’t log in until we have a user, right?), which we will click, and then we are asserting that said click will take us to a path that matches /signup/.

Let’s run it.

Makes sense. Our view is blank. Okay, let’s add a link.

Okay!

Well, we can fix that:

Test again, and:

That’s something we can fix, too. Seems easy. We know we’re going to need the view, too, so we’ll go ahead and do both:

… and touch app/views/users/new.html.haml.

Test again. Great! Our test passes. This is easy. We need a new test. Let’s test that on the signup page we can actually create a new user. We don’t want to need to sign in after making our user, so we’ll expect the users#create method to also log us in if we successfully create our user.

Okay, a lot of assumptions here. We’re expecting a form to exist on this page, with certain fields, which we will fill out and then click a button labeled “Create user”, and be logged in and redirected to the root path.

This error is easy to diagnose: we don’t have a form on the page at all. We like using simple_form to make form helpers that much easier, so let’s add it:

Now let’s create our form.

Well, @user is not defined. So the form helper is trying to initialize itself with an instance of NilClass. That won’t do. Now, for the first time, let’s drop down a level, to the controller test. We want to assert that the :new action creates a User object, @user.

This is a straightforward test. You could even argue that both of those assertions aren’t really necessary, maybe. I’ll let you argue about that somewhere else. Let’s run the test, with bin/rake test:controllers

Same error, of course. Let’s fix it. We like to fix errors, or failures, with the simplest possible thing. So we could do something like @user = Object.new. However, that still won’t make the test pass; that’s not always what is meant by doing the simplest possible thing. In this case, we know how rails works, and this simplest possible thing is just to create an instance of the User class. So we’ll do that.

Run the tests, and

Huh. That’s not right. Oh. We haven’t defined any of the other routes for the users controller. To the routes file!

Well, on running our tests again, that did it. Yay! We see a warning that we haven’t configured simple_form, so let’s do that just so we don’t need to see this error anymore.
When we run bin/rails g simple_form:install --help, we’ll see the options we’re going to have available to us:

Normally we might think now about whether we’ll want to use bootstrap or foundation, and maybe add it. Just so our app looks nicer, later, let’s user foundation-rails.

And then we’ll install foundation, and then simple_form with the --foundation option.

Okay… since we’re going to this trouble, let’s edit our templates a little, fire up the app and make sure it looks okay.

And the new user template:

Now bin/rails s and let’s visit localhost:3000/signup

Screen Shot 2015-05-07 at 6.53.44 AM

Okay! Onwards.

Well, we made our controller test pass. Does our integration test pass?

NOPE. Let’s make a create action.

Running the tests now, we get a missing template error, which is what we should be expecting at this point. Except, this time we know we don’t just want to make a create template. This action is going to create a user, log that user in, and redirect to the root url. A create ‘view’ doesn’t need to exist at all. We could create one, to get past this error, but we know that our test would then still go on to fail, because we won’t have redirected to ‘/’, so let’s think about that. Well… like we did before, we could just redirect…

Will this make the integration test pass?

Nope. What’s going on? Well, we’re redirecting to ‘/’, which maps to the user#show action, but that action redirects to ‘/login’. Our little hacks to make our tests pass have risen their beady eyes, and it’s time to fix them properly. Sorcery has a method called require_login, intended to be used as a before filter: if you try to get to a route that has the login_required filter, the not_authenticated method is called. Let’s add this to the application controller.

Now when we run our integration test, we get a series of redirect loops; our test harness is nice enough to halt after 5 redirects. The problem is, we now require login on every action in our application: but by definition, you aren’t logged in yet if you are createing a user. So we need to skip it.

Still getting redirected… oh, yeah! Our create action doesn’t actually do anything. Let’s have it actually create a user and log it in.

I think we want to drop down to the controller test again.

Oh yeah. :create method still does nothing.

Let’s fix it.

The user_params method is for strong_parameters. You can go ahead and look up what that is, if you like. So, we added a few things here. We’re hoping to make this pass in one fell swoop; we make a user, with our user_params; if it saves, we redirect to the root url, after using sorcery’s auto_login method to login our newly created user. NOW what happens when we test this?

Oh. Hm. That’s right, user doesn’t have a password_confirmation attribute; we only need that for creating the user, or later, for letting the user change their password.

This sounds like behavoir we need to add to our user model. So we should probalby write a user test.

We can think of 3 cases, off the bat, that we want to test for passwords; if the confirmation matches, the user should be valid. If they’re blank, even though they match, the user should be invalid; and if they don’t match, of course the user will be invalid.

These still raise that unknown attribute error. Let’s fix it. ActiveRecord has a validation made just for us.

While we’re here: we know that user’s require a password. Let’s test that, too. And let’s refactor out those params, we keep writing almost the same thing.

First we’ll do the refactor.

Now, let’s check: okay, tests still pass. Next? Add a quick test that email is required.

This test will fail; run it and see; so to make it pass, we add a validation to our user again.

Great; all the tests pass. Did this fix our controller tests? It did. How about our integration tests?

Wow! Not at all. When we try to fill out the form, capybara isn’t sure which field to select. And in the other cases, we’re still getting infinite redirects.

Well, we can take advantage of something we know about capybara: it will also match the name of the input field itself. SimpleForm, like normal rails form helpers, names fields by the model name and field name: so we can tell capybara to fill in user_password and user_password_confirmation. The other thing that (hopefully) we realize is, when we visit the /login path, we still aren’t authenticated; so we’ll be redirected (to /login) infinitely. We need to skip_before_filter on UserSessionsController, too.

Now all our tests pass.

This might be a good place to take a break. Get up, get another cup of coffee, or some other beverage of your choosing.

Let’s also do a quick retrospective on where we are so far. It could be argued that this is a simple case, and that TDDing it is overkill. That we know exactly what we’re going to do and how we’re going to do it. That might be true. But it’s also true that we could change something about this later. What then? Are we going to stop and go back and write tests for these things?

The other thing that is happening, is we can be extremely confident about the code we are writing. Starting from the outside helps immensely with this. In my first draft of this, I started with controller tests; dropping down to the model when needed, and back up to the controller. Problem is, if you do that, you can get all your tests passing and you still have no UI. You could do the forms and views after the fact, and you could even write your integration tests at that point, but to me it makes more sense to do them first. So I started over, beginning at the very outside. Now, even if we stop here (we’re not done; we’ll find bugs, and if we go to the login page in our app, there’s actually no way to log in yet), the part of our app that we’ve tested and worked through actually works.

If you’d like to be alerted when the next part of this comes out, please sign up for my mailing list:

powered by TinyLetter

I don’t send emails to it very often, and I’m never going to sell or share anyone’s email address. Happy TDD-ing.

What is Software Architecture?

Even in the best books (POSA, POEAA), “software architecture” is pretty loosely defined. In POEAA, Fowler says:

I tend to look at “architecture” as one of those impressive-sounding words, used primarily to indicate that we’re talking something that’s important.

And (emphasis added):

There are two common elements: One is the highest-level breakdown of a system into its parts; the other, decisions that are hard to change. … In the end architecture boils down to the important stuff—whatever that is.

“Whatever that is.”

Let’s break down what Fowler actually says there, because it’s probably the best definition we’re going to get.

  1. The highest level breakdown of a system into it’s parts. This seems obvious. From the very beginning of, say, going through a RoR tutorial or some other framework setup, you are assembling these parts together: in a web application for example, you’ll probably need a database. You definitely need a web server. If you’ve chosen RoR or a similar framework, it is assumed that you are going to have models, controllers, and views, and you are encouraged to organize things in a certain way. But there are other choices and components as well. Will there be background jobs? Are there external components, services, or APIs which you must query or update periodically? Is user authentication part of your system, or is it dependent on some external service, like Twitter or Facebook Oauth, an LDAP server, or something else entirely? Will this change later? I think if we’re just plowing ahead without asking these question, we aren’t thinking about software architecture. If you are stopping to ask the questions, you are thinking about architecture.

  2. Decisions that are hard to change. Some decisions are (hopefully), easy to change. Ideally, in an MVC framework, it is very easy to change your views without changing any other part of your application (if you don’t think this is true, you might not be doing MVC as intended, as this is one of the explicit goals of an MVC architecture). Again, if you need to change your datasource, hopefully this is an easy thing to change. This is dependent on a few things, but let’s at least say that theoretically, if you’re changing from one relational database to another, that shouldn’t be a crazy impossible task: it should be moderately simple to switch from, say, MySQL to Postgresql.

Other decisions are not so easy. If you commit to a framework or language, making a change probably means a complete rewrite. If you choose Rails, or whatever, and then later on, when your app is more or less complete and functional, you think that maybe you’d like to use Ember or Meteor or a Clojure framework: congratulations. You’re likely going to be rewriting the whole application.

Knowing which decisions will be hard to change is a mixture of common sense and experience. Some things might be immediately obvious even to a new programmer, while other times it maybe be obvious only to a senior developer that there are dragons in those waters.


So that’s sort of it. Architecture, in and of itself, is not really arcane or esoteric.

Highest level breakdown.

Things that are hard to change.

There’s a certain amount of experience needed in order to identify these things, of course, but I honestly feel like that experience can be accelerated by exploring these ideas earlier in your software career. If you do that, you can hopefully see these things in your own code and in the applications you’re working on and contributing to sooner than you might otherwise see them.


Install Go on Mac OS X

gopher

I’m just going to talk about installing Go on Mac OS X, because that’s the machine I have.

The actual installing couldn’t be simpler. If you visit http://golang.org/doc/install, you’ll see a nice friendly link to the Go Downloads page. You’ll see a batch of those which are for OS X 10.x+; choose the one that best fits the Mac you’re using. Choose the pkg download, unless you have some reason to want to install from source.

The pkg will open a typical Mac OS X installer wizard-style program, and it will install Go in /usr/local/go, which is where Go expects to be found.[^1]

Go does expect a few environment variables to be set.

$GOROOT is set to /usr/local/go by default, so you’d only need to change that if you installed Go in some non-standard location.


You’re not quite done. Go expects code to be organized in workspaces. All that means is you’ll want to create a directory for your Go work, and put your various Go projects inside it. Then Go needs to know where this workspace is.

For example, assuming you did mdkir ~/go, you would put into ~/.bash_profile


A little more

Go also assumes that you’ll be working with projects stored in source control, and wants us to use the repository’s root as our base path. If I’m creating Go projects and planning to put them in my github.com account, I’ll want to put them in a structure like:


I’ll leave some basic _hello world_ing up to you; I would recommend going through How to write Go code. It shouldn’t take very long, you’re already set up.

uncommon is alive

uncommon is alive!

I’m proud to have had a part in the inception of this project, though other responsibilities prevented me from taking a larger role in helping to create it. I hope I’ll be able to contribute some more in the future.

You can see what it’s all about here:

Uncommon in Common is the online home for a community of kind and curious people like you, a front porch for the Internet. It’s a place to share our favorite things and the best parts of our week, a place for meaning and wonder.

Right now, it’s only open to the founding members, people who joined the mailing list and made a small contribution early on in the project’s history. As I understand it, soon each member will be able to invite another soul for a year’s membership. At some point (I’m not sure when?), it will open up for membership. Stay tuned. It’s going to be a wonderful thing.

Refactoring with code blocks in Ruby

I came across this situation the other day. I had a method which already existed on one model: let’s say it ran through all of that models associations and did a thing, a notification, for example.

Seems okay. Turned out, I had another method, somewhere else, which also wanted to notify all the groups members–but it also wanted to do a little more logging. Let’s say, something bad happened: we need to put the Group in a different state, and then not only notify all the members, but do some logging. This is logging that we don’t need to do in the normal notify_members method. We could duplicate behavior:

But other than the extra things that we do, now we have two methods, which both iterate through our group’s members and notify them. Seems to violate DRY a little bit. It’s not the end of the world, but it could be better.

Enter Ruby blocks. Instead, we could do something like this:

Now our second method simply uses the first method, but adds some extra logging into the mix. We can yield the member up to the block, which is necessary because in this (contrived) example, our Alert creation and our logger message both want to specifically call out the member for later reference.

Code blocks. Spend some time with them. They can make your life better.

Responding to :js in Rails

There is an underused feature in the way Rails allows you to write respond_to blocks in your controllers, I think: specifically, in that you can (if you like), tell your controller action to respond directly to JavaScript with more JavaScript. Not simply responding with JSON, though you could do that; I mean you can write complete AJAX-y workflows and let Rails do most or all of the heavy lifting for you.

Let’s assume we’re going to have an action that might be called from a regular link OR it might be called via an ajax request. So we’ll want

Now if we link to our action like:

we’ll get an attribute in the resulting anchor tag that looks like data-remote='true', and Rails will handle clicking on that link as if it were an ajax request to whatever the target url is, which in this case, will go to our action. It will fall into the format.js block, and since there’s nothing there, will try to execute the_thing.js.haml (or erb or whatever).

Let’s try something extremely simple just to see that it works.

Let’s make a new rails app and a controller.

That’s a lot of files. Let’s talk about what’s going on.

For starters, if you try this, when you click the “foo” link on the index page, a js alert dialogue will appear. Not only that, but it says “It’s working, Dave.” It worked! But how?

In blatant disregard of rails convention, we created a custom route with our other actions for the foos controller. Having done that, we told that action (in the controller) it could respond to js. We created a js template in the views folder with the same name as our action, so it’s the template that rails tries to run. When we click the link, rails does run it, and because it’s an erb (or haml or slim) template, we can put Ruby in it, too. This is pretty awesome.

That’s really all there is to it. Using just this mechanism you could submit a form with data-remote => true and then save a record and have the resulting js template replace the form with a different partial.

I’m considering putting together a more extended, practical example of this type of technique. Is this interesting? (Y/N) Let me know.