00:00:12.259
Thank you! I said hi.
00:00:18.660
Hey! Um, very cool. I've had a great time here today. I am so excited for you to be learning.
00:00:25.980
Before we get into it, like we talked about, if you'll go to railsconf tutorials.com, there's a setup section where we clone a repository that we're going to use in the workshop. Then it runs `bundle`, and based on the Wi-Fi today, it may take about 40 minutes to actually install everything.
00:00:37.800
So, if you'll start that now, while I give my little preamble here, it may be ready for you in about 40 minutes.
00:00:43.140
What we're going to do, as Jeff said, is I'm going to babble on here about Ruby for about 40 minutes or so, take a break, and then we'll do a workshop where we're going to create a little beeper application that sends texts and emails when errors are reported—all through the magic of Ruby. It will use the Twilio API, so if you want to set that up too, that may help things along a little later.
00:01:04.500
All right, so back to the idea that Rails is just Ruby. When I first saw Rails, I was like, 'Whoa!' I was literally astonished at how cool it was. I'd been doing software development for a while in the .NET space, and previously some Perl, and seeing Rails was just unbelievable.
00:01:21.900
It seemed crazy how magical it was, how much was built-in to make the developer happy. The more you learn about how all of this works together, the more you realize that Rails is a great collection of patterns and APIs. It got its entire ecosystem from the Ruby ecosystem, which is set up for maximum developer happiness.
00:01:36.119
The entire Rails ecosystem is basically one big hippie commune, and we're all making sure that we're happy. That's so empowering and so cool!
00:01:42.300
So what we're going to do today is look at a couple of different ways that the Ruby part of Rails helps make Rails, well, Rails.
00:01:51.660
There are aspects of Rails that just seem magical, and I keep using this word, 'magical,' as sort of a theme while attempting to teach the Ruby part of Rails. There are things that Rails can do where it becomes so easy for you to provide great value to your business and to the awesome websites you're creating.
00:02:11.220
You can easily log every page load that happens. For instance, go into a controller and log every time something happens—not necessarily to a log file, but you can create an access log for HIPAA applications, and this would be trivial to do in Rails. In other frameworks, it might not be so straightforward.
00:02:35.700
Consider the ability to send updates whenever a record is updated. You can transmit those updates to another service, allowing for a full-text search engine optimized for lexical pattern searching. Anytime something changes, you can send in those changes. This is pretty magical stuff, and I know, right now, we might be like, 'Oh, wow.' But the ability to do this really is game-changing.
00:02:50.820
The entire idea here is that it's not really magic; it's Ruby. But when you're first getting into it, it can feel a little magical, especially when stuff just works with a well-crafted API that listens to what you're doing. Sometimes you have someone who has been working on it for a couple of years, saying, 'Oh, you just do this,' and you're like, 'Are you really?'
00:03:30.660
Now, let's take a whimsical analogy. Do you think Gandalf thinks about what he's doing as magic? I'm not sure he does. He knows the commands for his staff or whatever, and it just works for him. In his mind, he's just using an API. Perhaps a better example might be Darth Vader. He has actual magic, listening to people's thoughts from halfway across the galaxy, seeing the past and future, and using mind powers to choke people.
00:03:51.060
To him, though, it might not be magic; he's just figured out the APIs of the midi-chlorians that are throughout his body. Possibly, we just need to understand the APIs of Rails and Ruby. I'm glad no one left after my disparaging comments about Gandalf the wizard. You can talk to me afterward if I hurt your feelings.
00:04:06.120
You guys are wizards, right? When businesspeople ask you to do things, they often come up and say, 'I have no idea how long this will take. It could be several weeks.' They don't even know, and by the time they're done explaining, you may have already built a prototype because it was just about implementing a plugin or gem or whatever.
00:04:22.920
To them, what you did seems just mind-blowing. But the reason all of this exists is so that we can create business value, which is the whole reason we get paid to do this. That's why we provide back to open source, and Rails helps us along the way.
00:04:41.220
A couple of different ways that Rails assists us that we will cover include blocks, before filters, callbacks, models, and inheritance. We'll look at inheritance specifically in a controller, but it all starts with the block.
00:05:00.780
So, some Rails developers were asking, 'What is it about Rails that makes it feel so... Railsy?' What's the one feature that really enables all of the rest? At first, I thought it would be something like `method_missing` or some other dynamic nature. Maybe it was Ruby's ability to have config variables without declaring them first, but no, it wasn't those.
00:05:20.230
It was blocks—the ability to send information in and change your program's behavior. We're going to spend some time diving into blocks. A block, in this context, is the part of code that exists between the `do` and the `end` keywords.
00:05:44.580
Inside the block, you have code that represents executable logic. This code is essentially a closure, something you send in to perform at other times. For example, if you open IRB and run a code snippet where you put 'YOLO', you’ll see it get printed out 10 times. That's valuable code right there!
00:06:07.860
You might have seen similar patterns in Rails templating. When looping over users, you will often use a block syntax. The block runs from `do` to `end`, taking each user as input and permitting you to produce outputs accordingly.
00:06:24.840
You might also see this where you're creating a user and passing a block into the `create` method, setting the user's properties in that context.
00:06:38.940
We're also able to loop over collections using enumerable functions like `map`, which will create a new array of the results. Blocks can also employ alternate syntax using curly braces for single lines of code. If the code spans multiple lines, stick with `do...end`; for single lines, prefer braces.
00:06:55.560
Once you start identifying blocks, you'll see that they are ubiquitous throughout Ruby code. They are present in config values, allowing the code to be executed later.
00:07:08.760
Every method in Ruby can implicitly receive a block, and while you don't have to do anything special for a block to be passed in, if you want to use the block you've received, you need to yield to it. Yielding to the block is most commonly seen in Rails applications within views.
00:07:22.920
In Rails, for instance, the application template yields to the specific template being called. So when you yield to the main view, you're allowing that block to execute.
00:07:39.240
You can also have parameters for blocks, but a little gotcha is that if you don't send enough parameters, you won’t get an error; it will just return `nil` instead.
00:07:57.660
A quick visualization of how it works is like this: for each argument sent, it comes to the local value parameters of the block. Imagine taking each pair from an array and inserting them into your block.
00:08:14.580
A few advanced tips: don't use `return` in your blocks unless you really want to, because that return may jump out of the invoking method instead of returning within it. It's unlikely that you would want to do this.
00:08:32.640
Instead, remember that Ruby itself provides implicit returns at the end of each method. So, think of the block’s last line as the return value you want, saving the need to use `return` explicitly.
00:08:51.720
Sometimes, you might need to execute a piece of code that could fail, and when it does, you still want to have it execute. Richard, who is here and just got married, created a gem called `river_retry`. You can set how many times you want to attempt re-running a block if it fails due to an exception.
00:09:08.880
In this setup, you specify how many times to retry, and if there's an exception within the network communication, it will re-attempt the defined number of times. This is an example of a human trick that Ruby handles gracefully, made possible through blocks.
00:09:22.560
Next, let’s talk about before filters, which occur in a controller. In our vocabulary, controllers comprise actions that appear like methods. Actions are interactions with the browser.
00:09:34.260
For instance, you might show a user, create a user, or list users with the index. You can apply before filters that execute code either before or after each of these interactions.
00:09:46.920
Before filters can halt execution, and this gives them even more power—if a before filter returns false or redirects, the actual code will not execute, thus allowing you to enforce certain conditions.
00:10:04.860
For example, when displaying or creating a user, you could check if the user has the rights to perform these actions. This also helps to dry up your code, as authorization can be managed uniformly between creating and editing.
00:10:25.080
You could easily have a before filter in your application that checks for user login and redirects to the login page if the user isn't authenticated. Here's an example of that in action.
00:10:38.760
We implemented a before filter that ensures users are logged in. If not, they'll be redirected to the login page. You could establish this filter for any action, ensuring that the user is authenticated before any record is fetched or displayed.
00:10:54.360
Often, instead of using block syntax, we set method names when applying before filters. So we declare a before filter, specify a method name, and the same functionality applies—this is a common practice.
00:11:12.360
Now, we can set this up in the application controller, thereby allowing any inheriting controllers to utilize it without repeatedly defining the same before filter. This approach secures every request in your application against unauthorized access.
00:11:28.680
Moreover, you also have the ability to skip certain before filters. For example, if you have a posts controller behind a paywall, but for a specified share token, you want to grant access, you can accomplish that using the skip_before_filter method.
00:11:43.320
This allows you to create a simple public and private controller structure, fostering a hierarchy throughout your application—ensuring that if your API controller is protected, it applies standards across all API requests.
00:12:00.960
Next, let's discuss callbacks. Last year at RailsConf in Austin, Texas, I gave a talk about why you should be cautious in using callbacks in your model applications. While they can be powerful, they can also lead to complications.
00:12:16.680
But for now, I want to focus on the powerful aspects of callbacks. They allow you to define code that executes later during the lifecycle of an Active Record.
00:12:32.040
For example, an obvious case might be to do something after a record is created, such as creating another record. I appreciate using callbacks like before validation or before save, where you can execute code just before a record is saved.
00:12:51.180
This capability is very cool. Some of the most common callbacks used include before validation, before save, after save, and after destroy.
00:13:06.840
Within these callbacks, you have the flexibility to insert your logic. For instance, with before save, if you set it to return false, it will halt the saving process. Meanwhile, in before validation, you can write code that helps a model pass its validations.
00:13:25.440
Another great use for before validation is setting default values—such as when a user hasn’t specified one.
00:13:43.380
Let me present you with two examples: one involves a common scenario—a user model, where we define an action to downcase email addresses before validations. You may wonder why one would downcase emails, particularly if using Postgres.
00:14:03.540
The issue arises when someone inputs an email with a capital letter—searches won't match, unless configured for case-insensitivity. In most cases, it’s simpler to just downcase all your emails when saving.
00:14:22.860
Before validations are helpful for formatting and setting default values; I strongly support their use. Another case often seen in the wild relates to full-text search indexing.
00:14:39.960
When you utilize something like Solr, you want to ensure that anytime a method is added or updated, it gets reflected in the index. Without callbacks, you might need to re-index your entire database regularly, leading to lagging or out-of-date records.
00:14:56.580
Instead, with callbacks, you can update the index in real-time whenever a model changes. This creates a consistent lifecycle that you can hook into seamlessly.
00:15:12.660
Using Sunspot, you call the `searchable` method and pass in a block, allowing full-text search configurations. Now, anytime your model is modified, it automatically handles updating the index.
00:15:27.420
To use it, you’d just call `post.search` with search terms, and Sunspot will manage the interaction with the Solr server to return results and maintain local data.
00:15:41.640
The Sunspot setup utilizes after-destroy callbacks, which automatically handle the removal from the index when a record is deleted. This functionality exemplifies how blocks make these processes efficient.
00:15:56.760
Now, let’s move on to the workshop segment. Does anyone have questions on anything we've discussed so far?
00:16:09.780
Yes?
00:16:15.900
The question pertains to passing data into blocks or closures. Generally, you'd yield with a specific value, which can go into it, akin to enumerating over an array. If you needed to implement closure-like behavior, you might need a lambda, which you actually call instead of yielding.
00:16:35.280
This allows maintaining access to outer variables and enabling monitoring during changes. However, regular blocks don't inherently work that way.
00:16:53.940
Can you differentiate between blocks, lambdas, and procs? Those distinctions can be tricky, but they are vital.
00:17:10.560
If you deal with callbacks, keep in mind that having many side effects tied to saving a model makes it complex to discern the sequence of operations occurring with each save. This increases the testing difficulty, as you have to account for those side effects in your tests.
00:17:32.520
You will have to decide whether to stub service calls or use fakes in your testing. In unrelated tests that save a record, you may need to manage whether the callback will trigger, adding a layer of complexity.
00:17:51.000
For example, if saving a model triggers calls to an external service, making testing for this process tight is crucial, but it branches out widely into your other tests.
00:18:08.820
Now, regarding your question about the critical nature of text messaging for the workshop—it's more of a cool feature. It's not compulsory, so don’t stress about it.
00:18:26.520
Let’s check if anyone faced issues cloning or bundling the repository.
00:18:43.080
When cloning, if you receive SSH key issues, it likely indicates that GitHub doesn't recognize your credentials. Switch to an HTTPS link for the repository; I can assist with this.
00:18:56.550
So, in terms of our schedule, we will take a five-minute break, after which we'll work on creating the Beeper program.
00:19:13.320
Think of the Beeper program as akin to a Honeybadger or AirBrake-like application that responds to errors with notifications. The repository is set to receive errors, and our aim today is to add functionalities for sending notifications.
00:19:34.680
For critical errors, we'll send text messages, while for warnings, we'll send emails to the developer on call.
00:19:48.480
Thank you!