Refactoring Alert Notifications to Use a Shared View Helper in Rails
This guide walks through how to refactor our current alert system so that it utilizes a view helper method that can be called from the layouts and forms.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

That we have our alert messages on live it's time to take a look about how we can clean our code up. If I open up sublime text you can see that we have our alerts partial here which has a conditional which really doesn't seem that necessary.

large

And then inside of each one of them we have nearly identical code and we are going to now have to do the same thing in our portfolio form and in our blog form. Just with our small application we have found what's called a code smell where we have one, two, and three, four, five, spots where nearly identical code is being called. That is definitely something that we want to clean up. So let's see the best way to do it.

First and foremost I do not want to use a partial. I want to use a helper method for this. If I open up the application helper file and come all the way down and I can give us some room. I'll give us a bunch of room and then we can clean up the spaces.

I want to create a method and I'm going to call it alerts. There are a few ways that you could build this in but I think one way that would be pretty clean is I'm going to create a variable called alert and I'm going to set it equal to any of the possible alerts. So we know that we have three potential flash alert types. We have a flash alert. Then we have a flash error. Then we have a flash notice.

def alerts
  alert = (flash[:alert] || flash[:error] || flash[:notice])
end

What I am doing here is I have created this little almost mini conditional that is going to go and it's going to say, okay is there a flash alert? If not then is there a flash error? If not is there a flash notice? If not it's going to it's going to return nil. If one of these returns True it's going to not only return true but it's also going to store the value inside of the alert variable. And what I can do now is I can say if alert and then use this code. Here I can come in, grab all of this. And now I can say if alert than I want you to create one of these javascript and gritters, but instead of hard coding the value I can place it as the alert value.

def alerts
  alert = (flash[:alert] || flash[:error] || flash[:notice])

  if alert
    js add_gritter(alert, title: "Jordan Hudgens Portfolio", sticky: false)
  end
end

So now let's come and, I'm close out of my partial, and I'm going to delete the partial. Let's come into the app html file where I'm calling it. Instead of calling this partial I'm just going to call the alerts method.

medium

So this is just going to call alerts and it should work exactly like before. So right now let's come and click log out. And if I do that, look at that, signed out successfully. Hit log in and everything appears to be working. So that is a good sign.

This is an okay implementation and it works perfectly with what we're doing here, but if I open up our forms you'll notice something is a little bit amiss. So right here we have the portfolio. If I try to use our alerts here and if I move this and come here for our blogs you'll see that this actually doesn't work. Let me come to blog. Come to write a new blog. Now if I hit submit, nothing happens. No error messages. Nothing is going on. We don't have exactly what I would call a perfect implementation, obviously because it's not working. The reason it's not working is because our params for our flash messages are different than these messages. These do not get stored in flash params. It's very easy to test this out. If I come right here let's implement some bye bug. Just to verify, this is the blog. So if I come here, hit refresh, come to write a new blog, hit submit, this catches, which is good. If I come to the terminal, let's take a look at what we have access to. If I type flash you can see that right here the flashes are nil.

large

So that is the problem. That's why this is not getting picked up. If I type blog dot errors then we have our errors. So this is kind of important thing to think through is that we do not have the ability to simply call on the Flash params we need to call this directly which means we need to kind of rethink how we've structured this alert. And the better way of doing this is to create an alert generator. So I'm going to create a method. I'm just going to call it alert generator and it's going to take one argument that's going to be a message, and now we can just rip this out and call it here. Pass in message as the argument and everything else can stay the same.

def alert_generator msg
  js add_gritter(msg, title: "Jordan Hudgens Portfolio", sticky: false)
end

Come get rid of all of our white space and now inside of our alert I can just call alert generator, get rid of all of this. Hit paste. And now what we can do is if we go in to our forms now we can call the alert generator pass in the error as the message and we can do it here and we can also do it here and now it should work. So if I come back to Chrome go to blogs we should now be able to have access to this both in the blogs form and also in the portfolios form. Okay it took a while to load up. If I click on write a new blog from here. Let's see if we have a little air. Right here it says action view template error can't add a new key in the hash. My guess is we just need to restart the rails server. Sometimes it can get a little something caught in memory and restart will fix it.

Now if we come back to the site. After it's loaded now we should be able to hit refresh and there it goes. If I hit submit. Look at that.

medium

Now we are back to having this working. And if I click on portfolios. Go to new. Click on say a portfolio item. Now it's working here. If I come and I log out. It's working here. This is fantastic.

I also want to add this into our portfolio and our blog layouts. So for example if I come to blog and let's say that we create a new blog and actually put something. If I click submit you can see it creates it but we don't have an alert. And that's because we need to actually call our alerts from the other layouts from our blog html. Now what we can do is simply call this so we can say alerts call or helper method and do the same thing in our portfolio. Now if we come back and press edit it says post now live because this is one thing to know about rails and the flash is until the flash has been shown Rail's keeps it in the session. So now it's going to wipe it away, but it was storing it there for us, one little just kind of tricky thing about him.

If I edit this and hit submit now it says blog has successfully updated. Notice how this message is dynamic. This is not hardcoded this is exactly what we have inside of our controller. If I come to the portfolio we should see the exact same behavior here. So if I click on edit item and I add something new like sequel, hit save portfolio item. The record was successfully updated. So that is looking a million times better.

Notice there is a very specific pattern that we just went through. So when we had this implementation code hardcoded inside of alerts it made this alerts method very inflexible. It couldn't be used for anything except something that had the params here. And that's fine except it made it so that we weren't able to use it when we needed just a single call. So what I did was I took a method that was really doing two things. It was creating a flash message and it was checking to see if the params hash was full for a flash message and it was doing those two things. And because of that it made it too difficult to work with for all the purposes we needed it for. This is a very common pattern that you will find yourself running into where you start to build too much complexity into a method even though that was only five lines of code. So that doesn't seem like a lot. But there are times exactly like this where five lines is going to hurt us and we didn't shrink the method at all. All we did was we separated out the functionality so that we could make one part of it more specific. We created a little generator here so that it could be called specifically and then that method could also be called from the alerts.

I like that. Let's hit clear. See everything we changed. And now we are good to go. Let's say we'll say that we refactored alerts into helper method. Git push origin forms. And now let's check out our master branch. And let's merge it. So git merge forms, it's brought everything down. Git push and this will merge our branch up and our master branch now will be up to date. So we come back to our repo you can see we're now at 96 commits on the master branch. We have everything up to date all the way up to our refactored alerts into the helper method.

I'm going to click out of custom validations on the forms and this is everything that we're going to implement in this section as far as our app is concerned. In the next guide we are going to take our deep dive into forms and we're going to build a form completely from scratch. We have built forms using form tag and form for and hopefully that give you a little bit of an idea of how forms work. But we're going to go back even further and we're going to start and create a html form from scratch so we can walk through exactly what parameters are being sent. We're going to see what the authenticity token does and how we can call it manually. And those kind of things which should hopefully help you understand the way that you can get data from forms and put it into your application and most importantly see how Rails does it. So when you need to customize that behavior you'll know how to.

Resources