Skip to Content
Course content

219: Building an Admin Panel with Avo

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I’ve lost count of how many hours I've wasted in my career building the same CRUD interfaces over and over again. You know the drill: a controller for the admin, a set of views that look like they're from 2005, and a mountain of permission logic. When I first stumbled onto Avo, I was skeptical—usually, these "admin generators" either get in your way or create a mess of hidden magic. But let's dive in and see how it actually feels to build one out for a real project.

For this session, I'm using a bookstore app I've been tinkering with. I've already got Book, Author, and Order models. Right now, if I want to change a book's price or mark an order as shipped, I have to go into the Rails console or write a custom admin page. Let's fix that.

Getting the scaffolding up

First, I'll throw gem 'avo' into my Gemfile and run bundle install. Then, the installer: rails avo:install. I’m not going to bore you with the installation logs, but the important thing here is that Avo creates its own namespace. It doesn't hijack your ApplicationController, which I appreciate. It lives in its own world.

I'll fire up the server and head to /avo. It's a blank slate. Completely empty. I've got the dashboard, but no data. This is where the "declarative" part comes in. Instead of writing a controller, I'm going to generate a resource for my books.

rails generate avo:resource Book

Now, I'll check the generated file in app/avo/resources/book_resource.rb. By default, Avo tries to be helpful and adds every single column from my database table to the index and the form. When I refresh the page, it works, but it's ugly. I've got created_at, updated_at, and internal database IDs cluttering up my view. That's not how a professional admin panel should look.

Taming the Book Model

I want to curate this. I only want to see the title, the author, and the price on the main list. Let's go into the BookResource and start hacking at the fields block. I'll comment out the noise and explicitly define what I want.

class BookResource < AvoResource
  self.model = Book

  fields :title, :author, :price
end

I refresh. Much better. But wait—the price is just a raw decimal. It looks like a math textbook, not a store. I remember that Avo lets you specify the field type to get better UI components. I'll change :price to a more explicit definition.

field :price, as: :currency, currency: 'USD'

There it is. A nice, formatted currency string. It's these little quality-of-life tweaks that make an admin panel actually usable for a non-technical client. If you give a client a raw decimal field, they'll eventually ask you why the "cents are missing" or why there's no dollar sign.

Finding the needle in the haystack

As my bookstore grows, I'm going to have thousands of books. Scrolling through a paginated list to find books that are out of stock is a nightmare. I want a quick way to filter these. I'll try adding a scope.

I already have a scope in my Book model called .out_of_stock. I'm wondering if Avo can just... pick that up? Let's try adding it to the resource file.

class BookResource < AvoResource
  self.model = Book

  scopes :out_of_stock
  
  fields :title, :author, :price
end

I hit save and refresh. A "Scopes" dropdown appears at the top of the table. I click "Out of Stock," and boom—the list filters instantly. I didn't have to write a single line of SQL or a custom controller action. This is where the productivity gain actually happens. I'm spending my time defining what I want to see, not how to fetch it from the database.

Cleaning up the editing experience

One last thing. When I go to edit a book, I noticed the author field is just a text box. But Book belongs to Author. It should be a dropdown, right? Actually, it is a dropdown by default because of the association, but it's a giant, scrolling list of every author in the system. That's a usability disaster.

I'll try to make the author field searchable. Avo has a searchable option for associations. Let's see if this does what I think it does:

field :author, as: :belongs_to, searchable: true

Now, instead of a static HTML select menu, I've got a searchable combo box. I can type "Tolkien" and it filters the authors on the fly. This is exactly the kind of polish that usually takes an entire afternoon to implement with a JS library, but here it's just one line of Ruby.




📋 Practical Task

Implementing a Low-Stock Alert View in Avo

You are managing an inventory for a hobby shop. You have a Product model with a stock_count (integer) and a name (string).

  1. Create a scope in your Product model called low_stock that returns products where stock_count is less than 10.
  2. Generate an Avo resource for Product.
  3. Configure the ProductResource so that:
    • The low_stock scope is available in the UI.
    • The stock_count field is displayed as a number.
    • The name field is the primary field displayed in the index.
  4. Verify that clicking the "Low Stock" scope correctly filters your product list.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.