- Read Tutorial
- Watch Guide Video
In this section we've covered puts debugging in byebug. Now we're going to talk about pry. Pry is an alternative to byebug. It does not automatically ship with rails so we're going to have to install it. That's a pretty easy process and pry gives us a few nice advantages over byebug. We're going to go through a few of those.
In the show notes I have included a link to pry-byebug. This is going to be the Ruby gem that we're going to include in our application. If you come down to installation and copy gem 'pry-byebug'
then come to sublime. Paste it right under byebug in our ruby gemfile section. Press save in your file.
Open up the terminal type bundle
and then this will pull pry in for us. If you come back to Chrome you can see all of the different ways that we can use this.
The command that you're going to integrate is going to be called binding.pry
. I want to open up the portfolio controller, we need to do some refactoring. Let's type
before_action :set_portfolio_item, only: [:edit, :update, :destroy]
Imagine in a real-life scenario where we forgot to put the show list in there.
If I hit save and I'm going to come and create this method
def set_portfolio_item @portfolio_item = Portfolio.find(params[:id]) end
Now we can simply grab this here paste it in. Now each one of these methods that we listed is going to be able to have that code removed. It's going to have access to it because we're running this before action. Also, remove it for show even though I accidentally forgot to put show on that list. Then we're going to use pry to figure out and perform the debugging. I'm going to save and let's start up the site.
Go to our portfolio, this seems like everything's working, however, watch what happens if I click on the show item. If I click on the link you can see that that gives us an error, it says undefined method main image for nil class. This is a great example of an error that we'll run into when you're performing development. This is not explicit, it doesn't say "hey looks like you forgot to put a show inside of your before action." It doesn't know your intent. It is trying to set the main image, when it says nil class this means that we didn't have an object, there is no such thing as an @portfolio item. There is no object there. When we tried to call main image inside of our show file we didn't have access to it.
Let's see how we could use binding pry to help fix this for us. I would do is I wouldn't start in the controller necessarily because maybe the issue is in the view. I would go to the show view for the portfolios that you can see right away this is the error. If I were to see this in a real-life application I would kind of already have a hint that the portfolio item was empty because the error said a nil class and this is the first item.
If that was like subtitle or something like that then that might be a little bit different but because it was the call on the very top, this automatically tells me that portfolio item was empty. When we tried to call main image on it then threw an error. Put some embedded Ruby and I can say <% binding.pry %>
and save.
If I come here and hit refresh it's going to do the same thing where it hangs. If I open up the terminal you can see that I have a little REPL environment. This is going to give me the access to test everything out. Frst thing I can do is I would say portfolio_item and it's nil. That right away it tells me that's what the problem is, portfolio item isn't set. I'm going to look at the params. It shows that it's a controller that's the portfolio's controller and it's in the show action and I can see that my id is set so I should have a portfolio item to work with.
If I come here I'm going to just strip binding pry out and I can now move to the controller. I know based off of what we just saw, the problem is in the show action. I can put a binding pry right here and I'm going to now rerun it, opening up the terminal. We can see binding pry is there and I can check params again. I can see I do have access to grab the ID and now I'm going to check for the portfolio item and it's still nil. That there tells me "OK, the portfolio item is not being set" and that is what the problem is.
I can come back and go and look and say OK why doesn't the show action have access to it. Scroll all the way up. And look we left out the show action. I can type :show,
. Inside of the terminal, hit continue. If we come back here and hit refresh, it is still going to stop because I still have binding pry.
Now let's switch back if I type @portfolio_item
you can see that this is set. This gives us all of the data for the portfolio item. This also kind of shows one of the really nice benefits of using pry over byebug. Notice how nice this formatting is. This gives us the object back but where byebug kind of crammed everything together, when we did the Querrey on blogs, pry has a really nice way of formatting it.
This shows this is the title subtitle everything like that. I can do a portfolio_item.title
and that's going to bring that back to me. I could perform any kinds of actions that I want. This is a really effective way of being able to work with that data when you're getting unexpected results.
I can tell you from experience there are plenty of times where I've done this exact same thing, I have had a before action. I've added a new method and then I forgot to add the method to the list. If I wouldn't use a tool like byebug or like pry then the problem is I would just kind of be debugging by guessing essentially and that's never a good thing. I'd just staring at this code wondering why isn't this working. That's a really bad way of trying to fix a problem.
I've heard from multiple hiring managers and senior level developers that they have serious problems when they come by and they see a developer who is running into a bug but they're just staring at the screen. They want to see a developer who knows how to perform intelligent debugging. Which means that they want to find the root of the problem and then they can fix it. That's definitely something to keep in mind.
I want to reiterate that because I remember when I was originally learning development years ago that debugging and using debugging tools seems kind of pointless. I really didn't understand why they were important because I just thought I could just figure out the problem. But the more that I started to implement some formal type of debugging strategies the more I realized oh wow this is actually a very powerful way of being able to fix problems. I'm actually developing a strategy for figuring out problems. It always goes back to data flow and seeing "does this method have access to this data? What is this data looking like?" In our example, we were able to see right there. OK. The first portfolio item which the page needs the page needed that portfolio item instance variable it came up nil that instantly tells us where the problem is that says that our problem is that we have not set the values in the portfolio item. We make the change go in and then we can see that the data is all there and then everything will work.
Before I end on this I want to say that this was kind of a simple type of bug to fix. There are many other times where it's not quite as simple and that's what I want to get into right now and show you how pry can help out in those circumstances.
I'm going to come down to show remove that and then if I come back to our blog controller and I still have our special blog's scope right here. I'm going to open up a blog.rb, you can see our scope is set for special blogs I'm going to come back and I'm going to create another scope here. This one's going to be something like
def self.featrured_blogs limit(2) end
In the blogs controller, I want you to see the next steps because in our last example that worked well when we only had one item that was missing. That's kind of a basic error but many times you run into issues where values actually get changed. In other words, if we have blogs equals this and then somewhere down the road some other method actually changes the instance variable for blogs and changes it to the other scope of featured blogs. If we come back to the site and go to blog you can see that it only has two items.
Even though our all call right here with special blogs even though this set it and it had all of the items, right here this came and it changed it. If we were to see something like this where we have behavior but it's unexpected like we're expecting 20 blogs and we only get two, then there are some cool ways of being able to set multiple breakpoints with pry.
I can say binding.pry right here and I can set it here and I can set it here. So in a real-world example, you would look at every spot where the value is. You'd see every single spot where blogs is being set and then you can go and take a look to see what is actually happening.
If I come in here and hit refresh this is going to hold up and if I come to the terminal, I can type @blogs and right now it's nil and it should be because in this little breakpoints spot this means it is about to go to line 9. So I put binding pry here on line 8 which means that blogs is not set. It'll be set in the next value. What I can do is type the word next and what next does is it actually lets me step into the next line of code.
If I now type blogs this brings up all the blogs and it formats them really nice and one of the other cool things that this does this actually lets me navigate through them using the "J" and "k" keys. If you ever see this little syntax where you have a semicolon on the bottom left-hand side of the screen, j it lets you move down, K lets you move up. Control + "d" lets you skip down and then control +"u" lets you skip up one page at a time. If you want to quit out of it and get back into the regular terminal just type the letter Q and now you're back.
With blogs, I can also do count. So here I can see that. OK I have the 12 blogs that I expected but that's not what I'm seeing on the page. So why is that? Then just type next again. And now it takes us to the next line. Check what blogs count is equal to, still equal to 12. So far so good. Type next again. Now we'll type our blogs count. Now it's 2.
OK, This is the problem because right now obviously we inserted this bug so we knew what the problem wants. But imagine that you had code that wasn't quite this intuitive. So, in other words, like say that you had some conditionals where you wanted to show certain blogs to certain users and you wanted to hide them from others. A great example would be when we implement the concept of draft blogs being shown to you as a site owner but not shown to other users. Let's say that they all the users were being able to see all of the blogs that would be a bad thing. And this is a way if we set a number of break points here with binding pry this is a way where we could step through all of our code and see the exact line of code where the mistake is happening.
We could step through it. And then finally see oh my goodness that is where its happening that is where we went from showing all of the draft blogs only to the site owner and this is where we accidentally set it and now it's available to everyone. Then we can go we can make the change and we are good to go and we fixed our bug and we did it in an intelligent way of debugging instead of just guessing on what the problem is.
This is definitely in the list of best practices and if we hit continue it'll keep on moving down to the next line. And if you type exit ill get out and then we can come into the code and we can delete each one of these we can delete the line in code that was causing the error save and we are good.
I'm going to quit out of here and like I said because we perform that refactor I actually want to do a code commit for this one.
- git status
- git add .
- git commit -m "Refactored before action for portfolio setting"
- git push
Let's come up and we can close out pry. Nice work on that in the next guide. We're going to talk about error management.