In the first part of this series on creating Rails administration panels, we created a basic dashboard upon which we’ll be able to add the functionality necessary to actually manage the site. (Read part one.)
As a review, this simple blog-type application allows users to log in, then add, edit, and delete articles. We’re working on a namespaced administration section for the site, accessible only to people with accounts, to accomplish this. So far the application has an admin dashboard set up, but no further functionality. That’s what we’ll tackle in this tutorial. Specifically, we’re going to take a controller and views that were previously generated with Rails’
scaffold generator, move them into the
admin namespace, and make them work in our admin panel.
We’ll also be using RSpec request specs to drive this process. If this is a new process for you, you might want to go through the work we did in part one, or, of course, pick up a copy of my book on learning how to test Rails apps with RSpec. And with that shameless plug out of the way, let’s get on with our task. You can follow along with the complete source on GitHub; the relevant stuff is located in the scaffold branch.
Before we get too far into this, I want to clean up my RSpec setup a little bit. First, I’ve created the following factory (using Factory Girl) to simplify creating users for my tests:
I’ve also created a couple of RSpec macros to simplify the simulation of a user logging in, at both the controller and request level:
Again, take a look at the
scaffold branch on GitHub to see how this all integrates.
Before we go much further, let me point out that, on paper, this looks like a lot of work, especially when thrown in with failing tests. In practice, though, it’s pretty easy. That said, what we’re doing here–converting a scaffolded resource to one you’ll manage via an admin panel–will probably happen more in apps you’ve already scaffolded. If this technique of creating administration areas for your apps becomes commonplace for you, then you may find yourself creating the controller and views by hand, as we’ll get to in a later post in this series.
Here’s the request spec we need to pass:
And running it gives us this failure right off:
We need to namespace a resourced route for articles in
Go ahead and leave the top-level
resources :articles declaration; we’ll be addressing it later on.
When the spec runs again we get a new error:
What’s this telling us? Recall that in the previous post, when we created a dashboard view, we didn’t make the Manage Articles link actually link to anything–thus it’s just reloading the page we’re already on. Easily fixed in the dashboard view:
Running the spec now gives us this failure:
Which means we need to actually move the controller into the
And the subsequent error:
Tells us that the articles controller must be subclassed to
Admin like so:
Now the spec reports a new issue:
Wait, wasn’t this already resolved? Well, we moved
admin, so the route no longer has a controller to point to–and since
articles#index is our application’s root path, the spec is choking right out of the gates. What we need to do, then, is recreate a public-facing
index.html.erb! We’re going to be moving it in just a minute, and then we’ll create a new, public-facing view to take its place. Hang tight.
Believe it or not we’ve made a lot of progress, though looking at the latest error might make you think otherwise:
What’s going on here? The scaffolded
articles_controller.rb creates a collection of
@articles for the view to process, but our
rails generate controller-generated one does not. Let’s tell the index method what to do:
Yet another new failure from our spec:
This signals the start to our last big chunk of work. First we need to move the scaffolded views for articles into the
Argh, another failure:
OK, now we can create a simple, public-facing view to pass the spec:
From here on out, we’ll just be cleaning up the controller and views we moved into the admin namespace, to make sure routes are pointing to their new locations. For example, the next failure:
means that the New Article link in
app/views/admin/articles/index.html.erb needs to be updated:
And the next error:
Is telling us to fix the path our form points to:
One more failure:
We need to update the route our controller redirects to upon successfully creating a new article:
And with that, the core functionality is complete, and our spec should pass! (If it doesn’t, don’t fret–take another look at your spec, your code, and your test log to look for clues.) A quick review of what we did:
Before we call this feature complete we should address a couple of final issues. First, our full-blown articles controller–the one we moved into
controllers/admin–isn’t secure. If a non-logged-in person guessed the URI he could add, edit, and delete your articles. Not good, so let’s fix it with a quick
We’ll want to make sure this is properly addressed in our controller specs; see the source for how to do this.
One last, easily overlooked thing. Remember early on when I said to leave the original
resources :articles route declaration in
config/routes.rb? It’s working fine as-is, but it’s also generating routes for methods we don’t use anymore–namely, any CRUD method that’s not
articles#index. (Remember, the other CRUD methods used by the application are now namespaced under
admin). Removing unused routes reduces the app’s memory footprint, so let’s address that now:
While you’re at it, go ahead and remove the
get "articles/index" route that
rails generate controller gave us earlier–the resourced route is cleaner (at least in my opinion).
However, removing the other CRUD actions at this level introduces a new failure, which should look familiar:
Yes, another incorrect route in one of the pre-generated views.
One administration activity down, two to go–we can create articles, but we still want to be able to edit and delete them. I’m going to leave that as an exercise for you. Take a look at the scaffold branch in the source on GitHub to see how I’ve implemented this.
Like I said, the process of moving scaffold-generated controllers and views into a namespace looks more time-intensive than it is. However, it’s a good way to build administration tools from code you may already have in your application. On the other hand, if you need to administer a model but presently lack the controllers and views to go with it, you’ll probably be better off building them up by hand. We’ll cover that in the next post in this series.
If you liked my series on practical advice for adding reliable tests to your Rails apps, check out the expanded ebook version. Lots of additional, exclusive content and a complete sample Rails application.
Ruby on Rails news and tips, and other ideas and surprises from Aaron at Everyday Rails. Delivered to your inbox on no particular set schedule.