Creating a Rails admin panel from scratch, part 2: Scaffolded resources
By Aaron Sumner,
August 07, 2012.
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.
A little spec refactoring
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.
Making the move
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 config/routes.rb:
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 admin subdirectory:
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 articles_controller.rb into 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 articles_controller.rb:
Don’t overwrite 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 admin namespace:
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:
First, we created a set of namespaced routes for administering articles.
Next, we moved the controller and views into their new namespaced locations.
Then we created new public-facing views and a controller for articles.
Finally, we edited the pre-existing controller and views to point to the proper namespaced routes.
Some cleanup
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 before_filter:
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.
Next steps
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.
Summary
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.
Discussion
Follow along on on
Mastodon,
Facebook, or
Bluesky
to keep up-to-date with my latest posts. Better yet,
subscribe to my newsletter for
updates from Everyday Rails, book picks, and other thoughts and ideas that
didn't quite fit here.
Test with confidence!
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.