Building a Partial for Managing Admin Actions for Blog Posts
Our application currently has a list of actions associated with each blog post. In this guide we're going to walk through how to refactor the action links into a partial that can be called from anywhere in the application.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

We're making our way nicely down our list of tasks. In fact we are past the halfway point. We have finished 11 out of the 19 remaining items. The next one is going to deal with building out a partial for admin blog actions. In the last guide we implemented breadcrumbs. Right here we have the concept of breadcrumbs and this has home, rails which is our topic followed by the title. Then we have some actions here. One thing that I would like to do is to have these items pulled out into their own partial and they are in the part of the reason for this is because right now we have duplicate code going on. We have some code here but then we're also calling this from the topic show page. Technically this is just rendering the partial. We don't have duplicate code in the sense of having to call it twice but still, I'm not a really big fan of having this much code right in a partial when I don't have to. I think it makes sense to move this into its own little component.

Let's go and open up Sublime Text. I'm going to open up the partial which is going to be the blog partial. Right now we have a link to our blog title. Then we have published at and then our distance of time inwards. Now we have all of this action happening for our actions. A couple of things I want to do here. One, I want to change this format. I want to get rid of the blog meta post class and I want to convert all of these into icons. I think that's going to make for a better user interface and then I also(like I said earlier) I want to extract all of this out into a partial. Lets cut all of this and call a partial. I'm going to say render and this is going to be blogs/admin_actions and now into views go into blogs new file. Here let's create one called _admin_actions.html.erb and paste everything in here...

<% if logged_in?(:site_admin) %>
  <nav class="breadcrumb">
    <%= link_to blog.status, toggle_status_blog_path(blog) %>
    <%= link_to 'Edit', edit_blog_path(blog) %>
    <%= link_to 'Delete', blog, method: :delete, data: { confirm: 'Are you sure?' } if logged_in?(:site_admin) %>
<% end %>

Like I said we're going to get rid of this post and we're going to turn this into a nav because we want to implement breadcrumbs. I can say breadcrumb, inside of this, we can implement some links instead of the other items. Instead of just having the text here we going to do links. But before we do that I want to go test this to make sure everything is working. Remember little steps are a great way to go. Coming back here let's hit refresh and that is a good reason to test it out because imagine if we would have gone down a few more steps and integrated icons then we would have had some issues here. There are a couple options that we can have one is the fact that I want to see if I can actually just right here. I'm calling this, I saved this in admin actions but I can just pass in this blog variable as a local variable. For this partial I can say render partial: 'blogs/admin_actions', locals: {blog: blog}. This should work, come back, hit refresh There we go. All of this is working. This is even giving us our breadcrumb type of class this isn't everything I want but it's getting there. Let's come back to our partial. I'm going to get rid of each one of these little backward slashes. Now let's integrate our icons.

<% if logged_in?(:site_admin) %>
  <nav class="breadcrumb blogcrumb">
    <%= link_to fa_icon('file-text'), toggle_status_blog_path(blog) %>
    <%= link_to fa_icon('pencil-square-o'), edit_blog_path(blog) %>
    <%= link_to fa_icon('trash'), blog, method: :delete, data: { confirm: 'Are you sure?' } %>
<% end %>

First, I'm going to get rid of blog status and just call fa_icon and this is going to be file-text and everything else is going to be the same. If I come back here hit refresh. This is now a document. If I click on it it's going to change the status just like before. That is working nicely. There's a little thing that we'll come back and fix later which is the fact that you may notice it's very hard to tell with this being an icon. If this is published or if it's in draft mode but we'll take care of that right after we take care of the rest of these. The next one is going to be pretty similar to what we've already implemented so I'm going to do fa_icon and this one is going to be pencil-square-o, then close it off. That is going to be our edit link. If I click on this it all works. Our last one is going to be the delete post which is going to be fa_icon and just trash. OK. One other thing where it says if logged in site admin we can get rid of this because we know the site admins logged in because we have the entire thing wrapped in that. Hitting save everything here works. A couple things, one is I don't really like this style. I want to give us a little bit of separation and increase the font size so I'm going to add a new class here. Let's just call it blogcrumb. Kind of like breadcrumb except, blogcrumb and opening up blog.scss and scrolling all the way down to our custom classes for blogcrumb. I want to add some items so let's think about what styles that we want to change. One is going to be the font size and then the other is going to be the space in between.

