Skip to main content

31 Using ActiveAdmin to Build an Admin UI

Episode 164 · December 28, 2016

Learn how to build a dedicated admin area in your Rails app for editing records by admins using the ActiveAdmin gem

Administration Gems


Transcripts

What's up guys, this episode we're talking about the ActiveAdmin gem, and how to use it to build an admin interface for your rails app. This gem is rather interesting, and it relies heavily upon either auto-generated code or DSL's to customize the admin interface, this is interesting, it uses devise, it creates an AdminUser model, so all of your regular users are very separated out from ActiveAdmin, which is very nice for security reasons, there's no chance that anybody could ever set their role to admin and gain access to it, because they physically wouldn't have it record in the admin user table, so that is nice, you can customize this so that you can use roles and the same user table if you want, but this will look at your registered models and add them to the admin interface and it will generate index pages, search pages or search filers, it will generate show pages, edit forms, all of that stuff automatically for you so long as you just register the model in your admin. You can even tell it to use and pull out specific scopes from your models to display and allow for filtering, there's all kind of stuff that you can do with it, and it has it has it's own DSL for customizing your forms, your Ransack filters, your scopes, your views even, and adding buttons to the show and adding actions, you've got a massive DSL, and that's one of the pros and the cons with using this gem, it's 1) Really easy to customize things a little bit, but 2) it's kind of very hard to customize things a whole lot because you have to do it all within their own DSL, that gives you pros and cons, but let's dive into it and try it out and take a look at what we're working with. One cool thing is that we need to just register our models, and we can go to our scopes filters and customize our index, and it's a few lines of code, we don't have to worry about any model stuff, no controller stuff, no views, all of that happens inside our admin full file for our product, so that's kind of neat, let's dive into the gem itself, I'm going to use the version that's on GitHub, the latest version that is stable, you can use the master branch, but there is possibility that that will break, as they're actively working on it, so let's

rails new admin_example

We'll open this up in our editor and go to the Gemfile, paste in active_admin in there, and we also need to grab inherited_resources from rails 5, as this gem has been deprecated, and then taken over by the active_admin team, and last but not least, I actually had to specify devise manually in here to get the generator to run, so that may or may not be fixed later on as you watch this, but at the time of recording, I did have to manually specify devise. We can run bundle to install that, and once this is done, we can run rails generate active_model:install will set up our admin user devise model, we'll set up configs for active_admin in our initializers folder, create routes for active_admin, and an app/admin folder where we create all of our admin sections in there.

There we go, this gives all of our files, we can run rake db:migrate in order to add the admin user model, we can also run rake db:seed in order to create our admin for the admin area. If we open up seeds.rb we can see that it opened a line for creating an ActiveAdmin user, and it's just "[email protected]" and the password is "password", so we'll run that as well, and also create an ActiveAdmin comments, so you can comment on any model of the admin period, they're polymorphic, so they can be applied to anything, and lastly, let's generate two scaffolds so we can play with those, we'll have User so we can have a name and an email rails g scaffold User name email and rails g scaffold Post title body:text published_at:datetime user:references this way we can see how it works with associations, so let's run rake db:migrate, create those, and let's start up our rails server, and see if we can log into localhost:3000/admin.

After a second attempt I got it to work, I actually ran into this issue with jQuery UI datepicker, and had to use the ActiveAdmin from the master branch on GitHub in order to make this work, so they're in the process or releasing an updated version of the gem, they're working on version 1.0 for official full rails 5 support, but it does work perfectly fine in rails 5 if you use the master branch, so use at your own risk I guess, and we can log in here, and we will have our dashboard, this comes from the configuration of app/admin/dashboard.rb and this is the block that it uses to generate that container, so if we deleted this, we'll see this block disappear. So this is actually generating the views inside of a ruby file, which seems a little weird, which seems a little weird, so these div, span, small tags are all coming from an ActiveAdmin dependency called "Arbre" you can find out a little bit more about this in their documentation, take a look at Arbre's components. This is the section for that, it shows a little bit how to do that, it comes with some cool stuff like panels that you can use and columns to split up your stuff, similar with how you would with bootstrap, you're just using ruby to design the views instead, so it's kind of interesting that they've chose that route, but the benefit is you can make very quick tweaks to it without having to dive into all your views and have a lot of files to define your admin with. They have opted for this route, it has it's benefits and it's drawbacks, but it does work, and this is our Admin user section, you can see that we have all the Admin users listed out in a table, you can filter them, you can type in whatever you want and it will automatically search for you and tell you which fields you searched upon, but you'll notice that out models don't exist in here just yet, so the reason for that is we have to add them to files in admin, and we have to register them with ActiveAdmin, so let's go do that, if we go into our app and we say rails g active_admin:resource User and rails g active_admin:resource Post, and this will generate two empty files for us that register user and post models in order to display them, so this is great, except these have to be customized in order to pass in the permitted parameters, it's not going to generate those for you, although I kind of wish it would, but here we can say

app/admin/user.rb

ActiveAdmin.register User do 
    permit_params :name, :email 
end 

app/admin/post.rb

ActiveAdmin.register Post do 
    permit_params :title, :body, :published_at, :user_id 
end 

