 Good morning, I'm very honored to be the person to kick off this conference for you all. You probably know from all the banners we have around downtown, the theme of this year's conference is one industry, one stage. The last few years have been exceptionally great for our industry and with all of us here at one stage, our industry is stronger than ever. So ladies and gentlemen, welcome to Clean 2015, the biggest straight show for the laundry and dry cleaning industry. Nah, I'm just kidding. If you're here from the dry cleaning industry, unfortunately, your conference actually ended two days ago, you should probably stick around anyway because as you will find out, our industry is also very obsessed with keeping things dry and clean. Alright, let's try this again. Welcome to 2015, defense industry. No, but really, welcome to RailsConf 2015 everyone. I'm Gottry Chan, you can find me on the internet as Chink and Code. I love coming to RailsConf, this is actually my fourth RailsConf and this is actually a conference with a lot of sentimental value for me personally. Four years ago I was at RailsConf, my first tech conference ever on the RailsConf scholarship program. I came back the year after, went to the RailsCore office hour and had my pre-quest merged since then, I've been making regular contributions to Rails and shortly after RailsConf last year, I was accepted into RailsCore team and a year later here, I'm speaking at RailsConf for the first time. So I would like to thank the community for supporting me in what I do and if you were at Austin four years ago, I would like to personally thank you for shipping in for my ticket and I hope that was a worthwhile investment for you. And if you're here for the first time or if you just recently picked up Rails, I would like to welcome you on behalf of the Ruby and the Rails community. I promise that you will have a good time here. In fact, I had such a good time from RailsConf last year, I took one of the sign with me and traveled around the country with it. As you can see, we have been free a lot. We went to Hollywood, we went on the Conan show together. We sat at the pocket table and we even made it to Canada after spending a few days on a big boat. By the way, if you're thinking about this, please don't steal a RailsConf sign, at least not until the conference is over. Like I mentioned earlier, I'm on the RailsCore team. I also work on the newsletter called This Week in Rails. If you would like to keep up with the latest changes in Rails, this would be a pretty good way to do it. You can subscribe to the newsletter at that URL. Or if you're interested in writing this newsletter, we should have a chat after this. I work for a small agency in Vancouver, Canada called Ruby House. Yeah, speaking of Canada, if you have never been there and if you would like to experience Canada for yourself, I rolled a gem for that. You can run gem.canada and all you need to do is require Canada and you'll be able to program like a Canadian. If you want to actually experience Canada though, we're organizing a Ruby conference in Vancouver later this year. The details are a little bit sparse right now, but if you're interested in coming, you can follow the Vancouver Ruby Twitter account to stay in the loop. All right, let's actually get on to the real talk. Like many of you, I watched David Skeeno last year and I stopped calling myself an engineer and I became a software writer instead. After carrying this job title around for a year, I realized that perhaps this didn't really fully capture what I do for work. You see, when I work on clients project, I get to work on some pretty complex Rails apps and when I work on these complex Rails apps, I spend most of the time fixing things instead of making my code look pretty. So either I'm fixing an existing bug in the app or perhaps I'm writing some new code and then new code somehow broke the app in unexpected ways and I have to figure out why. So this is something that I take a lot of pride in and you can see it, I take myself very seriously. But of course, in reality, what I actually do is pretty boring. All I do is I dig into the code, I figure out what's wrong and I fix it, rinse and repeat. By the way, that's my coworker, Horse Can Code. If you see him around the conference, please do not be alarmed. As boring as my job is, in reality though. Because I work on the Rails code base, so when I get dropped in into these projects, sometimes people think that I'm doing something really special for them. In fact, you've probably heard of this before and you might even feel the same way personally about it. This Rails thing is basically just magic and it might be cool for a while, but as soon as things stop working the way you expected, magic becomes black magic and black magic is obviously bad because you can't understand it and the only way out is to hire a wizard to fix your code for you. One of the Rails 14 members have recently tweeted about this topic, so it turns out that there's actually no magic in Rails. It has some sane default and conventions, but all you need to do is actually just read the documentation, learn about these things yourself. One of the, this tweet sparked a conversation on Twitter and one of the replies kind of summed it up pretty eloquently. Perhaps what it really is is that Rails work a little bit too well out of the box. You can be really productive without actually spending a lot of time studying the documentation, so it almost feels like it can read your mind. And that's basically the key. The cost of learning Rails is not piled up front. You do not need to spend a lot of time learning before you can start writing code. And with that lens, perhaps, Rails is not really magic after all. Perhaps we're just treating it as a black box because we don't really understand what's inside the black box. So today we're gonna pry open the black box together so you don't have to be afraid of it anymore. You probably had this happen to you before. You wrote some code in Rails app and it blew up on you and you have no idea why. The first thing you need to do is don't panic. Take a deep breath, it's not too bad. You see, what actually happened here is that you wrote some code and you try to run the code, you expected the code to do something for you and that didn't happen. Perhaps the code did something else, perhaps nothing happened or perhaps you get an exception. But you see, you actually have some pretty solid advantages here. Well, first of all, you wrote the code so presumably you probably understand the code that you wrote and because you wrote the code, you have access to the code, you can run it, you can modify it, you can do whatever you want with the code. And first, because you wrote the code, you understand exactly what went wrong here. Now, you might not know why or how it went wrong yet but what you do know is that you expected A and B happened. And that's pretty key. Finally, because there's no magic involved, your bug is not going anywhere, it's not gonna magically disappear on you so you have time to fix it. So with that in mind, we're gonna look at some of the weapons you have to help you figure these things out when they do not work the way you expect. This is probably a little bit obvious but as Chef Riaff pointed out on Twitter, you should probably start with checking the documentation. Surprisingly, not a lot of people know where to go look for Rails documentation. This is not an API for Rails that spits out JSON, this is actually the official documentation. So this is where you get the documentation for a latest stable release and if you're using not the latest stable release, that's not a problem, you can get the docs for any tagged version from the same website. And finally, if you're on the bleeding edge, if you're running edge Rails, or if you're using beta or an RC, you can go to edgeapi.rubyandrails.org and you'll see the latest documentation for what is on master. There's also this thing called Rails Guides which is basically more detailed and hence on articles about specific topics and same thing, you can get a tagged version or you can get the edge version as well. Another seemingly obvious thing is that you should probably be using the latest version of Rails because the problem you're having might already been fixed but this is easier set than done because which version is the latest, how do I find out? If you're new to this, this might not be very obvious because the Rails versioning scheme might not work the way you expect. The first digit in the version there is the major version and the one in the middle is called the minor version and the last thing is called a patch version. Now the major minor thing doesn't really matter so much because the first two digit together is called release series and basically for this purpose, as long as you stay on the same release series, it should be 100% compatible with what you're using only with more bug fixes applied. So in other words, you should try to stay on the latest patch version of the release series that you're using. When a bug is yet fixed for a particular version, they get backported into this thing called the stable branches for a particular release series. So if you see that someone fixed the bug on GitHub, the pull request was merged but there's no released patch version for that yet. You can change your gem file and point that to the corresponding stable branch and you'll get the code instantly. Okay, so the easy stuff is out of the way. You read the documentation and you're using the latest version and you're still having the same problem. So this is a good time to get serious and dig in and get to the bottom of the problem. The first and the most powerful weapon you have is called the stack trace. You've probably seen it before. You get one of these things whenever you get an error in your app. And the first line is basically telling you what the error was and the rest of them is the stack trace. Stack trace is basically a bedroom trail of your code. It's a range and chronological order. The bottom is the oldest thing that it ran and the top is the most recent thing that was executed. There are apparently some talks of reversing this order in Ruby 2.3. I just heard that yesterday. But either way, one of them is the latest, one of them is the oldest, and it goes in that order. Perhaps a visualization will make it easier to understand. What this stack trace is really telling you is that at some point this create method and your post controller, can you, okay. Yeah, this create method in the post controller is executed. I wonder if I can fix this real quick. Sorry, give me half a second. Oh well, I guess it's just gonna be that way. Anyway, so this is the post controller and at some point Rails executed the create method here and that's the blue frame at the bottom of the screen. And now the create method eventually calls the respond to block and that's the purple frame on the stack trace and that purple block eventually called post.save. Ah, it's fixed, thank you whoever did that. It calls post.save which eventually calls the ensure author before save callback which is the red thing on the stack trace and finally that calls this ensure permission method somewhere and that's the yellow frame. And at this point something, we don't know what yet but something went wrong in here and an exception was raised. So really the stack trace is really just a snapshot of the last breadcrumb trail that led to the point where things started going south. Sorry, I know this is a lantern, no offense intended. But something is not right here. Well, first thing, someone must have called the post controller create method, right? Like it cannot just, you know, call itself in thin air and if you look at the, if you remember we didn't really call the before create or the before save callback directly. All we're calling is the dot save method and somehow that calls the ensure author and it's not showing up in the stack trace. So I don't think Rails is being completely honest with us here and yeah, come on Rails, we need the full story here. So it turns out that Rails is in fact hiding something from us here. Rails ships with this thing called the backtrace cleaner by default it will only show you the application stack trace, sorry, it will only show you the application stack frames in the stack traces and it will remove everything else. And in fact, if you look at your initializer folder you probably see one of these files and it tells you how you can customize this backtrace cleaner and at the bottom of there, there's a line that you can uncomment. If you do that, then Rails is gonna give you the full stack trace, which now looks like this. This is exactly the same error and because it doesn't fit on the screen anymore, I adjusted the font size a little bit. I hope you can still read it. If you can, I made another slide that zooms in for you, I tried to highlight the four lines that we see in the original stack trace. As you can see, it is embedded in this like sea of very tall stack trace. So, but you know, once we disabled the backtrace cleaner we see everything that's actually going on here. As it turns out this Rails things, it's just really cold on your computer that's executing somewhere and it's just, what it's really doing is it's just trying really hard to stay out of your way. This is pretty reasonable because when something went wrong it's most likely in your app code and by having the backtrace cleaner it helps you to focus on what is most likely to be wrong but at the same time, if you suspect Rails is responsible for your problems then you really need to see everything and to get the full picture and understand what's going wrong. Okay, so now we have learned to read the stack traces. You might start to appreciate how useful they could be but you only get stack traces when you have an error. What if you don't have an error? What if your code basically just silently failed or perhaps your app somehow executed some code and you have no idea how it got there? Well, you can just raise your own error. This is actually like, this might look very simple but this is actually a very useful thing to do. For example, let's say you have no idea it got to the ensure permission method and you can just raise an error within there and boom, you have a stack trace and you know exactly what lets you the execution of that code. Sometimes a stack trace just doesn't give you enough information to develop the problems though. As we mentioned earlier, a stack trace is a snapshot of the state of the system right before it when the exception happened. In reality, a bunch of other things probably happened before that point and the root cause of the problem can be anywhere within there. So as an example, let's say you got a no method error and you look at the stack trace and you understand why that's happening. You're trying to call a current user dot name but because current user is nil, you end up calling nil dot name and obviously that doesn't work. But looking at the stack trace here doesn't really help you though because you understand, yes, I'm getting a no method error because I'm trying to call dot name on nil but what you really want to know is why current user is nil to begin with and current user is set in the before filter all the way at the left. So the stack trace does not capture any of that information for you and that's not very helpful. So to find out why current user is nil, we're gonna look at this really advanced debugging method called the put statement. This is probably the first thing you learn when you learn Ruby but it can actually be a pretty powerful weapon for debugging as well. This is how you use it. You go into the piece of code that you want to investigate and you put so my god a thousand times. Well it doesn't actually have to be that but basically the idea is you want to print something ridiculous onto the console so that you can possibly miss it. So whenever it runs this code, it prints so my god a thousand times in your console and you will immediately spot it that is happening. And with that you can print a lot of other stuff in there. You can look at the variables you have access to. You can print anything you need on the screen to help you understand the problem. There are some other things that you can try to do here. For example you can put scholar which basically gets you a stack trace without actually throwing exception. So your code is gonna continue to run after that point but you still have a stack trace to tell you what exactly led to the execution of that code. There's also this thing called pp in the standard library which stands for pretty print. It gets you a little bit more organized output of complex objects when you print them to the console. And Rails also gives you this thing called instance values which basically gives you a hash of all the instance variables on the current object which is also pretty handy when you're debugging problems. The problem with the advanced debugging technique other than the fact that it's gonna pollute your logs with a lot of so my gods is that you need to know ahead of time exactly what you need to find out. So if you forgot to put up put statements for the session user ID variable then like you don't get the information in your log and you have to basically change your code add that back, rerun everything and restart over. Fortunately there's a better way to do this. Even more advanced debugging technique called a debugger. And if you're using Rails 4.2 or above you'll notice that you already have a debugger in your gem file called buy bug. And if you don't have one you can just add that yourself. So to use it basically just replace all the put statements with a buy bug call and when it reaches that line you get something like this in your console. From here you can execute arbitrary Ruby code so you can check the colors, you can check instance variables and so on. Besides the usual Ruby code there are some buy bug specific commands that you can run. I don't have time to get into that but you can look up the documentation yourself. And finally in Rails 4.2 you can also add this console helper in your ERB templates which allows you to do similar things but in the browser. All right so, but we still have another problem. Even the really advanced debugging technique of using a debugger does not do enough for us because if you look at the stack trace you will see that the first few frames that we actually want to investigate they're all Rails code. So it's not like you can actually open up the file and add the debugger call to the method. Or can we? Now if you look very closely you will see that there is a file name and a line number in each frame of the stack trace and you might be wondering hmm perhaps these are just regular Ruby files sitting on my computer somewhere so maybe if I open this file in my text editor and change it and save it perhaps that would just work and you would be absolutely right. This is one of the nice things about working with interpret language like Ruby. Most of the things you're executing they're just like plain text files sitting on your computer somewhere and you can modify them without recompiling them or relinking them or whatever. So you can totally just open up your text editor point it to this file, change it and it will work or there's a more convenient way called bundle open. So because you're using bundler for Rails app anyway you can just type bundle open the gem name for example bundle open i18n is gonna bring up i18n gem in your favorite text editor. And you can modify these files however you like you can add put statements in there or you can add debugger calls or you can change stuff around to experiment with any theories that you might have. You literally go crazy with this and not feel too bad about breaking things because once you're done you can run this command called gem pristine and it will basically restore every changes that you like all the damages made to the gem so you don't have to feel too cautious about doing this. There's one thing to remember because all the gems are loaded once when you start your Rails app if you made any changes to the gems, Rails or any other libraries you would need to restart your Rails server and if you're using Spring you have to stop that as well which gets pretty annoying if you're gonna make a lot of changes to these files constantly so you can temporarily disable Spring by setting the disable Spring environment variable and Spring will be disabled for that terminal session. Okay so now if you have your computer view and you actually try this in your app and you try running bundle open Rails you will notice something pretty strange. Yes, your text editor opened. Yes, you're in the Rails gem but the gem is empty. So this is actually because Rails is divided into a few smaller libraries and the Rails gem is actually just a meta gem that requires all of them so some of these libraries you might be familiar with is active record or active support but you don't really need to know what's the difference between each library because your stack trades already tell you which library you're looking at so in this case it's pretty obvious that you need to do bundle open active record so that's bundle open. Right so as an alternative if you happen to have a Rails called locally on your computer instead of using bundle open you can also modify your gem file and point it to a directory and this directory could happen to be the Rails checkout that you have locally and this is pretty cool because the Rails checkout that you have is obviously a git repository so all the commands that you know about git already works in there you can stash stuff, you can reset stuff to clean after yourself, you can even check out specific branches or specific text to like if you suspect that the latest 4.2.1 has a regression you can compare between 4.2.0 and 4.2.1 simply by checking out the corresponding text in the repository and restarting a Rails server so that's pretty convenient. Okay so going back to the stack trace so let's say you finally figure out how to make this bundle open thing work and you finally open the first file in the stack trace it looks like this you can if you have 2020 vision you can probably read it but I don't and this file is like 300 lines and I have no idea what it is about what do you do? Well first of all take deep breath it's not that bad. There are a lot of stuff going on in the file but most of them doesn't actually matter to you what you need to do is you need to stay laser focused on the problem you're working on and ignore everything else otherwise you would just get overwhelmed like trying to learn all of Rails and the one hour debugging session that you have is not gonna work so to help you with that you can basically ask yourself four questions whenever you're looking at method try to as quickly as possible find out what this method is supposed to do what are the inputs to this method now that could come in the form of the arguments in the method or it could be instance variables or it could be global variables but given the specific set of inputs what is the expected output of this method and finally the actual output match to the expected outcome so let's follow the breadcrumbs and see what happens we are in this method this is the method that the stack trace pointed us to it's called find SDI class now without knowing anything else about this method you can quickly notice that this is probably the right place to look because in our stack trace we're getting as a class not found error and this line is raising as a class not found error so this is probably what is ultimately causing a problem what is unclear though is why is this code raising this error like it just is an unconditional race why is that so it turns out that is rescuing name error and then ignoring the origin name error and raise this subclass not found error okay so now the problem shifts into this because we know that the code rescued name error so something from here must be throwing a name error for some reason and because you learn to use the debugger you can quickly check the value of this store full SDI class thing it might be a variable it might be a method but it doesn't really matter because it's gonna return a boolean or like a true V or false C thing and based on that you can quickly eliminate either one of these branch so let's say store full SDI class is false so all you need to do is look at this compute type method and figure out why is raising a name error but there's a problem though we know that we need to look inside this method but we don't know where this method is actually defined because Ruby allow you to mix in a lot of modules in the classes the answer to this question might not be immediately obvious to you the first thing you might try to do is open up your text editor and do a project-wide search but this doesn't usually go very well in Rails because we override the same method like 50 times and call super in num so you're probably gonna find a lot of definitions for the same method but fortunately because Ruby knows about where this method is otherwise it can't call it right so we can actually just ask Ruby for this information to do this you add a debugger like we always do and as to be in the same context that calls a method but once you're in there you can call the method helper which is a method that takes the name of the method you wanna check in the form of symbol and it returns some pretty useful metadata so for example you can ask for the source location which is a string that tells you where which file you find this method and which line number you find this method or you can ask for the owner which is the module or the class that contains this method that you're looking at if you add the method source gem to your gem file which by the way will be a part of Rails 5 it will be in the default gem file if you have this gem then you can even ask for the source of this method so if you type method compute type dot source it will literally print out the method definition and your debugger for you you can even get the comments that goes before the method so perhaps that would help you understand what the method is intended to do so with that information let's say we got to this method somehow it looks like a lot again but once again we need to stay laser focused so we quickly eliminated one of the branches and now we're left with this unfortunately after reading the code a few times you still have no idea why the code is written in this specific ways in particular you might think that something is fishy in the free lines that I pointed out and unfortunately there are not a lot of comments around it to help you understand what the code is supposed to do what do you do then well at some point in time some human being wrote this code presumably with a clear purpose in mind usually we don't just put code in Rails for reasons so one thing you can do is you can probably go back in time look at the initial implementation and go through the incremental changes that it's been through and perhaps that would help you understand the current implementation and the rationale behind it and this is exactly what GitLock will tell you it will tell you all the commits on this file you can get the same thing on GitHub by using the history view but what is even cooler is GitBlame so GitBlame basically tells you who touched the last who is the person that touched each line in the file last and more importantly it tells you the commit that touches that line and with the SHA you can do a Git show and it will show you the commit and it gives you the full context of the change and you can obviously do this on GitHub as well there's a blame button that does the same thing but unfortunately this commit turns out to be a refactoring commit that basically just moves a few things around so it doesn't really explain anything about the purpose of the method so what you actually want to do is you want to see the second most recent commit that touched the line that you're interested in and to do that you can run GitBlame with the SHA and the carrot after it the carrot is very important so I would like to highlight that and if you can see it from the back I will zoom in for you and zoom in a little bit more so yes, this is how you tell GitBlame to start from the parent of the SHA you have given and that basically achieves the result of you want to blame the second most recent commit that touched that line and if you prefer to do this on GitHub I wrote a Chrome extension to make it easier unfortunately there's a button there I need to fix but hopefully it will be fixed by the time you have a chance to try this at home or if you are interested in working on this you can compare with me later at the conference okay so after all the work you have established a pretty good understanding of the problem but with everything else that's going on your app you have so many gems, you have so many libraries it could be so many things, too many variables what do you do? naturally one of the solutions is to generate a new Rails app and see if you can reproduce a problem there and if you can then it's probably a Rails bug and if you cannot then it's probably some other gems that you use in your app you might not know this but if you do specify the depth flag when you generate a new Rails app it will set it up to point to your local checkout so a few other nice things like a disabled spring and stuff so basically it's a more convenient way for you to do some of the stuff that I mentioned earlier sometimes you don't really need a full-blown Rails app to reproduce a problem for example if you're having an active record issue all you need to do is set up a model connectivity base and then you can test that problem without being in the full context of a Rails app for that we have these bug report templates on the Rails repository it's in the guides folder and then there's the bug report template folder they're basically minimum boilerplate code required to run the test case against the Rails libraries and there's one for active record one for action pack and we just recently added a generic template for you to test everything else so with your problem reproducing fresh application and isolated test case it's very easy for others to help you so you can probably if you can consistently reproduce your problem it makes it very easy for other to investigate and maybe fix the problem for you so being able to reproduce a problem on a fresh Rails apps or in one of those bug report templates and then attach that to your issue would greatly increase your odds of getting helped or with everything you've learned from this talk you probably know enough to nail down where exactly the problem is happening and you can probably just fix it yourself and you can send a pro quest for that at this point you might be like wow I really know all these stuff I did not learn anything new from this talk I already use all these things you talk about in my own app and you are 100% right you probably know these things already and you're probably debugging your applications every day at work and that's kind of the point this Rails thing it turns out is just Ruby and when things doesn't work in Ruby well it just quickly turned into Ruby and it turns out that Rails is just another big legacy code base which is probably not that different from all the other code bases that you have to work with so you probably know how to deal with this already and if you would like to practice any of these things or if you would like to refund because you tried these on your app and it doesn't work we are hosting a Rails core community office hour on Wednesday during the happy hour at the HeroCube so you can bring your app and you can come talk to us and then we can probably help you with that or you should probably do this if you haven't already Eileen one of the Rails contributor is running a lab later this afternoon on contributing to Rails and she's gonna cover a lot of the things that I didn't have time to go into so if you haven't already sign up for the lab it's this afternoon that's all I've prepared for you today once again you can find me on the internet as changing code and thank you very much and enjoy the rest of the conference