.blogcrumb a {
  font-size: 1.25em;
  margin: 0px 10px 0px 10px;

First, let's test out the font size just to make sure that this is working. Say font-size: 1.25em; If I come back now and hit refresh our fonts should be slightly larger. They are, perfect! The next thing I'm not sure if this selector is going to work or not but we can always test it out and see. I want to change the margin: 0px 10px 0px 10px, just to give us a little bit of space. Let's see if this works or if we need to take our selector deeper and yes we do. What I'm doing wrong here is I am selecting the entire div where I really just want to select the 'a' elements inside of it so if I add that in and hit refresh it should give us some, there we go. This gives us some space. It doesn't affect the outer div but it still keeps our sizes. I test this out, delete that item that worked. This should be all hidden from our non-logged in users and they are. Notice how this is not being shown. That is perfect, I really like that! This is definitely better.

We have one other item I want to fix before we end this guide and that is that our status here is not clear. I have no idea if this is a published post, or if it's in draft mode. This button is kind of pointless like that. Let's talk about how we could possibly fix it. Let's do the easiest thing humanly possible first. I'm going to come here and add an inline style and this is not going to be our final edition, don't worry. Because usually inline styles are not exactly considered a best practice. For right now I just want to make sure that this works. So, I could change this and say inline style: 'color: blue'. Hitting refresh, now it changes to blue. You may think that the way to do this and this technically would work but it would be a horrible way to do it. Is by doing something like this by saying 'if blog.status' is let's say because status is an enum I could do something like. 'if blog.draft?' then I want you to do this and else I want you to do something. I want you to show a different color. In this case, if it's a draft I want red, and here I want blue or something like that. Hit end, save. If I hit refresh this one is a draft. It's red if I hit it again. It's blue. Hit it again. It's red. Technically that works. But if any professional Rails developers saw code like this they would not be very impressed. This is exactly the reason why we have view helper methods. I'm going to get rid of this, this and this. Let's talk about how we could implement a little bit of a better set of items. Coming down to the style. I'm actually going to keep style, but I'm no longer going to hardcode the value in. Instead what I'm going to do is I'm going to call a method. I'm going to call a method that will create. I'm going to create one called 'blog_status_color(blog)'. All of that entire process that we had before we can delegate it to this blog_status_color method. If I open up the blog helper and come down to the bottom we can implement a new method called 'blog_status_color blog' and just for style reasons I'm going to get rid of the parens but it's the same as if they were there. What we want to do is, now we can have our conditional logic. I can say

if blog.draft?
  'color: red;' 

For this one let's actually just leave this like this just to test this out and see if this works. If I hit refresh This works and you can see we have red and blue. If I hit it again this one is now red. That's all we need to do, we don't even need to add another color because I'm fine with using, in fact, I want to use the default color so if a blog post is published it's the same color as the rest of the icons. It's only going to be red if it is in draft mode. This is exactly what I am looking to do. Notice how much cleaner this code looks. We were able to remove all of the duplicate code and we could technically even refactor this. We could take this down to one line and say I want you to return the color red if blog is a draft. A lot of times I do like writing code like this so it's on a single line. I hit refresh. This still works exactly the same way as before. Just to verify that we don't have things 0h! Are we reversed? Let's see, click here. No it is in draft mode. I guess I've just been playing around with some of them. Ok this one is blog post 4 let's verify. Yes. These are in draft mode. Perfect! All of that is working.

In this guide, we implemented a few things. One we built another view helper method that will help determine the color that's shown for our statuses and we're able to refactor what could have been a very ugly set of code conditionals in the view and we're able to leverage a view helper method in order to implement it. We also refactored our entire system into a partial. Now, inside of this blog whenever it's called whether it's in a topic or whether it is in the index. We don't have to clutter up our view with all kinds of conditionals and with other items like that this is definitely reading much better than it was before. I'm happy with that. Hit clear. Let's see what files we updated. We added a new file called admin actions. We updated some blog styles we updated a blog helper and we updated our partial.

I think that's a good day's work. git commit -m "Implemented partial for admin actions", git push origin final-changes. We're all good to go! Let's see what we can cross off our task list. Here we have a partial for admin blog actions and I believe that is it right now. Yes. In the next one, we're going to implement a new header. I talked before about how I'm not a huge fan of this nav. if you like the nav that is completely fine you can keep it. I have no problem with that whatsoever. I personally haven't been loving it. Maybe part of it is because I've been looking at it every single day all day for a month but I am kind of in the mood to switch it up and I think it is a good exercise to show you how easy it is. Once you're using a framework like bootstrap to make some pretty sweeping changes in just a few lines of code. In that guide, we're going to walk through how we can update our nav bar so you then.