Now we should be able to refresh and see our posts and our users, and if we created the user, we can see that I have a page, it worked, it's kind of like admin scaffolds pretty much with some nicer views, but you'll notice here that it is smart enough to understand there's an association for the user id column, and it gives me a dropdown for that instead, so we can add a title and a body, and if we fill out the published_at, that would of course fill it out, but let's leave it out and create a button up here to add that in, so we can have a "Publish" and "Unpublish" button, now the way that this works, is we can have a member action here which is kind of like defining a route, and we could have a

member_action :publish, method: :put do 

end 

This is very similar to goingt into your routes files and saying

member do 
    put :publish 
end 

it's almost exactly the same, except that you're defining it inside of ActiveAdmin instead, so let's move those up here, so that is how you would define the route, and the block that you pass it is actually the code for the actions. So you say:

That is as simple as it is, but we need it to display on that show link, so here we can say action_item :publish do, and this is customizable for the show action or the index, and each of these is one of the commands in the DSL that you can use to add links to your views, integrating everything, the code looks like this:

app/admin/post.rb

action_item :publish, only: :show do 
    link_to "Publish", publish_admin_post_path(post), method: :put if !post.published_at? 

member_action :publish, method: :put do 
    post = Post.find(params[:id])
    post.update(published_at: Time.zone.now)
    redirect_to admin_post_path(post)
end 

We can refresh, and now we'll see the "Publish" button, clicking that will hit our little block that we wrote and mark published_at as the current time, so that's really neat, that we can add that without touching views or writing controllers or adding routes, kind of all do that in this one file, and we can do the same thing if we duplicate this, we can have "Unpublish" for the unpublished route, and we'll do this if it is published, and we can copy this one, and add our own unpublished method in here that sets it to nil instead. Now if we refresh, we have the ability to unpublish, and that sets it to nil and it shows up as empty and we can publish, and that button will change, and that's as easy as it is to add in an action like that into the UI. That's pretty cool, we're using some of the DSL for that, it's starting to mix a little bit of our views, as well as our routes and our actions, our controller actions into this one file, so you might notice that that gets a little confusing, and this is kind of the main drawback of using ActiveAdmin, once this gets about 10 times longer and you have a lot more complex admin interactions, this gets a little frustrating to work with, but at the beginning, the easy ability for you to add in these actions and stuff is very very nice because of the speed of development can be very quick. One of the things that I want to point out here is that it interprets that user id into the association and makes a clickable link for us to navigate between posts and their authors which is very cool, so it's smart enough to know to use those associations to build out that Admin UI, I like that a lot, the other thing we can do is we can go into the post.rb model, and we can say scope :published, ->{ where.not(published_at: nil )} but scope :unpublished, -> { where(published_at: nil)} if we add those in, we can go to the top here and tell active admin we want to display those scopes, and all of course is a scope that always comes with every application record or Active Record model, so going back to posts, we can scope these and say: Well there's zero published ones, there's one unpublished one, if we go to view it, we click "Publish" and go back, there's now one published record and zero unpublished records, this is pretty neat that you're able to add in scopes that quickly, you don't have to go and customize views or anything, you can just say scope this, scope that, and that's it. Another thing you might want to do is customize the form, so for example with devise, you have an encrypted password column in the database, but you obviously don't want that to ever be in your forms, so you want to be able to customize it, well this is really nice because you can say:

app/admin/post.rb

form do |f| 
    inputs "Details" do 
        input :user 
        input :title 
        input :body 
    end
end 

It will go and say: Ok, this is a user association so let's create a dropdown and let's load up the use rs and populate the dropdown with them, then the title as a string, so let's create a text field, but body is a text column so let's create a text area for that one, and then at the very end, we can say: actions which will update our form to say "Update post" and we cancel, and before you know it you have a form that's customized exactly how you want it.

Now there's no way I can cover everything about ActiveAdmin in an episode, or even really a series, but ActiveAdmin has a really good documentation site where you can learn about Arbre, the ruby syntax that you can use, that DSL for to create your views like the form stuff, or the show actions or any of that stuff, you can use that to build out your views in the admin a little bit more, you can look up how to create custom pages as you see here, you can design your indexes as blogs or grids or tables or whatever you would like, they have all kinds of different things like building custom controller actions, batching actions, which are on the homepage, so if you go to one of these you can check all of these off and say: "Delete all of them" or maybe you want to mark 10 posts as published all at once, you can see how they recommend you doing that, they also have information on how to set up pundit to enforce permissions across different user roles, all kinds of different things, it's been used by so many people, you'll always be able to find a good example of how to implement whatever feature you're trying to implement into ActiveAdmin.

That's a quick introduction to it, I hope you enjoyed it, ActiveAdmin has been in use by me over the years so many times, that it's definitely been worth it's value, there has been frustrations around how to organize those admin files well, but you can always figure out how to pull stuff out into concerns or something that you would include if you really needed it to, but I found that if you just organize these in good chunks, and you keep all of them like actions together and member actions together, and keep it consistent, it's really not to hard to manage, even if this gets to be three or four hundred lines of code, so with that said, I hope you enjoyed this and I will talk to you later.

Transcript written by Miguel

Discussion