A year ago, I had this idea: I was going to write things down. To be clear, this wasn’t a novel idea, and definitely not a new one by any stretch of the imagination. But it was something I wasn’t exactly in the habit of doing, and the first day of a new year seemed like the perfect excuse to begin creating this new habit.
So, I decided to start writing down all the things I didn’t know, and make an effort to learn them. I honestly didn’t know what I was going to be writing, and I didn’t know if any of it would be well-written, much less worth reading. All I was sure of was that I was going commit to doing it wholeheartedly, just once a week — not for anyone else specifically, but really just for myself. Thus began a year-long adventure of researching, writing, and sharing all the things I would discover in my first year as a software engineer in my very first developer job.
Today brings me to the end of the road on this journey of Technical Tuesday blog posts. And just like the first day of a new year, the last day of a soon-to-be-gone year is a seemingly perfect time to do some reflecting on a year of Tuesdays.
A few months ago, I had the privilege of being a guest on a podcast called Metaphorloop. One of the topics that came up was the nature of learning, and how teaching and learning interweave together to form an intricate, and somewhat inherently complicated web. We also talked a bit about this blog, and the process of actually writing a technical blog post.
Over the course of our conversation, I realized that my approach to technical writing is, highly likely, a rather unconventional one. There are plenty of blog posts out there that explain how to implement a technology, or break down a concept, and many of those posts are incredibly helpful, logical, and systematic in their approach. But I’ve always written with a kind of stream of consciousness kind of flow, as though you and I were sitting together, trying to work through a new gem or tough computer science theoretical concept together.
I was curious to see if there was a way to prove my approach to technical writing in some way or another, so I decided to take a look at the words I use when I talk about code. And boy, was that a revelation. The words I use when talking about code aren’t neccessarily logical, or even rational. In fact, they’re incredibly intuitive, and emotive. For example, I use the word fear in seven different posts. I also used the term afraid twice, and the word scared three times. Yet on the other hand, I used the word love ten times, and easy 46 times.
Maybe this is a sign that I’m not a great writer, or that I need to perhaps buy a thesaurus. But I also think that it’s a great metaphor for what I’ve learned over this whole year of writing these Technical Tuesday posts: even the most technical things aren’t based wholly in logic, and that caring about our code, and our efforts to make it elegant, beautiful, and concise are rooted far more in intuition than in logic. Perhaps what makes for good code isn’t that which we can explain or put our finger on as a better approach; instead, maybe it’s what we can’t quite rationlize, but what we feel to be right, beautiful, and a more elegant way of doing things. I never would have thought that this was the case unless I had spent a year of Tuesdays trying to teach myself, and by extension, a reader whom I don’t know how to learn something completely new and unfamiliar.
Even though this year of Technical Tuesdays has finally come to a close, this blog will stay around, and I’ll continue to write new posts here every once in awhile. After all, I’m nowhere close to the end of my list of things to learn about! Who knows, maybe I’ll come back to writing technical posts on a regular basis sometime in the future. But for now, it’s time for me to try something new.
I’ve written about the benefits of technical blogging in the past, and how one of the greatest draws of maintaining a blog is the personal benefits that it provides. To be honest, I started Technical Tuesdays from a slightly selfish point of view, with the hope that I’d keep a diary of sorts of my first year as a web developer, and all of the things I learned along the way. But it turns out that this blog evolved into something much larger than just that.
I have connected with people from around the country and across the world because of it. I have learned new ways of doing things, and improved my own code and refined my own skills as a side-effect of writing to explain things to others. Over this past year, I’ve received comments, tweets, and even pull requests(!!) with feedback on how to write and code better. I also recently learned that this blog has been read from Senegal to Kazakhstan, from Iran to Fiji. This little idea I had a year ago has proliferated into something that has been read by programmers in far corners of the world, and it has made me realize and feely deeply appreciative of how wonderful and widespread the Ruby and Rails community truly is. I am immensely grateful to be a part of it.
So, to those of you have been reading from the beginning, and to those of you who might have just stumbled up on this little corner of the web:
I crossed over to the dark side awhile ago, and I can hide it no longer. And when I say “the dark side”, what I mean is JavaScript. Surprise, surprise — I am now haunted by semicolons everywhere I go! I’ve been working a lot with Ember and a little bit with React over the past six months, and have both struggled and enjoyed integrating these frameworks with a Rails API. At first, coming back to Rails after a week or so of Ember was just like coming home: warm, comforting, and familiar. Yet the wild west of braces and semicolons called out to me. The more that I worked outside of Rails, the more comfortable I became with more functional programming concepts (read: concepts that are abstracted away such that you don’t ever have to think about them in the Rails framework). After awhile, I noticed that coming back to Rails was less like coming back to something familiar, but instead something that often seemed limiting and constricting in its conventions.
As much as I love the convention over configuration format that Rails brings to the table, there are times when I wish that there was a better way to do something. A lot of my desires lie at the crux of two forms of programming that I respect, and yet see both benefits and drawbacks in: functional programming and object-oriented programming. While JavaScript is an OOP language, libraries such as Redux or Nuclear JS emphasize more functional programming techniques like unidirectional data flow, for example. Ember is very much an object-oriented framework and, similar to Rails, is massive with a decent amount of abstraction hiding what’s actually going on. Yet Ember is also heading in a more functional direction, embracing the unidirectional dataflow approach used in Redux, which Ember refers to as “data down, actions up”.
Without veering too far off topic here, what I’m trying to get at here is this: we can learn a lot from observing how other frameworks (and even other languages!) handle their code when things get messy. I’ve come to respect Ember a lot over the past few months, and one of the many reasons I do is because of how the framework handles encapsulation. Ember has a pretty fantastic way of packaging up view logic into a single, standalone piece of code known as a component. Ember components are powerful because they can be rendered as many times as you need, and contain the logic for how something should appear. This means that we can iterate through an array of objects and render the same component, an encapsulation of how that object should appear, and only change the code in one place should we need to do so. I love how components work, and I’ve wistfully longed for a way to do something similar in Rails views. It turns out that someone else also wanted the same thing I did, except that he actually built it — thank you, Nick! And now we get to play with his creation, which is aptly called the cells
gem.
The cells
gem is packed with a cornucopia of functionality. Seriously: it does so many things — all the things! But before we go down the path of all the bells and whistles that this gem provides us with, it’s important to understand what it is meant to do at its most simplest level.
So much of the time, our Rails views are the first files to devolve into a complete and utter mess, with if
else
conditional statements in slim or erb that make it hard to read and really shouldn’t even belong there. But at the same time, we don’t really want to put them in our controller either, and it seems strange to make a model responsible for knowing how to present itself (and effectively blur the lines between the Model and View in a MVC framework). As it stands, partials and helpers are the only good solution to this problem, but they’re not really “good” solutions by any means.
Rails views are meant to be dumb — that is to say, they shouldn’t be responsible for determing the logic for how to render anything. Theoretically, you should just pass them some information, and they should spit it out in the correct format. But with partials, this can easily get out of control; we quickly end up with “decider logic”, or some sort of conditional statement that determines how the view should render itself. If we get a little queasy just thinking about this, that’s a good thing: logic should live in a class, not a view of any kind!
And that’s where the cells
gem comes in. At its core, it gives us an easy way to create a kind of Ruby object that has a single responsibility: rendering a template. Yup, you read that correctly: an object that renders a view. Or, as the documentation refers to them, view models:
“Think of cells, or view models, as small Rails controllers, but without any HTTP coupling. Cells embrace all presentation and rendering logic to present a fragment of the UI. The scope of that fragment is up to you: it can embrace an entire page, a single comment container in a thread or just an avatar image link.”
So far, this isn’t anything too complicated, right? But what does this look like in practice? Let’s take a quick peek.
In our bookstore application, we have a navigation panel that the user sees when they log in. We’ll probably have a button or tab that will reveal past addresses that are associated with the current user’s account. The annoying thing about addresses is that we probably want to format them different, depending on whether they have two street addresses (think apartment number, suite, etc.), or if they have an international address, or maybe for some other edge case that we haven’t even run into or considered quite yet. Ultimately, it would be pretty great if we could just take all the logic of how and whether to render an address and pass it off to an “address component” that would be responsible for handling this.
Using the cells
API, we can do exactly that. And this is what it would look like in a template, using a helper:
1
|
|
The cell method takes two arguments here, the first of which is a symbol and effectively tells the method where to look for the object that will be responsible for rendering our @address
instance. And the second argument is the @address
instance itself. The helper above is actually calling this method invocation under the hood:
1
|
|
Things start to get really fancy when we start using the same cell to render a whole bunch of addresses. In fact, we can actually just pass off a whole collection of addresses to our cell, which then allows us to use our cell helper inside of our UsersController
:
1 2 3 4 5 |
|
This might seem kind of strange at first, but once we let go of the comfort that is Rails convention, we might realize something: this is just nothing more than object-oriented programming! We have an object that has a single reponsibility: rendering a view. In a way, this is pretty darn Ruby-eqsue, isn’t it? If we can encapsulate a unit of work into a service, why not capture a piece of functionality into an object, especially if that functionality is going to be repeated in our application multiple times!
Okay, so how exactly does this model somehow render a view? We need to know how this magic happens! It’s time to put these cells under the microscope and compose a cell ourselves.
Getting set up with cells
is pretty straightforward. First and foremost, we’ll need to add gem 'cells', "~> 4.0.0"
to our Gemfile
.
One important thing to remember is that this gem supports various templating engines, but it’s actually up to us to specify which one we plan on using. In our case, we’ll stick to simple erb, which means we’ll need to add gem 'cells-erb'
before we can run bundle
. Other templating options include Haml (gem 'cells-haml'
) and Slim (gem 'cells-slim'
). As long as we’re using Rails, this is all we need to do. However, if we want to add cells to a Ruby project that is not using Rails, we’ll need to specifically include the templating format in our Cell class (for example, include Cell::Slim
).
But we’ll stick with our Rails cell for now. We can very quickly create a cell by using a handy generator and run a single command to create our address cell:
1
|
|
This will create a few things for us. First, it will generate a cell model at the path app/cells/address_cell.rb
. It will also create a view template at app/cells/address/show.erb
. The structure of these files is crucial, since the call method will lookup the correct template from the correct cell model, and expects everything to be structured according the name of the cell we’re specifying.
Now we can get down to some cellular business. Let’s take a closer look at our cell model, at address_cell.rb
. Here’s what it starts off as:
1 2 3 4 5 |
|
The show
method (our only method at the moment), maps to the address/show.erb
file that is our actual view. This method calls render
, which will invoke rendering for the show.erb
view.
This is a cell at its most basic level, and theoretically, it’s all you really need for it to work. However, we can start to get fancy here and add properties, and private methods that we might want to use in our view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
We have access to the cell’s model in this context via its attribute reader; we can read the value of the model’s attributes by using property
. This simply delegates to the attribute on the model itself, which means that property :user
merely delegates to model.user
. It’s worth mentioning that our model is the very same instance that we passed to our cell helper — in this case, our @address
instance.
Now that we have our cell model ready to go, we can write our view. We can put any rendering logic into this single view, and render it accordingly. More importantly, if we want to change how all our addresses are rendered, we can just change the logic in one place:
1 2 3 4 5 6 7 8 9 10 11 |
|
And what if we decided to have another cell template that was less detailed, perhaps one that would map to an index
action in our AddressCell
model? We would simply create a app/cells/address/index.erb
template:
1 2 3 |
|
And make sure that it mapped to an index
action in our AddressCell
model:
1 2 3 4 5 |
|
Which would allow us to call it using the call style, where we could specify the action that we wanted to call:
1
|
|
In this case, because we’re not using the default AddressCell#show
action, we need to explicitly specify which action in our model we want to call. But we can still reuse our cell over and over again for different situations, which is super cool!
It’s hard to cover everything that the cells
gem does without rewriting the documentation, but there are a few interesting tricks up this gem’s sleeves that seem like they’d be fun to play with.
So far, we’ve been using the cell helper to render a single object instance at a time. But earlier, we had wanted to pass a collection of Address
instances to a controller action. There’s an easy way to do this by passing the collection
option to the cell
method. Rather than the second argument being an instance of @address
, we can pass a collection of Address
instances:
1
|
|
This will by default call the show
method for each of the addresses associated with the current_user
. If we wanted to use our index
action to instead render our address/index.erb
per address instance, we can specify this by using the method
option:
1
|
|
One of the default behaviors of cells
is to not escape any HTML, at any point. But, if we had a property that was actually going to return HTML that needed to be converted to escaped strings, we could simply include the Escaped
module:
1 2 3 4 5 6 7 |
|
HTML escaping is fairly well-explained in the gem’s documentation.
The super awesome thing about the render
method is that it’s not complicated, at all. There are multiple ways of writing the same thing. If we’re rendering the show
method, we can simply call render
:
1 2 3 |
|
And if we’re rendering something other than show
, like index
, we can either tell the method the name of the template to render, or specify which view to render:
1 2 3 4 |
|
The only other piece of functionality we would need to pass to the render
method is locals, which can be passed in as a hash to the method directly:
1
|
|
So easy to write and remember!
It’s also worth noting that I only just learned about this gem, which means that I haven’t played around with it a whole lot. There’s probably many different ways to go about implementing it, some of which will be specific to a given application. But, it’s worth exploring to see if it’s a useful tool for replacing some ugly, repetitive view logic you might have polluting your codebase. And whether you decide to add cells
to your application or not, it’s still pretty cool to see how people in our community are taking concepts and techniques from other frameworks and languages and applying them in interesting ways to Rails. To me, it’s a good reminder that we should never stop examining other ways of doing things — even if that means subjecting ourselves to more semicolons that we might like!
render
will proxy to the object’s show
method, but can be overriden if necessary. Read more on the gem’s Github page.cells
gem is one the most well-documented ones I’ve seen. The documentation covers everything, from the basics of its API, as well as how to test, cache, and troubleshoot the gem.cells
, wrote a great blog post highlighting the best practices of the gem’s implementation in Rails. Check it out over here!One of my favorite aspects of programming is the fact that there’s always more than one way to do something. In fact, I think this is probably why I consider the very act of writing and building software to be a far more intutive task, rather than a merely structured, logical, and rigid pursuit. The very notion of no “one single solution” to solving a problem is what makes programming both a critical thinking skill, but also a creative one.
Let me give you an example: a few months ago, I wrote about using slugs and the acts_as_url
gem to create human-readable urls for an application I was working on. Rails has a handy to_param
method that can be used in conjunction with this gem to generate a hyphen-separated string that can be used in the show
route of a resource in place of the object’s numeric id
, which is both unreadable and usually doesn’t provide any point of reference for the user. So, here we are, using slugs.
However, just because we did something one way initially doesn’t mean that our way is the only way to do it. Actually, I am certain that there are other solutions — and some of them might actually be more flexible than our approach! This was what I realized very quickly when I recently learned about another gem that solves the same problem of slugs in a different, and rather interesting way! In fact it took what I already knew about using and generating slugs in an url structure to another level by using text-based identifiers in place of ids. Basically, it allows us to query for objects by finding them using their slugs, rather than their id
s. Doesn’t this make you super excited? Time to find out more about this approach and become friends with the friendly_id
gem!
The friendly_id
gem, created and maintained by Norman Clarke, describes itself as “the Swiss Army bulldozer of slugging and permalink plugins for ActiveRecord”. And that’s probably a pretty accurate name for all the things that this one single gem is capable of doing!
Before we can really explore all of its neat features, we need to do some initial setup. We’ll start by adding friendly_id
to our Gemfile
, and then running bundle
:
gem 'friendly_id', '~> 5.1.0'
It’s worth mentioning here that if we’re running on Rails 4.0 or higher, we must use friendly_id
5.0.0
or greater.
Next, we know we’ll need to add a slug
column to the table in our database that we want to implement friendly_id
on. We’ll add a publishers
table to our bookstore application, and assure that they always have a name
and a slug
column when they are committed to the database. We’ll also add a unique index to the slug
column, since we’ll be using the slug in our urls, which means that no two publisher
instances should have the same slug — and also because we’ll want to be able to look up publishers by their slug rather than by their id
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
It’s worth nothing that if we were adding friendly_id
to rows that already existed in our database, we would need to generate slugs for these preexisting objects. We have a few options on where to put this command — in a rake task or from the console, for example — but we’d have to find each of our objects and call save
on them to generate their slugs. For example, if we were implementing friendly_id
on our preexisting Author
class, we would run this line:
Author.find_each(&:save)
Now, time to extend or include the FriendlyId
module in our model; that’s right, it doesn’t matter which one you do, just as long as the model has access to the methods defined in the module:
1 2 3 4 5 |
|
Now comes the actual implementation! We need to use one method in particular in order to configure the way that the FriendlyId
module will behave inside the context of the model. This method is aptly named as: friendly_id
, which is essentially just the “base” method of the FriendlyId
module:
1 2 3 4 5 6 |
|
This method sets the default configurations of what method (yes, a method and not a column in the database!) it should use when trying to find an object. It also allows you to pass an options
hash, which is what we’re doing when we pass it use: :slugged
. We’re effectively telling the friendly_id
method to use the slugged addon.
So now that we’ve got the most basic implementation set up, what does this allow us to do, exactly? Well, given our current model, we can now find instance of our Publisher
class by their name:
1 2 3 |
|
Cool! We’re doing almost what Rails’ ActiveRecord
find
method would do, but we’re now no longer finding by a numerical id
, but a string identifer that actually means something to both us as programmers, and our users!
But what if we didn’t want to litter our codebase with friendly.find
everywhere? There’s a solution for that, too. We just need to use another addon, which isn’t implemented by default, called finders
:
1 2 3 4 5 |
|
This allows us to invoke find
directly — but we have to be careful with this because it could conflict with other places where we are using ActiveRecord
’s find(id)
method. Now we can do something like this very easily:
1 2 3 |
|
As we continue to implement friendly_id
on other models in our application, we’ll need to keep in mind that any classes that participate in single-table inheritence must extend FriendlyId
in both the parent classes, and all its children classes as well.
But what else can this gem do? It’s time to finally start playing around with all of its functionality!
When the documentation called this gem the “Swiss Army bulldozer” of slug url generation, it wasn’t kidding! There really is a ton that we can do with the various modules and addons provided to us by friendly_id
. We’ll explore just a handful of things that we can modify for different use cases.
One question we should answer off the bat is how exactly this gem actually decides to generate a slug. It turns out that the friendly_id
gem has a should_generate_new_friendly_id?
method, which determines when and whether to generate a new slug. A peek into the source code of this gem reveals that this method just checks whether there is a slug column defined, and the base
method on the FriendlyId module configurations has been called or not:
1 2 3 4 |
|
The documentation points out that it is totally fine to override this method in our models — for example, if we only wanted our slugs to be generated once upon creation, and never updated.
By default, friendly_id
expects the slug values that we told it to use in our model to be unique. It also helps that we assured that this is the case by creating a unique index on our slug
column. But, what happens if an admin (or even a user) tries to create an object that would create a duplicate friendly_id
? Well, the gem handles this case in a pretty cool way: it just appends a UUID to the generated slug to ensure that it will be a unique value:
1 2 3 4 5 |
|
Pretty awesome, right? It really does seem like this gem is a developer’s best friend!
As nice as it is that we have the functionality to append an UUID sequence to prevent non-unique slugs, it would also be nice if we had some control over how to modify a potential clash in friendly_id
identifiers. Well, our wish is this gem’s command! We can use a lovely “candidates” feature (new in version 5.0
of this gem!) to set up a list of alternate slugs that we can use to distinguish records in place of sequence.
We’ll first add two required columns to our publishers
database, city
and country
:
1 2 3 4 5 6 |
|
After we run rake db:migrate
, and make sure that these values are all populate in our pre-existing records, we’ll tell the friendly_id
base method to use the slug_candidates
method, which is going to be a set of instructions on how to construct the slug
for any given instance of our Publisher
class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
You’ll remember that I mentioned that friendly_id
uses a method, and not a column in the database to generate a slug — well, this is exactly why it does that: so that we can override a method very easily! Now the friendly_id
base method will use first the name
attribute, then the name
and city
attributes, followed by the name
, city
, and country
attributes.
1 2 3 4 5 |
|
It’s worth noting that our method doesn’t have to be named slug_candidates
in the context of our class: this is just the base method of our FriendlyId
module, which means that we can mame it anything we want, so long as we pass it to our friendly_id
method when we tell it what we want to use to generate our id
s for finding our objects. The nice thing about using an array of symbols (as opposed to string literals or procs and lambdas), is that the FriendlyId
module will invoke a method of the same exact name on our Publisher
model, which can be helpful if we have a city
and country
attribute on each of our publisher
instances, which maps to a column in our database.
Of course, if we do happen to have an edge case where two instances of a Publisher
have the exact same name
, city
, and country
, the friendly_id
gem can handle this situation as well! What will it do, exactly? Here’s what the documentation says:
“If none of the [slug] candidates can generate a unique slug, then FriendlyId will append a UUID to the first candidate as a last resort.”
Nice! So we can always depend on our slugs being unique in some way or another — in the worst case (which probably won’t even happen that often!), it’ll just add a UUID at the end of the slug that matches another one, making it unique.
We’ve been working mostly with the slugged
addon, but there are also quite a few other addons available to us. One of the most interesting ones is the history
addon, which allows us to save different versions of an instance’s slug
attributes!
For example, if we had Article
instances that might allow for their title
s to be updated by admins, we wouldn’t want all of our urls to be broken when an admin changed a title on an article, right? Well, this addon helps us prevent that.
In order for us to implement this module, we need add a table to your database to store the slug records. Luckily, friendly_id
has a generator for this:
1 2 |
|
Now we just need to specify that our base method needs to use the history
addon:
1 2 3 4 |
|
And now in our controller we can do something like this!
1 2 3 4 5 6 7 8 9 10 |
|
There are so many interesting use cases for this gem, and it turns out that it does a lot of the stuff we already know about under the hood. One quick example: it uses Rails’ ActiveSupport
parameterize method, which is actually used by to_param
— and which we have already explored on our own!
So, there’s never just one way to do anything. As long as we’re willing to learn the fundamentals of how to solve a problem in one way, we can explore all the different solutions that people have already come up with. And when it comes to generating urls and handling strange situations with slugs, we’ve got it covered with our new best friend, the friendly_id
gem.
friendly_id
gem is a way to find objects and generate urls using strings instead of numerical ids. The documentation for this gem is fantastic, check it out!friendly_id
in its most basic capacity.friendly_id
base method works? Check out the source code.I’ve been rather reflective this past week. This is mostly because the end of this year of technical Tuesdays is now very much in sight, with only a handful more posts left to write. Also, I’ve been going back over old posts and correcting a few spelling and code snippet mistakes that have been brought to my attention (shoutout to all of you who have been proofreading for me!). All of this is to say that I never realized until recently that I’ve covered quite the spread of different topics over the past year!
But here’s the rub: I’m not even close to being done with my list of things I still want to learn more about. And even though that list keeps growing, I’ve noticed that the complexity behind the concepts I’m learning and writing about has begun to slowly change. While I started off focusing on syntax and DSL-specific topics, now those topics have become more theoretical in nature. While I used to write about things like the Rails group_by method and the ampersand operator, now I’m diving into more complex concepts like association callbacks and service objects.
This week took complex concepts to a whole new level. I’m talking about higher-level CS theory that I didn’t even know existed. It all started when I heard someone use the term “pub-sub” (yeah, that’s a thing!). And it stands for publish-subscribe, which is a messaging pattern used in software architecture. If you’ve never heard about this before, don’t worry — I hadn’t either! It’s apparently not all that common in Rails development, but JavaScript promises are a loose example for how they are constructed. But let’s not get carried away with semicolons and such nonesense. How does the publish-subscribe pattern work in Ruby? It’s time to learn all about it!
In the context of building out systems of software, the publish-subscribe pattern is a way of handling how messages are sent between objects. We are probably already familiar with the concept of the “single responsiblity principle”, or the idea that no method should be responsible for more than one thing. This same concept extends to other parts of our application as well. As we’ve learned through the process of refactoring, our controllers shouldn’t be responsible for the logic that really belongs in model. Similarly, a model shouldn’t be responsible for calling on a third-party service or performing some task or piece of logic that doesn’t really relate to its own state.
The way that we solve this in Ruby is by abstracting out logic into smaller components. We have service objects, which are responsible for carrying out tasks and therefore are easily-testable, and encapuslate a very specific piece of functionality that the rest of the application doesn’t really need to know about.
In Ruby, when we have two objects that are connected in some way — for example, a Dog
belongs_to
its Human
— and the state of the Human
changes, we probably want to notify the instance of the Dog
that the object is associated with. We could say that the Human
sends out a “message” to the objects that are “listening” to it. The real terms that we are trying to use here are publish and subscribe. An instance of a Human
object “publishes” events (i.e., the human wakes_up
, is_ready_to_play
, etc.), and the Dog
object listens and “subscribes” to these events (and probably behaves accordingly, aka it would jump_excitedly
when the human is_ready_to_play
).
Usually, for smaller applications, it’s fine to just rely on one object telling another to behave a certain way explicitly. But, things get kind of messy as you have more objects “listening” to the events of other objects. This is where our knowledge of service objects can come in handy. We can pretty easily abstract out units of work into service classes. But, this still means that we need to notify our service classes whenever they need to change; in other words, we have to tell our services Hey, you need to behave in a certain way because something about the object you’re associated with has changed!
The publish-subscribe pattern uses the exact same concept of sending messages between objects when something about one of the objects changes — however, it does this by using an intermediary object, sometimes called a message broker or an event bus. The important thing here is that the object that does the “publishing” or “broadcasting” of an event has no idea who is listening to its events. It just sends out a signal of sorts. The intermediary message broker object then is responsible for knowing who is “subscribed” to this event, and who needs to know about it. The message broker then makes sure that the correct object gets this message. In the simple example from above, a Human
might publish an event, and another object, such as a DogNotifer
, would be responsible for telling the Dog
instance that it needs to do something.
I really like the way that Ahmed Abdel Razzak explains this in his blog post:
“The publish-subscribe pattern is a Ruby on Rails messaging pattern where senders of messages (publishers), do not program the messages to be sent directly to specific receivers (subscribers). Instead, the programmer “publishes” messages (events), without any knowledge of any subscribers there may be. The pub-sub is a pattern used to communicate messages between different system components without these components knowing anything about each other’s identity.”
This concept can be a little tricky to understand in Ruby until you see all the classes in action. So let’s start publishing and subscribing!
There are a few different pub-sub gems out there, but the one that I’ve found the easiest to use is a gem called wisper
.
We’ll start the same way that we always do: by adding gem 'wisper'
to our Gemfile
, and then running the bundle
command.
Now, let’s take a look at one of our Ruby classes that we can implement the pub-sub pattern on. Here we have a PressReview
class, that is a representation of a book review that might generate a lot of press for an Author
in our bookstore app. These press reviews are pretty important (think the New York Times Bestseller List, etc.), so we want to notify the author of the book when the press review goes live. We also want to generate a tiny news snippet that will just have a few lines about the article once it has been created:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
The first thing that we’ll want to do to add the wisper
gem is to include the Wisper::Publisher
module into the class that is going to be broadcasting events. In this case, we want to broadcast an event when our PressReview
class has been successfully created and has gone “live”. Let’s create a message broker class called CreatePressReview
that will handle the broadcasting of this event. We will either need to include Wisper::Publisher
or alternatively, Wisper.publisher
:
1 2 3 |
|
Next, we’ll need to add the method that is going to be doing the “broadcasting” of the event. It’s pretty typical to use a call
method to do this. Inside of this broadcasting method, we’ll want to handle two different situations (think JavaScript promises): if our press_review
is created succesfully, or if it fails to be created:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
We’ll notice that this class takes a press_review_id
, and then contains the logic to set and check whether the press_review
we just found is live
or not. If it is live and we’re ready to notify our author and generate our news item, we’re calling the broadcast
method, and passing it the name of the function we want to execute, along with the press_review
instance. And if the press_review
isn’t live, we’re calling a different method isntead.
It’s worth noting that the broadcast
method is also aliased to publish
and announce
, so either of these lines would have also worked:
1 2 |
|
Before we add any listener objects that will subscribe to these events, let’s first abstract out those alert_author
and generate_news_item
private methods from our PressReview
class into services objects. Our alert_author
method can now be rewritten as a AuthorAlerter
Plain Old Ruby Class, which calls upon an AuthorMailer
:
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 |
|
And our generate_news_item
method can be refactored into a NewsItemGenerator
service class, that creates a new instance of a NewsItem
:
1 2 3 4 5 6 7 |
|
1 2 3 4 5 |
|
Now that we have our publishers in place, we need to make our service objects actually “listen” to these events.
Our event listeners will subscribe at runtime to their publishers, which means that they won’t be executed until the broadcast events are actually invoked.
We can make any object a listener that subscribes to broadcast events by calling the subscribe
method. So, inside of our controller, we could do something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
We’ll remember that it’s the CreatePressReview
intermediary event bus class that’s actually responsible for broadcasting our events now, not the callbacks in the PressReview
class like we had before! We’re making sure that our AuthorAlerter
and NewsItemGenerator
services are subscribed to the “sucess” and “failure” events of the call
method that is defined in our CreatePressReview
intermediary class. And it’s only when we invoke the call
method (in the last of this controller action) that we’re “broadcasting” our event. We’ve hooked up everything in such a way that the event bus class and the service objects will run the correct code if our press_review
instance actually goes live.
But we’re not limited to doing all of this inside of a controller action! If we wanted to do this directly from our Rails model itself, we could write some similar logic by specificing the methods we want to invoke if the PressReview
was created successfully:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
This rewrite has helped us divide our code into smaller, discrete classes that are easily-testable. In fact, we could use the wisper-rspec
gem to help us in stubbing out some tests!
The pub-sub pattern might not be for everyone, but it’s certainly interesting to read and learn about. Even you decide to never use it, at least you can say that you saw a really cute penguin do some serious subscribing at the end of this post:
wisper
gem is useful for implementing pub-sub in Ruby.wisper
gem has changed a bit over time, so there are a few good write-ups on how to implement it. Check one out here and here.No developer knows everything — even if they do know a whole lot more than you do. I was reminded of this fact recently while pairing with a more experienced programmer on a large Ember-Rails project that’s now coming to a close. We were right in the middle of adding some methods to a Rails model when we realized that we actually needed to change something about how one of our model’s ActiveRecord
associations worked.
What we wanted to do was rely upon a callback function executing every time an association was created or destroyed. But, we hit a little bit of a wall, since we quickly realized that this wasn’t as simple as we initially thought. The complication came with the fact that we were dealing with a has_many
relationship, which meant that we weren’t dealing with a single object, but rather a collection of objects. The developer I was pairing with explained that he knew that there were some methods that ActiveRecord
has to achieve what we wanted to do, but he wasn’t sure how they worked exactly, just that he had seen them before elsewhere.
After doing a little research on what resources ActiveRecord
provides when it comes to solving this problem in an elegant way, we eventually decided to go another route and use a different callback function. But in the process of pairing, we learned that there are some methods that exist in ActiveRecord
that can come in handy in this situation. If we hadn’t been on a tight deadline for the specific feature that we were building, we probably could have devoted more time to learning about these callbacks. So, I decided to come back to these callback functions and dig a little deeper. Interestingly, there really isn’t that much documentation on ActiveRecord
’s association callback methods, and nearly no blog posts. This is uncharted territory, my friends! Are you ready? I hope so.
Callback functions are everywhere, particularly when we’re inside the context of most Rails’ models. Our average ActiveRecord
callback will hook into the object life cycle of our ActiveRecord
instances, which allows us to work with our object at any given point during its lifespan. The most common use case for implementing a callback is executing logic before or after the alteration of an object’s state.
Here’s my personal list of my top callbacks (yes, I have a list):
after_commit
after_update
after_destroy
before_validation
before_save
They pretty much do exactly what you think they would do: they hook into the object at the point in it’s create, update, validate, save, or destroy “state”, and allow you to execute whatever functionality you might need. This is just the tip of the iceberg though: check out the whole list of ActiveRecord
callbacks that are free to use.
But let’s get back to association callbacks. What makes them different from that bunch of functions we just listed above? Well, there’s really one big difference in particular: association callbacks are similar to normal callbacks, but rather than hooking into the life cycle of a single object, they are triggered by the life cycle of a collection of objects. Unlike “single object” callbacks however, there are a limited number of a methods available for us to use. Actually, there’s exactly four association callbacks, to get specific:
before_add
after_add
before_remove
after_remove
There are two important things to note about how and when these callbacks are run:
First, callbacks like before_remove
and after_remove
will run before and after the delete
methods. In other words, when we call objects.delete
, the delete
method will invoke the before_remove
and after_remove
callbacks by default. Similarly, the destroy
method will destroy a collection of records and remove them from an association while calling the before_remove
and after_remove
functions.
Second, if any of the before_add
callbacks throws an exception and cannot create the association with a record in the collection, the object simply won’t be added to the collection. Similarly, if any of the objects passed to the before_remove
callback throws an exception, the object won’t be removed from the collection. This is pretty important to keep in mind for two reasons: if we want to make sure that objects are only added or removed from an association collection successfully, and want to throw an error of some sort if for some reason this is unsuccessful, this is a really good thing. But, if we want to be able to assume that an object can always be added or removed from a collection without fail, this is bad thing, because we can’t always be sure that this will happen.
With all these points in mind, there’s only one question left to ask: how do we implement these callbacks, exactly? Time to find out.
Implementing our association callback isn’t too complicated of a task. Since these four association callbacks can only be invoked on a has_many
or has_many, through:
collection association, our callbacks can be added onto the same line where this association is defined in our model. For example, let’s say that our Order
objects can have many Discount
s (apparently we’re feeling particularly generous this holiday season, and we’re going to allow many discounts rather than just one!). We can start off with a model that looks like this:
1 2 3 |
|
Whenever a discount
is added to an order
instance, we want to recalculate the total for our order, with the discount applied. We’ve added the callback to our association, and are passing our callback the name of the function (in this case, we’ve called it recalculate_total
) we want to be executed every single time a discount
is added to our “collection” of discounts on an order
.
Now, all we need to do is actually write the recalculate_total
method. Since we don’t want this method to be called in any context aside from this association callback, we’ll make it a private
method:
1 2 3 4 5 6 7 8 9 10 11 |
|
We can really pass as many methods to our callbacks as we want, in the form of symbols in an array. We can also pass a proc directly into this array as well, as explained by the Rails docs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Pretty interesting, right? Who knew that this even existed?! (Spoiler alert: me. I had no clue this was even a thing.) But how does this even happen? Where is this defined, and how does it work? Let’s dig one level deeper and dive into my favorite place: the Rails source code.
I think one of the reasons that association callbacks aren’t as well-known or written about is because they live in an odd place. In fact, they are defined inside of ActiveRecord
’s Associations::Builder::CollectionAssociation
(wow, what a mouthful!) class, which doesn’t actually have any documentation at all! No wonder this is Rails best-kept secret! This class is actually inherited by the has_many
and has_many_belongs_to_many
association classes, while the CollectionAssociation
class itself inherits from the Association
class.
I’m still not completely sure what’s going on behind the scenes here, but from the source code it appears as though the association callbacks (namely before_add
, after_add
, before_remove
, and after_remove
to be exact) are all defined as an array of symbols, which is set to a CALLBACKS
constant, which is used throughout the class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
So, if this is where our association callbacks are defined, where are they being invoked? I’m glad you asked. It turns out, they’re used most often inside of ActiveRecord
’s Associations::CollectionAssociation
module, which contains methods that we use all the time on our ActiveRecord
objects — perhaps without even realizing it! Our association callbacks are passed as arguments and then implemented by the callback method in CollectionAssociation
module.
We can actually see our callbacks in action inside of a private
method called remove_records
, which is defined within this very same module. Here’s what that method looks like:
1 2 3 4 5 6 7 8 |
|
Nice! There’s our after_remove
callback, being called on each of our records
that’s being passed into it. We might not even realize it, but the remove_records
method is called upon by the delete_or_destroy
method (another private
method in this module), which is invoked by both of ActiveRecord
’s commonly-used delete
and destroy
methods! This is exactly how we can confirm what we learned earlier about our before_remove
and after_remove
callbacks. It’s not magic — it’s just code that’s hiding from us! Except now we know how to call upon our callbacks, so we can say that we are strangers no more.
ActiveRecord
’s normal callbacks, except that they hook into the life cycle of a collection of objects (has_many)
, rather than just a single object (has_one
).ActiveRecord
associations? Head over to the module documentation for associations.destroy
and delete
methods? Dive into the source code! Check out the delete and destroy method signatures.This blog post is part of a series on strong parameters. Read Part 1 here.
Rails often feels like a black box, with all of the complex logic abstracted away and hidden from view. This leaves behind a clean, convention-abiding framework where form follows function. But another, perhaps less-intentional side effect of all the “metaprogramming away” of this framework’s complexities is a frequent lack on clarity of what’s going on behind the scenes.
In my year of working with Rails, I’ve come to appreciate and respect so many things about it. In fact, I think that there’s something incredibly approachable about Ruby as one’s first programming language, with Rails as its corresponding framework. And of course, there’s something truly unique and welcoming about the Ruby and Rails programming community. All of these factors combined make it so easy for beginners of such different backgrounds to start building applications very quickly.
However, once you get past the intial stage of building applications with the basic CRUD operations, or if you’re trying to build something a bit more complex with added functionality, or trying to integrate with another framework, you eventually hit a wall where you realize that that you’re not completely sure how something works. This can be a hard wall to climb over, especially given the fact that you can start building things very quickly with Rails. Some people have heavily critiqued this aspect of the framework, arguing that it’s detrimential to abstract away so much of what’s actually going on, which makes it difficult for people to understand what their code is truly doing under the hood. I’ve peronally encountered this “wall of abstraction” a few different times, but each time I found some piece of logic that worked differently than I thought it would, it only lead me to learn something new about the framework. Most recently, that lead me down a wild goose chase into the source code for ActionController::Parameters
— a class that I didn’t even know existed!
There’s a well-known saying that Rubyists often attribute to duck typing: if it looks like a duck, and quacks like a duck, it probably is a duck. In other words, if an object behaves like another object, it doesn’t matter that it’s of a certain class or “type” (or species!) of another object, just so long as it can respond to the correct method calls to implement the behavior of that object.
This saying actually comes from a concept referred to as the “duck test”, which is a form of abductive reasoning, which is based on the idea that one can identify an unknown object by observing its habitual characteristics. However, this can be a little bit tricky because sometimes, just because something quacks like a duck and waddles like a duck doesn’t mean that we should stop questioning what it actually is and just assume that it’s a duck!
Let me explain with an example. Whenever we send or receive data from the server, it appears that everything is being sent as a Hash
. If we look at our GET
requests or POST
and PUT
requests using HTTP protocol, our data usually looks like some variation on a theme of something like the following:
1 2 3 4 5 6 |
|
If it acts like a hash, and quacks like a hash, it must be a hash, right? Well, not exactly. Last week we learned that params
in our controllers are actually instances of ActionController::Parameters
. But this data that we’re sending back and forth still looks like its a plain old Ruby Hash
. It also seems to behave like a hash, right? We can do something like this
1 2 3 |
|
and access a key in this so-called “hash” the same way we would with any other Hash
data structure. So, what’s different about ActionController::Parameters
?
Well, let’s find out. We’ll start by opening up the source code for this class, which lives inside of the ActionController
module. The first thing we’ll notice is this:
1 2 3 4 |
|
Interesting! The Parameters
class subclasses from ActiveSupport::HashWithIndifferentAccess
. If we were really curious about what type of object this class inherits from, we could trace that back to see that HashWithIndifferentAccess
simply inherits from the class Hash
. So, what makes HashWithIndifferentAccess
different from plain old Ruby hashes?
Well, the Rails guides answers this question pretty well:
HashWithIndifferentAccess
implements a hash where keys:foo
and"foo"
are considered to be the same. Internally symbols are mapped to strings when used as keys in the entire writing interface. You are guaranteed that the key is returned as a string. This class is intended for use cases where strings or symbols are the expected keys and it is convenient to understand both as the same. For example theparams
hash in Ruby on Rails.
Awesome, this answers our question and more! This subclass gives us the flexibility to access the keys in a params
“hash” by either a string or a symbol. The HashWithIndifferentAccess
class still responds to the majority of the same methods that a Ruby Hash
instance does, but with some added functionality, which can be especially handy if we’re dealing with JSON responses.
Protip: we can easily create HashWithIndifferentAccess
instances by creating a Ruby Hash
instance and calling with_indifferent_access
on it. This method is available to us since core extensions has the with_indifferent_access
method defined on the Hash
class by default:
1 2 3 4 5 6 7 |
|
So, parameters aren’t quite a hash, but they quack pretty much exactly like how a hash would quack. But there must be a good reason why they are different classes, right? Let’s investigate further.
On a very basic level, ActionController::Parameters
could be simplified to hashes with some serious restrictions and permissions. Because ActionController::Parameters
inherits from ActiveSupport::HashWithIndifferentAccess
, we can fetch values from our params “hash” using a symbol :key
or a string "key"
. But there are a few things that we can’t do so easily, and that’s where the functionality of ActionController::Parameters
really starts to come into play and begins to make a lot more sense.
We can easily create a new instance of ActionController::Parameters
. In fact, we do it within the context of our controllers all the time!
1 2 3 4 5 6 7 |
|
Except usually we wrap it in a _params
suffixed method like this:
1 2 3 |
|
Here is one example of the added functionality of this class. When we create a new instance of a ActionController::Parameters
class, it is by default, not permitted.
1 2 3 4 |
|
The permitted?
method actually doesn’t do anything more than return an attribute on an instance of a ActionController::Parameters
object, called @permitted
:
1 2 3 |
|
So the question is, where does this attribute get set? Well, there are two places that can set this attribute to true
. The first place is a method that we’re already familiar with: the permit
method! As we learned last week, this method calls params.permit!
as its last line, after it filters out any paramters that aren’t permitted scalar values (think Symbol
, String
, or Hash
). However, we can also just call permit!
on an instance of ActionController::Parameters
ourselves.
1 2 3 4 5 6 7 |
|
The permit!
method sets the @permitted
attribute to true
, and returns self
, which in this case is just the instance of the params class. This method is quite useful for mass assignment, since it effectively removes the need to list all the permitted values. It can be handy in a controller that is used only by admins that should have control over — and can be trusted with — updating all attributes of an object:
1 2 3 4 5 6 7 8 9 |
|
However, this doesn’t really make sense to use unless you are sure that you want to allow all the values to the params hash to be whitelisted. Proceed with caution!
Now that we know a little bit more about ActionController::Parameters
and what kinds of ducks — oops, I mean objects — they really are, there’s one question that we probably still have floating around in our heads: where on earth does our params come from during the request-response cycle…and how does it get set on a controller?
To answer this question, we must trace back how a parameter comes in from a request, and then how it is set on a controller. It isn’t magic (even though it seems like that’s the case!). In reality, it’s actually happening in a cool place called ActionController::Metal
. Yes, that’s a thing, and it happens to be the very class that ActionController::Base
inherits from. By default, we should always inherit from ActionController::Base
, because it gives us a ton of functionality and modules that help speed things up.
But even ActionController::Base
has to come from somewhere, right? And that somewhere happens to be ActionController::Metal
, which is the simplest possible controller that we can create in Rails, which provides little more than a Rack interface. Here’s a very, very simplified version of what that class looks like in the Rails source code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
As a request goes out or a response comes in, these values are set as instances on the controller itself! So if there was any doubt in your mind, everything in Ruby is an object — even controllers are just objects with instance variables and attr_readers and attr_accessors.
So, where do our parameters get set? Well, they also live in an instance attribute called @_params
, which is set by a params method. The parameters come in from a request, and are beautifully memoized in a method that looks like this:
1 2 3 |
|
Pretty amazing, right? That black box of ActionController
and strong parameters doesn’t seem so intimiating any more, does it?
It’s a little strange that we always talk about and use params.require
and the permit
method so often in Rails, particularly when we are first starting out, but we don’t necessarily question where it comes from! Or how it is set or being used, for that matter! But now we know. And we’ll never mistake our strong params for a simple Ruby hash again.
Or a duck, for that matter.
I recently learned that there’s a significant change coming to ActionController::Parameters
with the soon-to-be-released Rails 5! Namely, another Rubyist brought this to my attention over the interwebz:
@ThePracticalDev Nice post! Just a friendly change advisory, AC::Parameters composes an object and no longer inherits from HWIA in Rails 5.
— Jon Atack (@jonatack) December 1, 2015
It turns out that ActionController::Parameters
will soon return an object, rather than a Hash
instance, which also means that it will no longer Hash will no longer inherit from ActiveSupport::HashWithIndifferentAccess
as this post explains. Check out this great blog post by Eileen Uchitelle, a developer at Basecamp, to learn more about how ActionController::Parameters
will be changing with the next release of Rails.
ActionController::Parameters
behaves a lot like a hash that can be accessed with either symbol or string keys. This class has some added methods like permitted?
and permit!
which check and set the @permitted
instance attribute on a params object.ActionController::Metal
? Head over to the Rails docs to learn more and read this helpful StackOverflow post.When you write code every day for a living, it’s easy to get hyper-focused on building out new features and getting things done quickly. What’s much harder is to take a step back and figure out exactly how something is working. Of course, sometimes this happens inherently and without any effort on your part — say for example, when you’re fixing a bug or need to integrate with a third-party service and are forced to understand what’s happening on a more granular level. But generally speaking, that is less common when you’re working a within a framework that you’re already comfortable with and use daily, without giving it a second thought.
I had one of those “take a step back and question everything” kind of moments recently. I was writing a controller for the admin interface of a Rails application, and hit a roadblock. To be clear, there wasn’t anything super complex about the controller I was writing; it had the basic CRUD actions that any controller does, and I had written controllers like it plenty of times before. Yet somehow, when I got to writing the params
private method for this controller, I couldn’t remember what methods I needed to use. I was super tempted to open up another controller and just copy and paste the strong parameters from one file into another. But I realized that this wasn’t really going to help me at all. What I really needed to do was grasp how strong parameters worked on a more conceptual level. If I could understand why we use the methods that we use, and to what end, I would never need to even look up the documentation for whitelisting parameters ever again!
So that’s exactly what I did. I decided to peek under the hood of Rails’ ActionController
, and set my mind to learning everything there was the know about strong parameters. Spoiler alert: I didn’t completely succeed, and I definitely don’t know everything about whitelisting parameters. But what I did finally come to understand was why we use the methods that we do (think require
and permit
), and why we invoke them in that order. And hopefully I’ll be able to explain how some that black box magic in Rails actually works!
When we’re first introduced to the Rails framework, there are some fairly basic components that we learn about, including the MVC structure, which stands for Model, View, Controller. Personally, I found models and views to be far easier to grasp than controllers. Controllers were a whole other beast entirely. In fact, one of the very first concepts that I struggled with was the very basics of writing a controller action! I eventually got a better at that, and now for our bookstore application, I have a more sophisticated controller (in this case, for our Order
objects), which looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
Nice! We’re using our new memoization technique, and we’re rendering json responses to make it much easier to integrate with a JavaScript frontend; of course, we could have also just rendered our @order
instance if this were a simple Rails application with no frontend framework. But…there’s one thing that we’re still missing, and clearly put off because I was dreading it: our strong parameters!
The ActionController
strong parameters module was introduced back in 2012 with the release of Rails 4. The idea behind strong params was to abstract out the creation of models via mass assignment into the controller, rather than in the context of a model. Prior to this feature, we used to need to whitelist attributes in our models using attr_accessible
1 2 3 |
|
in order to use mass assignment to instantiate an object from our controller actions:
1 2 3 4 5 |
|
Not the best solution, right? Enter our knight in shining armor: strong_parameters
, a gem that the Rails core team released to fix this problem, which was eventually merged into Rails. Okay, let me rephrase that: our rather misunderstood knight in shining armor.
In order to comprehend how strong params permits attributes, there are two essential methods we are required to understand.
The main reason for even needing strong parameters of any sort is to ensure that we’re only passing safe, protected data from our user-accesible interface. We don’t really expect most users to try to pass in malicious data, but it’s always a possibility. Moreover, there are various situations (dealing with money, for example, or people’s personal information) when delicate information must be passed around securely across the web.
So, how can we ensure that only the correct data is being passed through, and that too in a safe way? The Rails solution to this problem is to whitelist a set of attributes that should be allowed to be modified and passed through by a user (regardless of whether the role of the user is that of a guest, admin, etc.).
The first step to whitelisting any set of attributes is making sure that the parameter we are looking to “whitelist” is actually present. If we think about it, this is pretty logical: how can we pass in the correct attributes to create or update an object if don’t first check that we have the parameter that contains the attributes we need? Only once we ensure that a parameter exists can we begin to strip away the “blacklisted” attributes.
In fact, that’s exactly what this method does under the hood. If we peek into the source code for this method, this is what we’ll find:
1 2 3 4 5 6 7 8 |
|
At this point, we should be wondering what self
is in the context of this method. In other words, what object responds to this require
method? And what is this ParameterMissing
error, exactly? Let’s take a look at the require
method documentation to find out:
require
ensures that a parameter is present. If it’s present, returns the parameter at the given key, otherwise raises an ActionController::ParameterMissing error.
Okay, so now we know that the error being raised in the conditional is actually an ActionController::ParameterMissing
error. One question answered. But what does require
get invoked on? Well, it turns out that the answer to that is a new instance of an ActionController::Parameters
object!
There’s a great StackOverflow answer that points this fact pretty explicitly. The params
object that we refer to in the context of our controllers gets treated as though it’s just an instance of a Ruby Hash
. But in actuality, it’s an instance of something called ActionController::Parameters
, which is the object that responds to the require
method. But more on that a little bit later.
For now, all that matters is that the require
method returns a new instance of an ActionController::Parameters
object for the key that is passed into it. If that key doesn’t exist in the object, it throws an error. What does this mean, exactly? Well, when we write our order_params
method in our OrdersController
, it will begin like this:
1 2 3 |
|
We’re actually returning the value of the parameter at the key that we’re requiring (in our case, order
):
1 2 3 4 |
|
And what’s more: we’re creating a new instance of an ActionController::Parameters
object whenever we invoke params
in our controller! Okay, so that’s the first step: making sure our parameter exists. The second requires a bit more…permission on our part.
Now that we’re sure that our parameter exists, we need to actually permit the correct attributes on our objects. Since our users can add more books to their cart while they’re shopping, they should be able to update the total
of their Order
. However, the number
on their order is unique (and probably has an index on it), and is generated on the backend when it’s created. We definitely don’t want them to be able to update or modify that value at any point!
So, we need to permit
a single attribute on our required parameter key. That means that our whitelisted params now look like this:
1 2 3 |
|
So what’s happening here? Well, the permit
method also is defined on the ActionController::Parameters
class. It returns a new ActionController::Parameters
instance, which includes only the given filters — the arguments that we’re passing in here as symbols — and sets an attribute using a protected instance method called @permitted
on the newly-created ActionController::Parameters
to be true
.
This means that if we invoke permit
on our required parameters, we’ll return the actual hash, not the value for the parameter
1 2 3 4 |
|
Wait, but how does this happen? Well, if we look at the source code, we’ll see that the permit method takes an array of arguments named filters
, and then iterates through them to check what type of object they are:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
The reason for the case
statement here is to handle nested attributes, which might look like this:
1 2 3 4 5 6 7 8 |
|
So if we really only need these two methods to require a parameter key and then permit the correct key and value pairs inside of it, what’s the need for having a seperate method? Why do we need to encapsulate this logic? We could very well just do something like this, right? And it would work:
1 2 3 4 5 |
|
It turns out that abstracting our strong params out into a private order_params
method is just a good practice that was established by the Rails core team. The Rails guides explain this pretty well:
Using a private method to encapsulate the permissible parameters is just a good pattern since you’ll be able to reuse the same permit list between create and update. Also, you can specialize this method with per-user checking of permissible attributes.
Another reason for having a separate method is because things can get kind of tricky once you need to permit nested attributes. At that point, it’s especially important to understand how these methods work.
Tune in next week, when I’ll continue this deep dive by exploring the ActionController::Parameters
class and answer the super confusing question of where params get instantiated (no really…where?), and what makes a parameter different from a hash (no really, I promise that they’re different!). Until then, keep peeking into that source code and stay afloat like this guy:
require
method ensures that a parameter key is present, and throws an error of it doesn’t exist. The permit
method filters out the keys that we want to whitelist based on the filters (which we pass in as symbols) that are passed into it.ActionController::Parameters
in the Rails guides.A couple of months ago, I wrote a blog post on some basic Ruby keywords including begin
, end
, rescue
, and ensure
. A few days after publishing said post, another Rubyist friend of mine sent me a message telling me to read about memoization. “You basically describe memoization in your post without ever explicitly explaining it,” she had said. At the time, I had added it to my ever-growing list of “things to learn more about”, but promptly forgot to make the time to learn about the concept.
Cut to last week, when I was trying to write a controller action that had to do something a bit more complex than simply render a JSON-formatted response of a given resource. So, I started off by implementing a begin
end
block to execute a bunch of code that needed to run on it’s own. I remembered writing about how to use these two keywords, so I pulled up my post and was suddenly reminded of…memoization. It turned out that I actually needed to use memoization in this controller action, and had already been using it elsewhere in the very same project! But, I still didn’t understand what it was, or in what way I had been using it so far.
After putting it off for months, it was finally time to learn about this memoization business. For those of us (myself included!) who haven’t quite gotten the memo on memoization, here’s the brief lowdown: the term dates back to the year 1968, when it was coined by Donald Michie, a British artificial intelligence researcher who worked alongside Alan Turing at the Code and Cypher School at Bletchley Park during WWII. The basic idea of a memoization function is that it can “remember” the result that corresponds to a set of given inputs. In other words, it can store the results of an expensive function call by “saving” the result such that when you call the same function again with the same parameters, you don’t need to rerun the function. In the context of computer science specifically, this is a kind of optimization technique that is used to make programs more efficient and much faster. There are a few different ways that memoization pops up in Ruby and Rails, which is exactly what we’ll need to learn about next!
There are effectively two types of memoization when it comes to Rails applications: simple, single-line memoization, and the more complex form found in multiple-line memoization. They still are the same concept and we can implement them using the same conditional operator; the fundamental difference between the two types hinges upon how much logic needs to be run for the object that we’re trying to “remember”, or in other words, memoize.
Let’s start with a simple memoization example. In our bookstore application, we have a piece of functionality that allows users to write reviews for books that they have purchased. Currently however, our ReviewsController
doesn’t account for that functionality. It only has a simple index
action that is currently rendering all the Reviews
that have been published
:
1 2 3 4 5 |
|
The published
method that we’re chaining on here is just a simple scope that we learned about last week, and added on to our Review
model:
1 2 3 4 5 6 |
|
We can implement some simple memoization by abstracting out what’s currently happening in the index
action of our ReviewsController
. Since memoization roughly translates to the concept of “remembering” the return value of a function without having to call it again, we could use Ruby’s instance variable to store the return value of an expensive function call. In our case, the function that we’re calling and saving to our instance variable is the published
scope on our Review
class:
1 2 3 4 5 6 7 8 9 10 |
|
Now our index
action is calling the private reviews
method, which is “remembering”, or essentially assigning and saving the return value of Review.published
to the instance variable @reviews
. Right now it doesn’t look like much, but this could help keep our code clean as we continue to build out this controller.
The tricky thing to keep in mind with controllers is that they are nothing more than Ruby classes. This is important to remember because this instance variable will exist for the lifespan of a single request; if we make a network call (probably a GET
request) when we query the index
endpoint of our ReviewsController
, the @reviews
instance variable will be assigned and exist for the duration of that request. Once that request has completed, that instance of the controller is no longer needed and a new one would be created. Right now, we’re not doing very much in our existing codebase with this piece of functionality. But why might that be important? Let’s find out.
Imagine that the index
action of our ReviewsController
needs to be rewritten to account for a new piece of functionality. Instead of merely loading all of our published
book reviews, we now want to be able to account for some query params. For example, if a user navigated to a route such as /the-sound-and-fury/reviews
, they should be able to see all the published books reviews for that specific book, based on the book slug that is used in the URL. We immediately know that we need to change our reviews
method. But it’s not going to be as simple as just chaining on another method; we have a bit more complicated logic going on here.
First, we’ll need to check whether there’s a book_slug
parameter being passed in. If there is, we’ll need to query for the correct book reviews based on that query param. If there is no parameter being passed in, we’ll just want to return our published
Reviews. To account for this new feature, our method may now look something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Here, we’re implementing the multiple-line form of memoization, which calls for the use of our favorite Ruby keywords, begin
and end
. We’re first setting a local _reviews
variable to all the published
reviews; if there’s a book_slug
query parameter being passed in for this GET
request, we’re modifying this variable to select only the published reviews that have a book_slug
attribute that matches the query param that was passed in. Ultimately, we’re returning our _reviews
variable, which will either be just an array of all the published reviews, or the published reviews that match our query parameter.
We don’t necessarily have to use a variable name prepended with an _
underscore, but I’ve seen other developers do this in their code and I’ve come to realize that this can be one way of denoting to other developers that this variable is being modified but not explicitly used. It can be a way of indicating that this variable is only necessary to assign the instance variable @reviews
, and is never called or referenced outside of our begin
end
code block. We should also note that our index
action hasn’t changed one bit. All of our modified logic still lives in the same method, and is still accessible from our @reviews
instance variable, from any action within this controller.
Sometimes, the begin
end
block for multiple-line memoization is simply used because all of the code won’t fit on a single line. The begin
end
block ensures that the code will be executed together in a single chunk, which effectively encapuslates the block of code in the same way, as though it were written on a single line, but makes it look much prettier and far easier to read.
In order to really understand what’s going on with memoization, it’s important to identify the behind the scenes action of Ruby’s “or equals” (sometimes referred to as the “double pipe”) operator: ||=
.
When I first learned about this operator, I initially thought that it functioned by telling the Ruby interpreter something equivalent to, Hey, if a value for this variable already exists, please return that. Otherwise, if this variable doesn’t have a value yet, assign it to whatever block of code comes next. But apparently, that’s not exactly what’s going on here. In actuality, this operator is far more nuanced that most people may initially think it to be. Peter Cooper’s Ruby Inside blog post does a fantastic job of unpacking all the different edge cases of the or equals operator, including the various scenarios when it can be a bit problematic. I really like the way that he summarizes the misconception behind the “or equals” operator quite simply as follows:
A common misconception is that
a ||= b
is equivalent toa = a || b
, but it behaves likea || a = b
. Ina = a || b
,a
is set to something by the statement on every run, whereas witha || a = b
,a
is only set ifa
is logically false (i.e. if it’snil
orfalse
) because||
is ‘short circuiting’. That is, if the left hand side of the||
comparison is true, there’s no need to check the right hand side.
In other words, what he’s saying here is that when we write something like this:
1
|
|
what we’re actually doing is saying something along these lines to the Ruby interpreter: If @reviews
currently evaluates to false
, then set it to the the return value of Review.find(params[:id])
. But, if @reviews
is not a falsey value, don’t assign or set the variable to anything. Just stop running and exit out of the method.
It’s also worth bringing up the fact that both nil
and false
are “falsey” values, which means that if @review
was nil
and empty when this line runs, the method would not short circuit, and would continue to execute after the ||=
operator, thereby assigning the @review
instance variable during method execution. This is significant if you are integrating with an external API where you can’t be sure if your instance variable will be falsey or not:
1 2 3 4 5 6 7 8 9 |
|
In this case, if our API endpoint that we’re querying happens to return nil
for a set of reviews or for a particular book that may have no reviews, every single place that we’re calling this method will be running the logic inside of the begin
end
block. This pretty much makes our idea of “memoizing” the result of this expensive query a moot point, because we’re not “remembering” the return value, but instead just running that line of code again and again. We could fix this by writing a less beautiful but more flexible method like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
This isn’t as big of an issue if we’re using an ActiveRecord
method or a scope, which would return an empty array []
, and not nil
. But it’s important to keep the memoization of falsey values in mind, since we could very easily be making a lot more queries to our database than we might realize.
Finally, there’s another tricky situation when it comes to memoizing a method that accepts an argument. Justin Weiss’ blog post explains how to get around this by using the Ruby Hash
initializer method (Hash.new
), which ensures that the only time a block will be executed is if we try to access a key that doesn’t yet have a value assigned to it in the context of our hash. This can be a little hard to understand at first, but is pretty useful for more complex forms of method memoization.
Memoization has clearly been around for a long time in the computer science world, but interestingly, it’s had a bit of a rocky history in Railsland. It turns out that there actually used to be an entire ActiveSupport::Memoizable
module back in an older version of Rails 3! Apparently, there was a lot of controversy surrounding that particular module, and it was deprecated and, eventually, completely removed in 2011.
At the time of deprecation, the Rails core team encouraged everyone to use the ||=
“or equals” operator format of method memoization, and what’s really cool about this is that you can actually see examples of how the core team members changed the code in the exact commit where the Memoizable module was removed. Here’s one example in the Rails source code of method memoization in the DateTimeSelector
class:
1 2 3 4 5 6 7 |
|
Pretty cool, right!?
Of course, some Rubyists were not a big fan of this commit and module deprecation. In fact, some developers have fought to keep the module alive in the form of gems! The two that are the most popular are the memoizable
gem as well as the memoist
gem. Both of them ultimately allow us to write a memoizable method like this:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Effectively, this continues what the ActiveSupport::Memoizable
module used to allow. In the method above, calling card_last_4
on an instance of an Order
class would only be calculated once, and would be memoized from that point on.
I haven’t used either of these gems because I personally would prefer to follow Rails conventions. But, I plan on playing around with them a bit in order to try and understand why it was deprecated, and why it implemented in the first place. Of course, we could also read the entire Github discussion that took place at the time of deprecation, but that’s a whole lot of comments to read.
No matter what form of method memoization we choose to use, there are certain times when it makes a lot of sense and is clearly the right tool for the job. Anytime we find ourselves making repeated database queries, or time-consuming expensive calculations, or repeated calculations that are never really going to chance for an instance of a class or a controller, memoization using Ruby’s ||=
operator is probably our best bet. And now that we know the theory and history behind Ruby method memoization, we’ll never forget!
I hope.
||=
, which assigns a value and executes the following line of code only if the variable being assigned is not falsey (i.e. not nil
or false
).Over the past forty or so Tuesdays — has it really been that many?! — I’ve written on a spread of topics. There’s a slight problem with this: sometimes I forget what I have and haven’t written about. Here’s a case in point for you: last week, I wrote about finder objects, and casually tossed in some scopes into my models. It turns out, I’ve never actually written about how scopes work, or what they really do!
I know, I know, that’s pretty terrible of me. I actually learned about scopes awhile ago, and now I use them fairly often in my applications. However, I got so used to writing them, that I never really thought that much about how they work behind the scenes. In fact, when I sat down to write this post, I had to go on a hunt into the Rails source code and Ruby blogosphere to figure out what was going on under the hood every single time I implemented a scope in my code.
The main reason that I like to use ActiveRecord scopes is because they allow us to specify commonly-used queries, but encapsulate these queries into methods, which we can then call on our models or association objects. However, my hunt lead me to find out that scopes have been around for awhile in Railsland, so they’re not exactly that new. But, what’s interesting about them is how their implementation has changed and grown with different releases of Rails. There’s also a lot of debate over how and when scopes are different from their counterparts, or simpler class methods. But what makes a scope exactly? Well, it’s finally time for us to hunt down the answer to that question.
While developing applications, we often run into a situation where we want to select a particular group of objects (read: rows from our database) based on the characteristics that they share. The basic implementation of scopes can be summed up as this simple idea: being able to narrow down the objects that we want into a specific subset, based on some given parameters. We can tell ActiveRecord
(an Object Relational Mapper, or ORM) to select a certain group of objects by implementing a scope that is specific to a model. Luckily, scopes aren’t too difficult to define, and mostly adhere to a simple structure.
In our bookstore app for example, we have a Review
object, that we allow our users to write about the Book
s that they purchase through our store. For now, our Review
s belong to a User
, and they have some basic attributes which map to columns in our database, including a published_at
datetime attribute, that we set when our User clicks the submit button, which saves their “drafted” review and turns it into a “published” review.
However, one side effect of having this attribute (and effectively, two different states or “types” of reviews) is that we now have no obvious form of selecting only our “published” reviews — that is to say, reviews that have a published_at
date attribute set on them. How can we fix this? Well, we can write a class method that, when invoked, will run a query on our ActiveRecord
object and only return the reviews that have this attribute. If we did that, our model might look something like this:
1 2 3 4 5 6 7 |
|
Okay, that’s a good start. Remember that the implicit self
in the body of this class method is our Review
class, so we’re basically running Review.where('published_at IS NOT NULL')
. But now we run into another problem: this query isn’t all that specific, is it? What makes a published
review, exactly? Well, it’s not just the fact that the published_at
date should be set; we also need to account for the fact that some reviews could be set to be published in the future, at a later date. What we really want to select are our reviews that have a published_at
date that has already happened; in other words, a date which occurred in the past. We can modify our class method to account for this:
1 2 3 4 5 6 7 8 |
|
If we try out this class method, we can see the exact SQL that gets executed:
1 2 3 4 5 6 |
|
However, instead of writing this functionality into the body of a class method, we could accomplish the exact same thing by using a scope:
1 2 3 4 5 6 7 8 |
|
which allows us to invoke a method in the console that pretty much looks like the method we had before:
1 2 3 4 5 6 |
|
Okay, wait — what’s going on here?! How did that even happen? Well, let’s break it down:
scope
method. This class method is defined within the ActiveRecord::Scoping::Named
module.scope
class method requires two important arguments: a name for the scope, and a callable object that includes a query criteria. That last part about passing a callable object is pretty important, because only procs and lambdas are callable objects. In fact, that -> {}
syntax that we’re using is just another way of writing a lambda in Ruby.ActiveRecord::Relation
object. This is significant because ActiveRecord::Relation
objects are not eagerly-loaded — they’re lazily-loaded. Lazy-loading basically means that we’re never going to query to the database until we actually need to. What makes this really awesome is that lazy-loading allows us to call more methods (read: scopes galore!) on our returned ActiveRecord::Relation
object.It looks like perhaps there’s some funky stuff going on here. But, all of these things still don’t really answer our burning question: why use a scope when we could just write a class method?!
What’s in a scope? A class method by any other name would smell just as sweet! Oops, I got carried away there. Enough poetry, let’s talk prose. Or scopes, rather, and why we might want to use them.
We want to change the implementation of our published
class method such that it accepts an argument that makes our query more flexible. Let’s say that we want to be able to filter our Review
s by a specific publication date. We might now have a class method that looks like this:
1 2 3 4 5 6 7 8 |
|
The on
parameter would ideally be a Date
or a Datetime
object that would dynamically change the rows that we’ll query for in our database. This will behave exactly like we want it to, until…it breaks. How can we break this? Well, let’s say that we now want to order our published reviews by their position
attribute, which for the time being, is just an integer. No problem, we can do that, right?
1 2 3 4 5 6 7 8 9 10 |
|
Sure, no problem! This returns exactly what we’d expect. But what if we’re relying on this method elsewhere and somehow don’t pass in a parameter to our published
method. What happens then?
1 2 |
|
BOOM! Everything broke. Oops. What happened here? We tried to call the order
method on a falsy object (aka nil
). Obviously Ruby is unhappy, because it looks like Review.published(nil)
returns nil
, which doesn’t respond to a method called order
!
Now, let’s go fast forward to our new scope implementation in the Review class:
1 2 3 4 5 6 7 8 |
|
We’ve changed our callable object to accept a parameter, which is how we’re going to determine our published_at
date. We can be pretty certain that this will execute the same query if we pass an actual date to this scope. But what if we pass nil
again?
1 2 3 4 5 6 7 8 9 10 11 |
|
Well, would you look at that! It didn’t break! It ran our expected query, but because scopes return ActiveRecord::Relation
objects, it didn’t call order
on nil
, it just kept chaining on to our query. The first part of our query (responsible for finding any reviews that were published on a date) didn’t return anything, but the second part of our query (responsible for just ordering whatever got returned by our first query) did work! How, exactly? Well, it just so happens that calling a method on a blank ActiveRecord::Relation
object returns that same relation. An important thing to note: if we had a query that was scoping down our reviews to ones that were published on a date and ordering those objects by their position, we would have gotten an empty relation:
1 2 3 4 |
|
The above query narrows down our scope quite a bit, which we could do if we wanted to specify that to SQL. But in our case, our ORDER BY
clause isn’t grouped inside of the AND
, but instead exists outside of it, which is why we’re not getting an empty relation returned to us.
While we’re on the topic of relations, it’s also important to note that the method we have right now does not return an object to us! Relations are not objects! We’d need to explicitly query for a record if we wanted to return it:
1 2 3 4 5 |
|
Hopefully we should now be able to easily see that the order
method that we’re chaining on right there at the end could really be abstracted into its own scope! Let’s fix that, shall we?
1 2 3 4 5 6 7 8 9 10 |
|
Much better. Now we can just chain on our order
scope to our published
scope without ever having to worry that our scopes will break. But wait, there’s even more we can do with scopes!
Because scopes accept lambdas and procs, we can pass in different arguments. We did that before when we passed in a datetime parameter. But this kind of flexibility can be especially powerful, because we can do things like pass in limits:
1 2 3 4 5 6 |
|
This will run our same SQL query, but will add LIMIT 10
to the end of it. We can customize this scope further, or we can add more if we need to. We also might want to just perpetually apply a scope to all queries on a specific model. When we run into this situation, we can use the default_scope
method.
1 2 3 |
|
This will automatically append all of our SQL queries on this model with ORDER BY "review"."position" DESC
. What’s really nice about having a default scope is that we don’t need to write and perpetually call a method named something like by_published_date
on this model; it will be applied and invoked by default on all instances of this class.
According to the documentation, if we want to get super fancy with our default scope and have so much logic that it’s bursting from our callable object’s so-called seams, we can also define it in an alternate way as a class method:
1 2 3 4 5 6 7 8 |
|
We’re also not limited to just using the where
method! We can use plenty of other ActiveRecord::Relation
methods, such as joins
or includes
, which will eager load other relations when we want to. Here’s a handy scope we could add to our Shipment
model that we built out last week:
1 2 3 |
|
This is pretty cool because we’re using our default_scope
method to automatically eager-load our associated order
and line_items
on our shipment
without having to make two additional queries just to load them! As is the case with includes
, it might not always be a good idea to do this, since we could be loading more records than we want, or could get stuck with a n+1 situation on our hands. But if we know what we’re doing and are sure that this scope is necessary, it can be pretty powerful.
We can also merge two scopes together, which effectively allows us to mix and match different WHERE
conditions and group them together in SQL with an AND
:
1 2 3 4 |
|
which we can then merge into a single SQL query by chaining our scopes together:
1 2 3 4 |
|
We’ll notice that in this situation, our WHERE
clauses are grouped together with an AND
, which can help us when it comes to writing super specific queries.
ActiveRecord::Relation
object, which makes them forever chainable!scope
method actually work? I’m not sure that I understand all of it, but perhaps you will! Check it out in the Rails source code!Most developers aren’t ever completely happy with their code. I’m no exception to this stereotype — I almost always know that I could probably write a cleaner, more concise method, controller, or class. Usually, it’s a matter of not know the best tool to reach for to refactor my code; eventually, I learn a new pattern or form of encapuslating logic that I later use to make my old code a lot better.
But a few weeks ago, I wrote 100 lines of beautiful code. I’m talking about a goregous, straightforward, no-nonsense class that did a lot in a relatively few lines of Ruby. I still feel pretty proud of it (can you tell?), and part of the reason for this is because I also learned a new pattern while writing this class. I was actually pairing with another developer, and we wanted to try using a rather common Rails pattern to solve a problem we were running into again and again: messy queries in our controllers and models.
We both were familiar with the concept of “skinny controllers” and “fat models”, or the idea that your controllers shouldn’t be responsible for containing the logic specific to a model. However, we also didn’t want our models to get out of control in size, which is exactly what was starting to happen. So, we searched for a workaround, and found our answer in one of the most elegant patterns I’ve seen in awhile: finder objects. Finder objects are simple Ruby classes that encapuslate the logic behind querying the database, and they are hands down, my new favorite kind of Ruby object.
In our bookstore application, we have Order
objects, which represent the orders that a user places in our system. However, these are books that we’re dealing with, and eventually we need to address the whole fulfillment process, which will need to be represented by a whole other set of models. For now, we’ll try to keep it as simple as possible. Let’s say that an Order
has many Shipments
, and each shipment represents a batch of Book
objects (read: products) that need to be shipped out together.
Right off the bat, we know that our Shipment
model will have some kind of state machine that will need to track the different stages of the shipment phase. Again, to keep it simple, let’s say that there are five different stages or state
s of a shipment:
processing
once an order has been placed.needs_label
state.needs_tracking
state.ready
for shipment.shipped
.To be clear, this is a super simplified version of what would happen in a real-life application! Now, in our admin panel, let’s say that we have a page that will render all of our shipments, which should always ordered by when they were created, so that our admins know which shipments to process, and in which order.
We can take it a step further and say that our main admin panel page — which will correspond to the index
action in our controller, should show our admins the most urgent shipments that need their attention as soon as they log in; in other words, these would be the shipments that were created more than a week ago, but still haven’t been processed.
I think we can all agree that basic Rails best practices should steer us away from doing something like this:
1 2 3 4 5 6 7 |
|
We definitely know that the controller really shouldn’t be responsible for querying for the correct Shipment
objects. All our controller should have to do is just render the correct ones, and not go digging for them in the database!
Okay, so we’ll create some scopes for these queries instead. These scopes should live in our model, not in the controller, right? Let’s see what our model might look like if we take that approach:
1 2 3 4 5 6 7 8 9 |
|
This cleans things up a decent bit! Scopes are actually part of the Active Record Query Interface, and they allow us to specify commonly-used queries which we can then actually reference and use in the form of method calls on our models themselves. They are really nothing more than defining class methods on a model:
1 2 3 4 5 |
|
However, they’re pretty wonderful because you can just chain them as method calls (Shipment.urgent.shipped
), but all they do is execute the correct query for you:
1 2 |
|
But the good news about scopes is also the bad news: you can just keep adding them and adding them, and chaining them onto everything. Our Shipment
class has only three scopes at the moment, one of them being the default
scope. But, we’ll probably have a page that should only render only the shipments that are in the needs_label
state, or a page that maps to a controller action which should only return shipments that are in the needs_tracking
state. We could keep adding scopes and then have our controller actions call the scopes on the class to return the appropriate shipments from our database.
Or, we could try something a little different.
Our scopes don’t actually add any new behavior to our model. As we saw earlier, they are nothing more than macros for querying for the correct rows from our shipments
table in our database. So, it really doesn’t make sense for our model to contain all this logic that doesn’t add any new behavior to it.
It would be nice, however, if we could apply the rule of “separation of concerns” here, and have an entire class whose sole responsibility would be to dig up the correct objects based on the parameters we were querying by. Really, this class should do nothing more than find the right objects. You might even say that instances of this class are just…finder objects! (Get it? Man, I really hope you got it.)
Anyways, how might this class look? Well, we don’t need any of the functionality from ActiveRecord, so we can create it as just a Plain Old Ruby Class:
1 2 |
|
Next, we’ll want to tell our finder object which models to query for, so it will know how to construct our queries, and which table to query. Since we never really want to have this method accessible elsewhere, we can make it a private class method that will only be called from the context of another ShipmentFinder
class method:
1 2 3 4 5 6 7 8 |
|
Now, we can use Rails’ arel DSL to construct a basic query. To do this, we’ll need a method that returns the table, which can also be a private method since we’ll never want to call it explicitly:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Now, we can write as many specific queries as we want. For example, we could write a urgent_needs_tracking
class method that could constructs a query using two private methods, needs_tracking
and is_ready
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
Now we can rely on our ShipmentFinder
class to find our shipments that have been created more than 7 days ago, and still don’t have a tracking number. We also can add more functionality that can be used in specific instances, which is exactly what we’ve done with our needs_label
and is_ready
private methods. We can use arel to construct queries using those methods to scope down what objects are actually returned. We don’t have to do anything fancy, if we don’t want to. Take a look at that shipped
method — this is just using a simple where
arel method to construct a query that reads like this: SELECT "shipments".* FROM "shipments" WHERE "shipments"."state" = "shipped"
.
Finally, the last step: it’s time for us to actually call on our finder object to do its job!
Let’s bring it all together by going back to our ShipmentsController
and add our new finder object into it. Our index
action should now be able to account for different types of shipments that our admins might want to query for. For now, we’ll construct our controller to accept a query parameter in our params hash that will be that status
of the types of shipments we want to return. Depending on the frontend framework we’re using, this might be a dropdown or checkbox option that will set a value on the status
key in our params hash.
Our controller action could now be rewritten to look something like this:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Here, we’re accessing the query param from params[:status]
, and turning it into a symbol (status_method
). Next, we’re using Ruby’s super handy respond_to?
method, and sending our status_method
symbol to our ShipmentFinder
. So, if our admin selects an option that sends the query param urgent_needs_tracking
, we are telling our finder object to call that method, and execute that query. The return value of the query executed by our ShipmentFinder
’s urgent_needs_tracking
method is what will be set as the instance variable @shipments
for the duration of this action on the controller.
If no query param is set, or if our ShipmentFinder
doesn’t have a method that maps to a query param, we’re just returning all of our Shipment
objects by default.
This is quite an improvement from our earlier code, which had our controller digging for rows in a database that it really didn’t have anything to do with. Now, we’ve separated our concerns into a new finder object, which exists as its own query interface on its own. It’s also worth noting that sometimes, creating a finder object can be overkill, and sometimes, if we have a lot of finder objects, we’d probably want to abstract a lot of this functionality out into a BaseFinder
class, which our finder objects could inherit from. But this is definitely a great start. No more digging for us!
ActiveRecord::Base
, and should be responsible for nothing more than executing queries. Read more about them on this fantastic blog post.Last week was my first week of working from home, which meant two things: spending a lot of time with my computer and limited time with other human beings and, more importantly, debugging things on my own without having anyone nearby to ask for help. The latter of the two actually ended up reaffirming the fact that I actually can debug a decent amount of things on my own if I just power through and am stubborn enough to not give up.
I also learned something interesting about the debugging process: while we’re learning, we often solve the same problem again and again. At least, this was the case for one of the features I was working on which involved using an object’s slug to generate a url. As I started thinking through how to approach solving this, I immediately had the feeling that I had done something similar in another project. Digging through another repository’s source code confirmed my suspicions, and I rediscovered the stringex
gem and its multiple libraries, including acts_as_url
!
All of this begs the question: why didn’t I remember that this gem existed — or that I had already used it? My guess is that it’s because I neither wrote about it nor understood how it worked until a few days ago. This week, it’s time to rectify that situation and dive into the acts_as_url
library and find a solution for all slug problems, once and for all!
We all are familiar with the Rails mantra of convention over configuration, aka making the lives of developers easier by eliminating the need for them to make decisions about how to structure their code. Now, this design paradigm is pretty fantastic, particularly when we’re first learning a new framework. But eventually, there comes a time when we need to tweak our code’s conventions just a tiny little bit.
What’s an example of this? Well, take Rails convention of finding an object by it’s id
. This standardization pops up all over the place, but the one that we’re particularly concerned with is the generation of a url. By default, Rails applications will build a URL path for the show
action of any given controller based on the primary key (aka the id
column in our database) of the object that we’re trying to “show”.
Let’s put this in context of our bookstore application. We have a bunch of Book
objects, and we want to iterate through their titles and then link to their individual “show” pages. A very basic, not-at-all-fancy template might look something like this:
1 2 3 |
|
It’s important to note that we’re actually passing in the book
instance here — an ActiveRecord
object, and not the book
’s id
. Why is this important? Because there’s a method that Rails is using to convert the Book
object into a URL in order to generate the correct address for our book_path
. That’s why we need to pass it an ActiveRecord
object, because the method that’s being called expects an object and returns the id
as parameters in the url. What does this look like, exactly? Well, right now our book_path
takes a Book
instance and creates a path that looks like this: localhost:3000/books/25
.
Which is fine! Actually, it’s more than fine: it’s the expected behavior given our Rails mantra of convention over configuration. But, what if we actually want to configure this a little bit more. What if, instead of using the primary key of our Book
instances, we wanted to use the title of the book? It would be lovely if we could link someone to a particular book’s page with a more human-readable url (for example, something like awesomebookstore.com/books/the-bell-jar
in production).
There’s a solution for this problem, and it’s called slugs. Slugs are a solution for semantic URL generation, which is also sometimes referred to as “RESTful” or “SEO-friendly” URL generation. As our application grows, not only would we want our URLs to be user-friendly, but we probably also will want them to be optimized for search engine results. So, we need to change our application’s configuration to use a slug.
Protip: if anyone ever pop quizzes you about where the term “slug” comes from, you can totally school them with the following interesting fact: a “slug” used to be a shorter name given to a newspaper article while it was in production; during the editing process, the article would be labeled by its slug, which would more specifically indicate the content of the story to the editors and reporters. The more you know, amirite?
There are obviously a lot of ways to approach this, but why reinvent the wheel by writing a bunch of methods that someone else has already written? Let’s make use of someone’s open source work and use the acts_as_url
library to get the job done for us!
The acts_as_url
library is actually part of the stringex
gem, which adds some useful extensions to Ruby’s String
class. After we add this gem to our Gemfile
(gem "stringex"
) and run bundle install
, we can get started doing a quick setup.
The documentation for this library is fairly straightforward, and a quick read-through gives us a good idea of what we need to do in order to make it work properly. The basic implementation of this library is four-fold:
acts_as_url
method in our model using the attribute name that we want to use for generating our url.to_param
method (Confused? Hang tight, we’ll get there in a second!)find_by
our new url attribute inside of our controllers.Let’s take it step by step. First, we’ll write a migration that will add a slug
column to our books
database. This is going to be the column that will map to a slug
attribute on our Book
objects:
1 2 3 4 5 |
|
Once we run rake db:migrate
and add this attribute, we will want to add the acts_as_url
class method to our Book
model.
1 2 3 |
|
The default behavior of this method expects that we have a column and attribute called url
on our object. Since we aren’t using the default attribute name, we need to specify the name of the attribute that we’re using to store the generated url string. Thankfully, acts_as_url
takes a bunch of options, including url_attribute
, which is what we’re using here. There are some other useful options worth checking out in the documentation, including scope
, limit
, truncate_words
, and blacklist
.
Next, we’ll need to override Rail’s to_param
method in order to actually use our generated url attribute. Basically, we’ll just want to write our own to_param
method and return our slug
attribute from inside of it.
1 2 3 4 5 6 7 |
|
And finally, we need to make sure that we’re finding our object using the appropriate attribute from within the context of our controller. The documentation suggests we use
the find_by_url
method, but we could also use the find_by
method in our controller as well.
1 2 3 4 5 |
|
Nothing changes about how our controller works and we can still do all the fancy things we were doing before, like use a decorator (Remember those?). The only thing that happens now is that our original book_path
helper will now use the book
instance we passed it to generate a url with a slug instead of the primary key!
Success! We’ve done it! Actually, we’ve almost done it. One tiny little thing that I always forget is all of the books that already exist in our database. What about them? They all have a slug
attribute, sure, and a slug
column – but there’s a slight problem: the column is empty! So we can’t find_by
the slug
attribute for those books, can we? In fact, if we try to call to_param
on any of our preexisting Book
instances right now, all we’ll get is nil
!
No worries, we just need to call a method inside of our console:
1 2 3 |
|
Now all of the Book
instances that had empty slug
attributes have ben initialized, and we’re good to go! Right? Wrong. Because I haven’t explained the whole to_param
situation yet, and I promised that I would get to it. Now’s the time to figure out the magic behind that!
to_param
The Rails solution to generating params for an object’s url path comes from its elegant to_param
method. By default, this method just calls to_s
on a Plain Old Ruby Object, and converts it to an instance of Ruby’s String
class. However, there are plenty of places where Rails itself overrides this method (which explains why we also have to do it in the context of our own controller)!
In fact, the Rails documentation even explains when and how to go about redefining the implementation of this method:
“Notably, the Rails routing system calls
to_param
on models to get a value for the:id
placeholder.ActiveRecord::Base#to_param
returns theid
of a model, but you can redefine that method in your models.”
1 2 3 4 5 |
|
Of course, we could have easily redefined this in the context of each of our models, but using the acts_as_url
library reduces the amount of duplicated code that we need in each of our models, and is pretty sophisticated in that it allows us to use different attributes across different models to generate our url path.
Interestingly, the source code for Rails’ to_param
method reveals some elegant checks as well. This method first checks whether the object as been persisted to the database, and then returns a string representing the object’s key. We can actually see how the to_key
method is being called from inside of to_param
, and how the default return value of an unpersisted object’s param will be nil
. This is the magic that goes on under the hood when we were trying to find the slug
attributes for all of those Book
instances before we called initialize_urls
on them!
So, even though slugs have a reputation of being slow, now we know how to speed through this problem with an elegant and quick solution! I can’t say the same for this poor guy, though:
acts_as_url
library expects an url
attribute on a model, and uses that to generate the path for an object. You need to override Rails’ to_param
method that, by default, will use the id
of an object to generate its path.to_param
method used to be defined inside of ActiveRecord::Base
, but has since moved to the ActiveModel::Conversion
module, which handles default conversions, including to_model
, to_key
, and to_partial_path
. Read more about how these methods work in the Conversion module documentation.A few weeks ago, while learning everything I never knew about user authorization, I also stumbled upon a cool refactoring pattern that I didn’t even know existed. This pattern is based on the simple idea of Ruby modules and mixins, but is particularly handy when it comes to dealing with class methods and callbacks.
ActiveSupport is a pretty massive component within Rails, and it’s responsible for a ton of different functionality, including language extensions and utilities. I last wrote about ActiveSupport back when we were exploring the Rails inflector and the libraries it provides for handling the pluralization of different strings. This was way back in September, and at the time, my understanding of ActiveSupport was pretty limited. It turns out that yes, ActiveSupport does provide a bunch of different patterns to transform simple Ruby strings…but it also has a lot more going on inside of it. For example, the ActiveSupport Concern module, which only recently made its debut in Rails 4.
The ActiveSupport::Concern wrapper is an interesting way of encapsulating…well, certain functionality that you might be concerned with. These concerns take advantage of two directories that are automatically part of the load path within a Rails application: app/models/concerns
and app/controllers/concerns
. So, how do you write a concern, and what should go inside of it? Don’t worry, that’s exactly what we’ll concern ourselves with next.
Concerns are meant to make our lives less complicated. Or at the very least, we should be less concerned about the quality of our code if we use concerns, right? But what are ActiveSupport’s Concerns really meant to be used for? And how do we know if we should be using them? Well, to answer this question, we can turn to the creator of Rails himself. In a blog post pre-Rails 4 titled Put chubby models on a diet with concerns, DHH explains when and why to consider using ActiveSupport’s Concern module:
“Concerns encapsulate both data access and domain logic about a certain slice of responsibility. Concerns are also a helpful way of extracting a slice of model that doesn’t seem part of its essence (what is and isn’t in the essence of a model is a fuzzy line and a longer discussion) without going full-bore Single Responsibility Principle and running the risk of ballooning your object inventory.”
When we talk about concerns, what we really are honing in on is the most effective separation of concerns. I really like the way that David thinks of models having an “essence”, and I think that this is a great way of approaching when and when not to use a concern.
Let’s look at our bookstore application. We have an User
model for anyone that signs up to use our application. Whenever a User
signs up, we want to send them an email telling them that they’ve been registered, and probably highlighting some of the cool things that they can do to set up their profile on our application. Now, this seems like something that only the User
model would be concerned with, right? Well, yes, until we realize that we have another model that needs to share this same functionality!
For example, we now have organizations that want to sign up for our application. They also need to receive the same email and be “registered”. As our application grows, we might even want to create a Registration
model, which would belong to an User
and Organization
. Now, obviously we could accomplish what we wanted to by just adding the same lines of code to both models, but that makes for neither DRY code, nor a great separation of concerns. But wouldn’t it be great if we could take this piece of “registration” functionality, wrap it up, and only pull it out when we need to use it? It turns out that is exactly what we can do with ActiveSupport::Concern
.
Before we write our concern, let’s look at what our User
model looks like. Here’s a truncated version that contains only the logic pertaining to registering a user:
1 2 3 4 5 6 7 8 9 |
|
We very well could stick this inside of our organization.rb
model file, but there’s a better way to do this. There are a few steps to creating a concern, the first of which is recognizing where to put it! Since we’re creating a concern for a model, this will live inside of our app/models/concerns
directory. We’ll call this concern a Registerer
concern, since that’s its single responsibility, and we can preemptively namespace our concern under Users
, which would make its path app/models/concerns/users/registerer.rb
.
Next, we’ll want to extend
the Rails ActiveSupport::Concern
module itself from within our concern:
1 2 3 4 5 |
|
Now, for the actual writing, there’s one method that’s going to be our new best friend: the included
method, which takes a block. A little-known fact about this callback is that it’s actually defined by Ruby’s Module
class, and it’s called whenever a module is “included” into another class or module. This is where we’ll put the important class methods and callbacks that we want to be shared amongst the models that will use our concern.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
This is mostly straightforward. All the logic for a registration now lives in this single file, including the creating of a registration association on our target object (in this case, the User
model), the registering of a user by passing our User
instance (self
) to our RegistrationEmailerJob
, and the updating of the registered_at
attribute on our User
model using the touch method — assuming, of course, that we’ve defensively coded this attribute onto our User
model. We’re also able to use the after_commit
callback hook, since the included
method can accept callback names as parameters.
Now that we have all this code in one place, how do we add it to our model? Well, we can do it in a single line:
1 2 3 |
|
All we need to do is include
our concern, just as we would a module. And down the road, when we find out that we need to create Organization
model that shares this set of functionality, all we need to do is add the exact same line to our new model:
1 2 3 |
|
And here’s the really nice part about utilizing concerns in this way: when we realize that we need to change how this works — maybe we need to add another job or service object, or perhaps another, more specific callback — we can add it to one place and update our logic in a single file! This ties in quite nicely to DHH’s point of a model’s “essence”. In this case, being able to be “registered” isn’t necessarily something that pertains to the User
model specifically. But, it also doesn’t need to be its own object per se. Instead, we really just need a set of methods that can be available to be invoked upon an object, which is exactly what ActiveSupport::Concern
provides us with.
Because concerns are so simple to extend and include, there are lots of use cases for them. We learned earlier that Rails comes with two concerns
directories preloaded: one for models
, and another for controllers
. Let’s look at a practical example for using ActiveSupport::Concern
in the context of a controller.
We recently added the pundit
gem to our bookstore app for user authorization. But we only had a few controller actions that actually needed to be authorized; the rest of our controllers didn’t need any authorization, because they could be accessed by anyone. Our Reviews
controller was being authorized, for example, but our Comments
controller didn’t need any authorization whatsoever.
So, for the controllers that didn’t need authorization, what did we do? Well, we were adding some skip_after_actions
lines, which were instructions that the pundit
gem documentation had given us:
1 2 3 4 5 6 |
|
Now, imagine we also have a BlogsController
with just an index
action API endpoint, which doesn’t need to be authorized. And maybe we also have TagsController
, which also doesn’t need to be authorized by pundit
. We could copy and paste these two lines into every single controller…or, we could use our newfound knowledge of ActiveSupport::Concern
!
Let’s share some of this code, shall we? We can create a skip_authorized.rb
file inside of app/controllers/concerns
. And inside of it, we’ll include Pundit
— otherwise, our skip_after_actions
will have no idea what actions we’re trying to skip! Our concern might look something like this:
1 2 3 4 5 6 7 8 |
|
Pretty simple, right? And suddenly, our CommentsController
, BlogsController
, TagsController
, and pretty much every single controller that we want to share these skip_after_action
callbacks now can be refactored to have this single line:
1 2 3 4 5 |
|
And now, if we wanted to rescue
from a Pundit::UnauthorizedError
, we could add a single line, into a single file…but all of our controllers would mix that in! Similarly, we could create an Authorized
concern for every controller that needed to actually implement pundit
authorization. See, there’s no need to worry for the rest of our days, because instead, we can just be concerned — ActiveSupport concerned!
Concern
module allows us to mix in callbacks, class and instance methods, and create associations on target objects. This module has an included
method, which takes a block, as well as an append_features
method and class_methods
block, which you can read about in the source code.There are times in a Ruby program or Rails application that one comes to a single realization: Oh no, I need to deal with an external file! For larger applications, this might manifest as a request to your Amazon S3 bucket for a file, which you then need to modify in some way, or perhaps just simply read and have access to. But sometimes, even a simple Ruby script or plain old Ruby class may need to read or write to an external file.
I honestly didn’t know a lot about Ruby’s File class (wait, Ruby has a file class?! Yes, yes it does.) until recently, when I had to handle a situation that would allow me to download files from a file storage service (such as S3), and then process the file locally on my machine. The process was a bit complicated, and I still think that I have more to learn about how it actually works. But, one thing that I did actually start to wrap my head around is Ruby Tempfiles. Yup, that’s right: not only does Ruby have a File
class — it also has a Tempfile
class.
It turns out that these two classes intersect quite a bit, and it can be a little confusing to know how they differ. The only way to really understand Ruby’s Tempfile
class is to play around with it and create some tempfiles. So let’s get filin’!
The reason that the Tempfile
class and File
class seem so similar — and can therefore be so confusing — is because the Tempfile
class actually inherits from its parent delegate class, which just so happens to be…File
! So, tempfiles are actually just a type of file. So, what can you do with files in Ruby? And what makes tempfiles different from a regular old file?
Well, the documentation for File
objects is hugely informative, and if we dove into it, we’d learn that Ruby files actually inherit from a class called IO File
. But let’s not get too distracted here: what can we do with files, again? Well, we can read a file’s data, we can write more data to it, and we can even change its permissions (i.e. who can access and write to the file). Pretty straightforward, right?
Now, onto tempfiles. As their name would suggest, they’re files that are temporary. But even though they are named pretty well, it still might not be clear in what way these files are temporary. Well, we can create tempfiles in the same way that we create regular Ruby files, but what makes them unique is that tempfiles only exist as long as there is a reference to them. In other words, tempfiles get deleted automatically by the Ruby garbage collector. If no variable is pointing (read: assigned) to a tempfile, the garbage collector will “finalize” the tempfile object, and the file would be deleted from our system.
So…why is this significant? Well, what would happen if we tried to access a tempfile that Ruby has deleted? Bad things, that’s what! Well, we’d actually just get an error, because we’d be trying to access a file at a path that doesn’t exist anymore. But still, things could get pretty bleak if we didn’t know what was going on — or worse, if we didn’t fundamentally understand how tempfiles worked!
A good rule of thumb for deciding whether or not to use a tempfile is this: if we need access to the file outside of the context of our Ruby script, we probably shouldn’t be using a tempfile. However, if we want to temporarily create, read, or write to a file, and then have Ruby delete it for us (for free!) when we’re done using it, then a tempfile is our new best friend!
When it comes to creating files, there’s a certain order of operations with method invocation. Even though the documentation for the Tempfile
class has a list of helpful methods for us to use, there’s a lot of less obvious functionality at our disposal, as long as we know where to look. Because the Ruby Tempfile
essentially inherits from File
, a tempfile behaves just like a file object. This means that we can call any File
instance method on a Tempfile
object. This is particularly important to note since some of the most common methods that are called on a tempfile are actually defined within the File
class. So, if we couldn’t find where a particular method on a tempfile was being defined, it probably means that we need to go look inside of the File
class.
Okay, enough talk about where to find these methods; let’s figure out which methods are actually pertinent to tempfiles. Both files and tempfiles share a sequence of events: generally, we create the file, then we read or write to it, and then we close it. But with tempfiles, there’s a little twist at the end. Let’s take a look at the order of filing operations:
new
This method is pretty self-explanatory: it’s what we’ll use to create a new tempfile. This comes from the File
class, and takes a single argument: the name of our file. Let’s create a tempfile called cats
:
1 2 3 |
|
This creates a unique filename in our operating slystem’s temp directory, and it contains our filename cats
in its basename. If we wanted to find out exactly where in our temp directory this file lives, we could just ask it for its path using — you guessed it — the path
method:
1 2 |
|
We could also specify the extension of the file that we’re creating (i.e., pdf
, gif
, etc.). However, it’s not as simple as just appending it to our filename; if we do that, this is what happens:
1 2 |
|
Not great! We don’t want our extension to be a part of our filename, we want it to be at the end, obviously! Luckily, the new
method allows us to pass the filename and extension as an array:
1 2 |
|
Much better! Now, let’s open this file up.
binmode
The next step is to put our file into binary mode by using the binmode
method. As the documentation explains, this method is what changes how we write data to the tempfile’s binary.
1 2 |
|
This disables us from encoding and creating new lines, and it changes the way that we write content; setting a file to binary mode forces Ruby to treat the content as ASCII-8BIT. There’s also a handy binmode?
method that we can use to check whether our file is in binary mode or not.
write
Finally, once we’re in binary mode, we actually write to our file! And of course, the tool for the job is the write
method. This takes a parameter of whatever it is that you want to write to the file.
1
|
|
Interestingly, this method is defined in the IO
class, which subclasses into StringIO
.
rewind
Now, if we wanted to read to our file, we could just read it, right?
1 2 |
|
Wait, what happened to our "meow meow meow"
string? Well, if we think about it, when we were writing to our file, we ended at the end of wherever we stopped writing. And that means that there’s nothing to read, because we’re at the end of our file. This calls for the rewind
method, which will take us back to the beginning of our tempfile.
1 2 |
|
We’re now at the beginning of our file!
read
After rewinding back to the beginning of our file, we can now actually read it using the read
method:
1 2 |
|
So far, we’ve been working with this file as though it’s a normal Ruby File
class. But let’s not forget…this is actually a Tempfile
. And dealing with how to close and clean up a tempfile is where things can get tricky. Now all that’s left is for us to elegantly handle these fleeting, disappearing files.
The last steps in the order of filing operations is explicitly closing our tempfile. This is probably the most complicated part to understand, especially if we’re not familiar with the concept of garbage collection. However, I think that the Ruby docs do a pretty great job of explaining the how and why of explicitly closing tempfiles, a good practice that the core team strongly encourages:
“When a Tempfile object is garbage collected, or when the Ruby interpreter exits, its associated temporary file is automatically deleted. This means that it’s unnecessary to explicitly delete a Tempfile after use, though it’s good practice to do so: not explicitly deleting unused Tempfiles can potentially leave behind large amounts of tempfiles on the filesystem until they’re garbage collected. The existance of these temp files can make it harder to determine a new Tempfile filename.”
The guides suggest that the best way to go about deleting a tempfile after we’re done using it is by calling two specific methods from within an ensure
block (remember the ensure
keyword? No? Don’t worry, you can read about it over here).
But first, let’s round out our order of filing operations with the two most important tempfile methods.
close
This method basically tells the Ruby interpreter, you can’t read the file now!. It closes the file and doesn’t allow it to be read or written to.
1 2 |
|
Some blogs have mentioned that this method isn’t always necessary, but it can’t hurt to use it.
unlink
This method is what actualy deletes the file from the filesystem.
1 2 |
|
We could also use the delete
method, which is just an alias for unlink
.
Playing with these methods in irb
has been fun, but what would this look like in a Rails application? Well, we’d probably want a single method to handle the creation, writing, and deletion of our tempfile (think separation of concerns!). And this is where the use of our ensure
block would come in.
This might look something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Here, we’re using all of the methods in our order of tempfile operations! And, because ensure runs even if there were any errors raised, we’re basically always going to handle the closing and deleting of our tempfile. In this case, we probably don’t want to call all our tempfiles cats
, so instead we can be a bit more fancy and use the SecureRandom
module to create a base64 tempfile name each time. We even go crazy and take this yet another step further, and have our file_attachment
method take a block, which we could yield
to inside of our begin
block, before we rewind
to the beginning of our tempfile.
As you can see, the possibilies are pretty endless! Tempfiles are our oysters! Well, until Ruby’s garbage collector deletes them, that is.
File
class and Tempfile
class is that tempfiles are cleaned up (deleted by the garbage collector) once there is nothing pointing to them. Tempfile objects inherit from the File
class, which means that we can use any file method on a Tempfile
instance.unlink
method is super important to use, since that’s what actually deletes our tempfile from the filesystem.Ah, authorization – or as I like to call it, authentication’s cooler, slightly less complicated twin. It’s easy to confuse the two, but there’s a fundamental difference between them. I recently learned that while setting up an authorization system for an application that’s nearing the end of development. Authentication focuses on who you are as a user — an admin, guest, or user with an account, for example — while authorization is about what actions you can take. Authorization centers around what you are actually able to do within the context of your role.
It often makes sense to leave authorization as one of the later (and sometimes, last) step of development, purely because it means that you don’t need to worry about making sure that you are authenticated in your development environment while you are still building out your application. But eventually, somewhere between development and deployment, you’ll have to think about the abilities of your users — or, what they can and can’t do.
There are a few different ways to go about creating an authorization system, one of the most popular being can_can
, a gem that has been around in the Rails community since 2010, as well as a newer gem called rolify
. But the one that I’ve found really easy and fun to work with is pundit
, an authorization system crafted by eLabs, and interestingly enough, based off of the logic and thought behind the CanCan’s approach. The developers at eLabs actually started off using the CanCan library in their own applications, but quickly realized that it could become very complicated, very quickly. So, they built the simpler authorization system of pundit
, which is exactly what we’ll play around with today!
Implementing the pundit
gem is easy once we understand how it’s structured, what it’s expecting, and what conventions to follow. But before we do anything else, we’ll need to add it to our Gemfile
:
gem "pundit"
and run our favorite command, bundle install
.
The documentation for this gem is fairly well-explained, and even allows you to generate all the basic files you need with a single command (rails g pundit:install
). However, generators can be a little bit dangerous if you don’t understand what’s going on behind the scenes, since all logic has been abstracted away and things start happening automagically! So, let’s set up our authorization system for our bookstore manually. Don’t worry — it’s not going to be too painful!
First things first: we need to make sure that we include pundit
in our controllers. This is a particularly important step because we’re going to use a method inside of all of our controllers, and if we don’t include Pundit
, none of our controllers will have any idea what method we’re trying to call. Since we’re going to be authorizing multiple classes, it makes sense to add pundit
to the file where all our other controllers will inherit from: ApplicationController
.
1 2 3 4 |
|
Next, we need to understand how pundit
actually works. If we take a look at the documentation, there are a few things that immediately become clear: pundit
is focused around something called “policy classes”. Similar to how cancan
relies “ability classes”, pundit
expects a policy class to house our authorization logic.
Okay, so we need policy classes. But what kind of classes are they? Do they inherit from anything? How many do we need, exactly? And what should go inside of them? If these are the questions running through your head, fret not: there are answers to all of them!
Here are the basics of building a pundit
policy class:
ActiveRecord::Base
, or anything else. The only thing that the class must have is the suffix Policy
.User
model would have a UserPolicy
, while a Book
model would have a BookPolicy
class.user
, and the model
that we want to authorize. The initialize
method in a policy class will always expect these two parameters in a certain order: user
as the first argument, and the model
object that we want to authorize as the second arugment. The model
doesn’t have to be an ActiveRecord
object – it can literally be anything that you want to authorize!UsersController
has create
, update
, and destroy
actions, our UserPolicy
class should (theoretically) have create?
, update?
, and destroy?
query methods inside of it.Okay, that’s enough on policies to start. Let’s actually start writing some of those policy classes! We’ll need to create a folder for all of our policies since we’re not using the generator (app/policies
), which will house our policy classes. The most important policy class that we should write first is our ApplicationPolicy
, which will reside at app/policies/application_policy.rb
. This is where we can put our initialize
method in, since we know that every policy needs to have this method inside of it.
1 2 3 4 5 6 7 8 |
|
Since the initialize
method of our ApplicationPolicy
is going to be used by all of our other policy classes, we can refer to the second argument (the model that we want to authorize) as resource
. Depending on what policy class we are in, the resource
object will change. If we had used the generator, we’d notice that the model object is actually referred to as record
, which also would have been an acceptable name for our second argument. Either way, this is a nice and easy way of abstracting out this method into one file, and then reusing it in our other policy classes. Speaking of which…it’s time for us to write those, next!
We’ll start by authorizing (one of) the most important objects in our application: our users! Since we have a User
model, we’ll need to abide by pundit
’s policies, and create a user_policy.rb
file inside of app/policies
. We’ll make sure that it inherit from ApplicationPolicy
, so that we’ll have access to the initialize
method:
1 2 |
|
Next, let’s take a look at our UsersController
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
There’s nothing too fancy going on in here at the moment, and for now, we’re only concerned with authorizing the update
action in our UsersController
. Ultimately, we don’t want any user to be able to update their information unless they are logged in; in other words, a user shouldn’t be able to update anyone else’s name and email except for their own.
So, if we want to authorize the update
action, we’ll need a query method in our UserPolicy
class called — you guessed it — update?
:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
All we’re doing here is verifying that the user
instance that we’re passing in to the initialize
method (which we’re inheriting, remember?) is the same instance as the resource
that we’re passing in. The resource
is the model that corresponds to the policy; in our case, we’re in the context of the UserPolicy
, so our resource
is the user
instance.
The last step is actually telling our update
action in our UsersController
to use the UserPolicy
and authorize our user
instance. To do this, we’ll need to call the authorize
method, and pass in our resource
that we want to authorize:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
In addition to calling authorize
, we also need to make sure that our policy is actually being used! In fact, that’s what the after_action :verify_authorized
line is doing. The documentation suggests adding this to our ApplicationController
, but for the sake of clarify, we can put it here temporarily, just to see how everything is working together. Pundit adds a method called verify_authorized
to our controllers. It’s this method that is reponsible for raising an exception if authorize
is not called. It’s recommended to put this in an after_action
so that we don’t forget to authorize any controller actions when we invoke them. Eventually, we’ll want to abstract this line to our ApplicationController
:
after_action :verify_authorized, except: :index
Since this is an after_action
, we can pass it except
or only
, if we want to skip authorization for certain controller actions.
So, how is all of this working? Well, when we pass user
to the authorize
method, we are actually telling pundit
to look for a UserPolicy
, find the corresponding action, and invoke it. If our user
instance is not authorized, pundit
will raise a Pundit::NotAuthorizedError
. The source code for the policy finder and the authorize method reveal exactly how this happens, and are pretty cool to look at under the hood.
The pundit
gem is pretty powerful, but the thing that makes it the cool kid of authorization is how it handles scopes. We can use scopes when we want to have a specific subset of records that a user has access to — basically, when we want to narrow the “scope” of the resources that are visible to our user, based on their “level” of authorization (admin, guest, etc.).
Let’s write a quick scope for the Review
objects of the book reviews in our bookstore. Right now, our ReviewPolicy
looks like this:
1 2 3 4 5 |
|
We have a corresponding update
action in our ReviewsController
, and we’re allowing a review to be updated only by the user who wrote it (in other words, the user
object that the review
belongs to). But we also need an index
action, and we want to limit the reviews
that can be viewed by a user in the index action. Ultimately, the only user
that should be able to see all reviews (including drafts) should be admins; otherwise, the only reviews that should be visible are the ones that have been published.
And that’s where scopes come into play. There’s a few rules to scopes:
user
instance, and a scope
. The scope
is what we’ll perform some kind of database query on — usually an ActiveRecord class or ActiveRecord::Relation
.resolve
method, which should return an array of instances that we can iterate over — again, probably an ActiveRecord::Relation
.Let’s go ahead and add a scope to our preexisting ReviewPolicy
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
The only thing that’s actually happening here is that we’re limiting the number and types of book reviews
that will be rendered by the resolve
method. If our user
is an admin, we’ll run the query Review.all
; otherwise, we’ll execute the query, Review.where(published: true)
.
Again, we could abstract the initialize method of our Scope
class into the ApplicationPolicy
so that we could inherit class Scope < Scope
, rather that actually writing the method directly into this class. In fact, that’s probably exactly what we would do once we realized that we needed to write more than a single scope.
The last step is adding our scope to our ReviewsController
. We can use a method provided by pundit
in our controller called policy_scope
, which takes an class instance of a model (in our case, Review
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Now, our index
action uses the policy_scope
method to find the reviews that we’ll render. The policy_scope
method infers that we want to use the ReviewPolicy::Scope
class, and it will instantiate the class and then call resolve on the instance. In fact, the code that’s actually getting executed here is this:
reviews = ReviewPolicy::Scope.new(current_user, Review).resolve
The other important line in our controller is the method that’s actually mkaing sure that the policy scope is being used:
after_action :verify_policy_scoped, only: :index
Similar to verify_authorized
, the verify_policy_scoped
method is what ensures that the policy scope is actually being used. And in our case, we only have a scope on our index
action, so we can specify that we only want to use a scope on :index
. Not too bad, right? Just tell pundit
what you want to scope, and what you want to authorize, and it will do the rest for us!
But what if we had a class that never needed to be authorized or scoped? How could we tell pundit
to just skip the authorization for that specific model? Well, it’s pretty easy — we can just use skip_after_action
:
1 2 3 4 5 6 |
|
Simple! This gem is pretty fantastic to work with, and gives us great guidelines on the proper way of using it. I really liked this particular piece of advice from the library’s developers:
“Pundit strongly encourages you to model your application in such a way that the only context you need for authorization is a user object and a domain model that you want to check authorization for. If you find yourself needing more context than that, consider whether you are authorizing the right domain model, maybe another domain model (or a wrapper around multiple domain models) can provide the context you need.”
It turns out that authorizing with pundit
can be a really good time. You might say that it’s even kind of…fun!
pundit
gem is a simple way to build a powerful authorization system. It expects plain old ruby policy classes for each model that you want to authorize, and each class should contain query methods that map to controller actions for the model. The controller that corresponds to the model should call the authorize
method for the object, and should either contain or inherit an after_action :verify_authorized
method.pundit
, and based it off of the cancan
library. In fact, they even wrote a super blog post about their process, which you can read over here.This blog post is part of a series on Active Job. Read Part 1 here.
With the advent of Rails 4.2, one thing is definitely for sure: there is now one background job to rule them all: Active Job. Last week, I learned about Active Job’s easy integration with ActionMailer. But, as nice as it is to have those simple deliver_now
and deliver_later
methods, there will inevitably be a time that we want to do something more — something that requires writing our own custom job.
Active Job is, thankfully, very good at letting us do this. Since my ActionMailer post last week, I’ve written a few jobs using Active Job’s framework. And each time that I’ve done it, it’s gotten easier and easier. Of course, not all of my jobs have been super complex, but once I understood the basics, I could look at other people’s code and understand how it was structure and what exactly was going on.
The only way to get comfortable writing my own custom jobs was by – wait for it – actually writing one! So that’s exactly what we’ll do together. Let’s turn our ActionMailer method from last week into its own job that will be able to run asychronously. Hold on to your hats, because we’re about to leave the shire.
The most important first step before even generating a job is to make sure that we have our queue adapter set up for Active Job. The default queue adapter for Active Job is to run inline (or, within the same request-response cycle), which means that it will not run in the background. One of the lovely things about Active Job is that we can use any queueing backend that we prefer, as long as we follow the documentation to set it up. Last week, we did this by adding delayed_job
to our Gemfile
, and setting our queueing configurations inside of config/application.rb
:
config.active_job.queue_adapter = :delayed_job
The delayed_job
backend also requires us to run a migration, which adds Delayed::Job
objects to our database:
1 2 |
|
This will be important later on, because the only way for us to see any jobs that are enqueued or that have failed is by calling Delayed::Job.all
in the console or from within the context of a controller. This migration also adds helpful columns to our delayed_jobs
table, including priority
, attempts
, run_at
, failed_at
, and last_error
. This data would be particularly relevant if we wanted to allow a job to be re-run, or for a job’s errors to be displayed within an admin panel.
Now that we have all of our queueing backend setup taken care of, we can start to write our job. At the moment, we have an instance method called send_confirmation_email
on our Order
class, which uses deliver_now
to send an email. You’ll remember that we’re calling this method from within a state machine:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
We still want to use our OrderMailer
, but it would be nice to be able to do that within the context of a background job that exists in its own file, so that we can customize it. Let’s generate our job and text unit for our order confirmation emailer, with a nice namespace to boot:
1
|
|
Now, inside of app/jobs/order/confirmation_emailer.rb
, we have a simple little file that looks like this:
1 2 3 4 5 6 7 8 9 |
|
It doesn’t look like much, does it? But, it’s honestly almost all that we need. The most important thing to know about ActiveJob when it comes to writing a job is this: you must have a perform
method. And, as you might expect, the perform
method should be, well, responsible for actually performing the job. However, our job doesn’t do anything yet. And we’re not even calling it anywhere! You know what that means, right? It’s time for us to set off on our custom job adventure and start writing!
Since we already know that our perform
method is going to be responsible for performing our job, we know that this is where all of our logic should go. It would be nice if we could just pass this background job an order
instance, and then tell it what to do with that order. Our OrderMailer
has a confirmation_email
method that accepts an order
object, so we can really just use the mailer inside of our job.
Let’s pass an order
to our job, and then have the job be responsible for delivering the confirmation email:
1 2 3 4 5 6 7 |
|
Nice! That was easy enough, right? You’ll notice that our ConfirmationEmailerJob
inherits from ActiveJob::Base
. This is very important, because without inherting from this module, our job would have no idea what to do with its perform
method! It’s crucial to keep this in mind particularly if we are manually creating our jobs and not using the rails generator; in that case, we need to add the ActiveJob::Base
inheritance on our own. (I was bit by this recently, so don’t make the same mistake that I did!)
Honestly though, this isn’t doing that much more than what our OrderMailer
did initially. We’re writing a custom job, so let’s customize what this job can do. In addition to delivering our confirmation email, it would be cool if this job could also update an attribute on our order
called confirmation_sent_at
. This is just a datetime format attribute that will probably end up in an admin panel or dashboard. And there’s a really elegant way that we can update this attribute from within the job:
1 2 3 4 5 6 7 8 9 |
|
The touch
method is part of ActiveRecord, and allows us to save an ActiveRecord object with the updated_at
and updated_on
attributes set to the current date and time. It’s important to note that there are no validations that are performed by this method, and it’s actually only the after_touch
, after_commit
, and after_rollback
ActiveRecord callbacks that are ever executed.
If we called order.touch
, we would only update order.updated_at
. But, since we have a specific attribute called confirmation_sent_at
in order to specifically keep track of our confirmation emails, we can tell the touch
method to update that attribute by passing it in as an parameter: order.touch(:confirmation_sent_at)
. This is a pretty awesome method, but don’t make the mistake of trying to call it on a plain old Ruby object, or on an unsaved ActiveRecord object! The object must be persisted, since the touch
method is defined in the ActiveRecord::Persistence
module. Otherwise, you’ll get an ActiveRecordError, and we don’t have time for that silliness!
However, what we do need to do next is call our background job and have it…well, do it’s job!
Now that we have our Order::ConfirmationEmailerJob
class ready to get to work, it’s time for us to actually get to work and start performing. Since we already have our state machine in place, let’s just call our job from within our Order
class:
1 2 3 4 5 6 7 8 9 10 11 |
|
Nice! The perform_later
method on our Order::ConfirmationEmailerJob
will instantiate our job and call perform
on it. Since we’re already in the context of the Order
model, we can simply pass in self
, which is just the order
instance, into our job, which will know exactly what to do with it. We’re also taking advantage of the after
callback in our state machine, and invoking our job directly inside of our completed
event. Alternatively, we could have abstracted this out into a method for a more granular separation of concerns. But since our job is pretty simple, it also makes sense to put it directly into the after
block.
Now, when we call order.completed!
, our state machine will transition our order
object to the state 'complete'
, and after the event, it will create a new instance of our Order::ConfirmationEmailerJob
, which will call the perform
method asychronously, and will use delayed_job
to enqueue the job in the background. The emailer job would then send our order confirmation email using ActionMailer, and then it would update the confirmation_sent_at
attribute on our order
instance. And, if we wanted to see what the job looked like while it was being running asychronously, we could open up the rails console and run Delayed::Job.last
, which would show us all the details about the most recent job that we had called.
Wow, that’s a lot of things happening in a pretty complex sequence! That tiny little perform
method isn’t looking so tiny after all, is it?
Interestingly, the job that we wrote is still a lot simpler than how Rails jobs used to be written. Before Active Job was integrated into Rails 4.2, we weren’t able to pass in an order
instance into the perform
method of our job. Instead, we had to pass in the id
of an object, and then look it up inside of our job:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Not as nice as clean as what we wrote initially, right? But still, despite all the extra lines of code, it’s pretty amazing that all of these actions can be performed asynchronously, and within different request-response cycles. Rails’ ActiveJob truly does rule all.
ActiveJob::Base
, and implementing a perform
method. Now, we can actually pass in instances of objects to the perform
method, rather than ids, which is all thanks to global ids.touch
method works? Check out the documentation on this amazing little function.Last week, I sent a lot of emails — after all, I was working on creating my very first mailer. But in the process, I also realized something else: waiting for an email to send is not fun. Especially if you can’t do anything else while you’re waiting.
This problem pretty much encapsculates the reason for the existence and invention of background jobs. I’ve actually been playing around with creating and running jobs in different applications for the past few months now, yet I never really felt comfortable with them. I knew that having jobs run certain processes was clearly very important since they kept popping up all over the place. However, I was having trouble wrapping my head around what exactly a background job was, and when and why I would ever need to use one.
Working with ActionMailer turned out to be the perfect stepping-stone to Active Job, which helped me to better understand inline processes, asychronous requests, and how all of these things fit into running a job. Since we already know how to create mailers, that will be the perfect introduction to running our very first job! Integrating ActionMailer and Active Job is a piece of cake, so we’ll start with that first. Baby steps, my friends!
Background jobs existed far before ActiveJob came into being in December of 2014. In fact, if we take a look at one of our more complex, pre-Rails 4.2 projects, it’s likely that we’ll see a some classes that are suffixed with Worker
. These classes are a little bit like service objects in that they are responsible for taking in an object as a parameter and performing a certain action with or on that object, sometimes implementing a service class in the process of doing so. The “worker” term really just refers to classes that we use in the background of our application.
But, why would we ever need to run a class in the background of our application? And honestly, what does that even mean? Well, we can start by defining what exactly makes a background job, beginning by peeking inside of our config/application.rb
file. There are a lot of things happening inside of here, all of which are setting different configurations inside of our application. But there’s one line in particular that we should pay more attention to:
Rails.application.config.active_job.queue_adapter = :inline
Without even worrying about what queue_adapter
is doing for now, we know one thing for sure: our current active_job
configuration is set to run inline
. Okay, let’s try to deduce what inline
means, exactly. A quick search in the Rails guides leads us to the documentation for something called the InlineAdapter
, which explains:
“When enqueueing jobs with the Inline adapter, the job will be executed immediately. To use the Inline set the queue_adapter config to
:inline
.”
Interesting! So, if running a job inline
means that it happens right away, running a job that is not inline means that it will be delayed in its execution – that is to say, it won’t happen immediately, but it’ll happen later on. So the next logical question, then, is why?
After doing some digging, the best explanation I’ve found for why we’d want to run a process not inline but rather in the background, at a later point, comes from Ryan Selk. I really like the way that he explains the thought-processes behind choosing when to use a background job:
“One common situation for needing background jobs is consuming external APIs. It is unrealistic to think that all of your external APIs will have 100% uptime. By allowing API interaction to happen in a background job we can manage failures more effectively. Instead of having the user wait for a task to end, we send that task to the background queue. The User can then continue interacting with the app. Background jobs also give us the opportunity to prioritize jobs which are waiting in out background job queue. In many cases using background jobs can significantly reduce the required resources of the app.”
Ultimately, it all comes down to waiting. If there is ever a situation where your application would have to wait for a process – an email to send, a request to complete, or a response to be received – that’s a sign that you probably should be using a background job, rather than an inline process. In his blog post, Ryan talks about using 3rd party APIs, or performing some form of “computation intensive work, such as solving equations or image processing”; basically, anything that would require enough time or effort to make our application lag or to keep our user waiting would be a prime candidate for a background job.
So, let’s implement a job using Active Job…that’ll be easy, right?
When Active Job was first introduced, one of its most impressive aspects was the fact that you could easily create a job and then later specify the job runner that you wanted to use. Active Job was essentially built to be its own mini-framework, which made it incredibly useful for declaring a job, and then making it run on any backend that you wanted (for example, delayed_job
or resque
). This also meant that it became super easy (think changing a single line in our application) to switch between different queuing backends. An important thing to remember is that Rails itself doesn’t have a job runner; by default, it comes with an “immediate runner” queuing implementation, which means that each job that is enqueued will run immediately (in other words, it will run inline
).
Setting up Active Job is incredibly easy, which is another thing that makes it so beautiful. It comes with a generator, which means that we can run a simple command like this to create a job that would send a newsletter to new users of our application:
♥ bin/rails g job new_user_newsletter
Of course, we could also just create our own file inside of app/jobs
, as long as it inherited from ActiveJob::Base
. But let’s hold off on writing a complex job for now. Let’s try to first get Active Job to work with ActionMailer and send our order confirmation email via our OrderMailer
for today.
The first thing we need to do is to choose a queuing backend. I’ve found delayed_job_active_record
to be a pretty good starting point, so we can add that to our Gemfile
and run bundle install
. This backend also requires two additional forms of setup: first, a migration that sets up Job
objects in Active Record. We can run these commands easily in our terminal:
1 2 |
|
And secondly, inside of our config/application.rb
, we’ll need to set our queue_adapter
configuration to use delayed_job
rather than be set to inline
processes:
config.active_job.queue_adapter = :delayed_job
This last part is very important, as the documentation explains that Rails doesn’t have it’s own queuing adapter:
“Rails itself does not provide a sophisticated queuing system and just executes the job immediately if no adapter is set.”
Without setting up our queuing backend, Active Job won’t know what to use to send our email. And speaking of emails, it’s finally time to integrate Active Job with ActionMailer!
Active Job is neatly integrated with ActionMailer so that we can easily send emails outside of a single request-response cycle (in other words, asynchronously). There are two methods that exist on the ActionMailer module that we can use. In fact, we already started using one last week: deliver_now
.
Inside of our Order
class, we were using deliver_now
to send a confirmation email that was written inside of our OrderMailer
. We probably both need a refresher, so here’s the code that uses our favorite thing ever: a state machine!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
If we instead change our send_confirmation_email
to use deliver_later
, we can send our order confirmation email through Active Job, rather than sending it inline, within the same request-response cycle. All of this magic is built into the deliver_later
method. In fact, if we take a look at the source code for Action Mailer, we’ll learn that there are actually two different types of deliver_later
methods: deliver_later
and deliver_later!
. They’re both similar in that they both enqueue our email to be delievered through Active Job.
However, when deliver_later!
is invoked, it relies on deliver_now!
, which delivers an email without checking perform_deliveries
and raise_delivery_errors
. But, because deliever_later!
depends on deliver_now!
, which in turn bypasses these two important methods, deliver_later!
it will never, ever raise any errors. The documentation suggests that we use this particular method with caution, so if you’re unsure, it’s probably best to stick with plain old deliver_later
.
Integrating ActionMailer with Active Job is probably the easiest way to start using background jobs. But there are a lot of other ways to implement Active Job in our applications! Now we know enough to start writing our own custom jobs that will run asynchronously! In fact, that’s exactly what we’ll do next week, in part 2 of this series. Get ready to become an Active Job boss and walk around like this:
deliver_later
method in order to integrate with ActionMailer.There’s one thing that everyone loves: getting mail! But there’s one thing that all developers would rather avoid: sending mail. Unfortunately, this paradox perfectly describes the joys and horrors of getting your application to send a single email.
I recently worked on building out a password reset feature for one of our applications. In order for this feature to work, I had to figure out how to get my Rails application to send an email to our user with a password reset token in case they had forgotten their password. I thought that handling the authentication and token aspect of this would be complicated, but it turned out that learning about mailers was the more fun part. I had never actually worked with Rails mailers before, and honestly, I thought that I was in over my head (this also might be partly attributed to the fact that I had just come back from a two-week vacation and felt like I had completely forgotten how to code).
So, I did what any developer would do: I cried and went home. Okay, okay, I’m just kidding! What I actually did was read through the documentation, play around with my application and, in the process, taught myself how to use Rails Action Mailer. I never thought that I’d say this but, getting that feature to work and seeing that email pop up was incredibly exciting. In fact, I don’t think I’ve ever been more excited about sending and receiving an email. But don’t let me tell you how thrilling it was — let’s create our own mailer and experience it together!
Rails has a wonderful built-in mailing system called Action Mailer, which allows us to send email from our application as long as we have a mailer model. Mailers are actually a lot like controllers: they have their own app/mailers
directory, and each mailer has its own associated view as well. Each mailer also inherits from ActionMailer::Base
, and just like controllers, can be generated really easily.
For our bookstore app, we won’t start off with anything too fancy just yet. Instead, let’s stick with a simple mailer that will be responsible for one little thing: sending an order confirmation email whenever a user successfully places an order (did your mind immediately jump to using a state machine? I hope so!)
To start, we’ll use Rails to generate a mailer:
♥ bin/rails generate mailer Order
Running this command in the terminal generates a few different files for us. We now have an app/mailers
directory, with an order_mailer.rb
and application_mailer.rb
file. It also generates three files inside of app/views
: order_mailer
, layouts/mailer.text.erb
, and layouts/mailer.html.erb
, as well as test units for our order mailer (order_mailer_test.rb
).
Depending on how many mailers this application will have, it might not makes sense to generate all of these files. If we decided to manually create our mailer rather than generating it, we’d need to keep one thing in mind: our mailer must be a file inside of the mailers
directory, and it must inherit from ActionMailer::Base
(unless, of course, we wanted to use a mailer from another library, such as the Devise::Mailer
from the devise
gem).
The mailer model has methods defined on it that allows us to actually specify how and where an email is sent. Right now, however, our mailer models look pretty empty! Inside of our generated ApplicationMailer
, the only setup we have is our layout configuration and our from
address:
1 2 3 4 |
|
While our order_mailer.rb
is completely empty:
1 2 |
|
Since mailers are so much like controllers, we can approach writing them in a similar way. The first thing we’ll do is write some actions. Just like with controllers, we want our methods to adhere to the single-responsiblity principle, which means that they should be handling only one thing at a time. We’ll start by writing a confirmation_email
method, which will take an Order
object as its parameter.
1 2 3 4 5 |
|
Just like in controllers, any instance variables that we define in our method — in this case, @order
— become available for us to use inside of our views. This will be important when we want to render the user’s information via our @order
instance. But…we’re not actually mailing anything right now, are we? Of course not! In order to actually create our message and render our email templates, we need to use the mail
method.
The mail
method is defined on ActionMailer::Base
(hence why every mailer should always inherit from it so that it has access to this very crucial method). If we look at the documentation for this method, we can see that it accepts a headers hash, which is where we can specify the most-used headers in an email message. Some of the options we can pass in include subject
, to
, from
, cc
, and date
, among others. For now, we’ll just pass in a to
option and a subject
option:
1 2 3 4 5 6 7 |
|
If we wanted to get really fancy, we could specify default
values for any of these headers (except for date
) inside of our OrderMailer
class. Alternatively, we could also write our mail
method as a block, which would allow us to render specific templates — a piece of functionality that might be nice as we add more methods to this mailer over time. We could also use the block syntax in order to render plain text directly without using a template, which would look something like this:
1 2 3 4 |
|
But let’s hold off on all these bells and whistles. Let’s just get this method into our state machine and actually send this bad boy.
Now for the fun part: sending and receiving our mail! There are two methods we can use to send an email: deliver_now
and deliver_later
. The former sends our email inline (in the same request-response cycle), while the latter sends emails in the background by integrating with Active Job.
We already wrote our confirmation_email
method, so now we just need to invoke it. But, we defined it on our mailer class. However, we don’t need to instantiate a new instance of our OrderMailer
class (like we would have to do with a service object, for example). Instead, we can just call our confirmation_email
method on our mailer class directly. Since brevity is the soul of wit, here’s a truncated version of the state machine in our order.rb
file, which is where we’ll invoke this method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
You’ll remember that our confirmation_email
method takes an Order
as a parameter, which is why we’re passing in self
, the Order
object, into the method, before chaining on deliver_now
at the end of it. Now, after our completed
event is called, this email will be sent. But how do we know what our email will say, exactly? Well, we can head over to our email templates to find out.
When we generated our mailer, one of the files that was generated was app/views/layouts/mailer.html.erb
. If we take a look inside of this file, we’ll see that it’s pretty simple; in fact, all it’s going to do for now is yield
to whatever template needs to be rendered. If we wanted to add styles or formatting that would apply to all of our mailers, this is where it would go:
1 2 3 4 5 |
|
For things pertaining specifically to our OrderMailer
template, we’ll need to visit the view for that mailer, which will live inside of app/views/order_mailer/confirmation_email.html.erb
. We can again think of how controllers work with their associated views (for example, an index
action corresponds to an index.html.erb
file). Similarly, our OrderMailer
class knows about its own specific view because its name is the same as the mailer’s method (confirmation_email
). This is where we can put the text for our email template; for now, it won’t be anything too special and will just use our @order
instance from the confirmation_email
method we wrote in the OrderMailer
to retrieve and render the order number and user’s email:
1 2 3 |
|
Awesome! Now, in development, we can test this out by placing an order, triggering the send_confirmation_email
method in our state machine, and using our OrderMailer
to send an email in a sychronous request to our user’s email address. That’s a lot to do, but we made it happen!
Before we get too email-happy, here’s a thought: how much do you really like email? I don’t know about you, but I would really rather not get an email every single time I test out my mailer in development. Thankfully, there’s a gem that was created to solve precisely this very problem: letter_opener
.
This gem intercepts our mailer and allows us to preview an email from within our browser instead of actually sending the email to an email address. One of the great benefits of this — in addition to both saving space in our inbox and not having to set up email delivery in our development environment — is us not having to worry about sending test emails by accident to someone else’s email address!
Adding letter_opener
to our application is pretty easy, and the documentation is easy to follow. First, we’ll add the gem to the :development
group in our Gemfile
:
gem "letter_opener", group: :development
After we run bundle install
in our terminal, we’ll need to do one last step: setting up our mailer configurations. Basically, all this means is that we need to specifically set up our development environment such that it will use our letter_opener
gem as its delivery method. In fact, that’s pretty much the only line we need to add in our config/environments/development.rb
file:
config.action_mailer.delivery_method = :letter_opener
The delivery_method
acepts a delivery method object and defaults to :smtp
. Since we want letter_opener
to handle our mail deliveries, we’ll just set our delivery method on Action Mailer to the gem that we want to use.
Now that we’ve set this up, any email that is sent by Action Mailer will be intercepted and open up in a new tab in our browser, rather than actually being sent to an email address. These files will be stored temporarily in tmp/letter_opener
.
But as lovely and helpful as it is to have all these test emails popping up in our browser, there’s one thing that would be even nicer to have: all of these emails being triggered outside of the request-response cycle. In other words, what we want to do is to run these requests asychronously. Well, what does the documentation say about making this happen?
“Active Job’s default behavior is to execute jobs
:inline
. So, you can usedeliver_later
now to send emails, and when you later decide to start sending them from a background job, you’ll only need to set up Active Job to use a queueing backend (Sidekiq, Resque, etc).”
Okay, it sounds like we need to learn a little bit about Active Job and set up a queueing backend to send our emails in a job. But let’s save that for another blog post. Tune in again next week, when I’ll delve into the basics of Active Job and asychronous processes. Until then, have fun opening those emails!
ActionMailer::Base
, and work just like controllers, with actions and corresponding views. Check out this fantastic post on sending emails using Action Mailer to dive into the details.ActionMailer::Base
. Read more about them over here.Words are pretty important. But do you know what’s more important than words? Grammar. (Can you tell that I was an English major?) Despite how big of a book nerd I am, there’s acually a crucial reason as to why we should keep things like grammar in consideration: convention.
At it’s very core — pun totally intended — the Rails framework is based in conventions. We rely on the framework to create our models, controllers, and views in a specific file structure, and for them to be named in a certain way. But what we often forget is that we also rely on Rails to be smart enough to handle strange edge cases, like knowing that a mice
table should store the Mouse
model objects, and that the MiceController
should be responsible for passing those objects back and forth!
It all seems pretty automagical. But we have to keep in mind that it was the Rails core team that created and established these conventions, which means that they’re not magic — they’re just code! And as much as we can rely on preexisting Rails conventions, there might be times that we need to tweak our code to abide by those conventions. And because computers are not people (and because English is a crazy language with so many strange exceptions), we’re probably going to run into a roadblock when dealing with grammar naming conventions. Thankfully, there’s a great tool to help with this problem: the Rails Inflector, also known as every grammar nerd’s dream.
The Rails Inflector is actually a part of the ActiveSupport module, which is truly a beast of a module, and probably warrants a few blog posts of its own. The tl;dr version of ActiveSupport is this: it provides a bunch of different patterns to transform simple Ruby strings. The inflector library in particular is responsible for handling the pluralization of different strings.
An important thing to note about the inflections library is that it’s pretty much set in stone. According to the documentation, these rules are never going to change so that Rails can remain backwards-compatible for older applications:
“The Rails core team has stated patches for the inflections library will not be accepted in order to avoid breaking legacy applications which may be relying on errant inflections. If you discover an incorrect inflection and require it for your application or wish to define rules for languages other than English, please correct or add them yourself.”
Basically, what this means is that Rails provides us with some basic inflections; however, if we want to create our own custom grammar rules (or if we notice something that’s incorrect), we have to write our own inflections for our application. It’s also worth noting that if we want to create models that are not English words, we’d need to write our own pluralize rules for those as well. But before we go about writing completely new inflections, let’s first see what inflector methods we have available to us!
The ActiveSupport::Inflector
module has a handful of public instance methods that are available for us to use. In fact, when I was first learning Rails, I played around with these methods in irb, but didn’t really know (much less understand) where they were coming from. But it turns out that the Inflector methods can be super useful! Here are some of my favorites:
humanize
This method is great for displaying an attribute name to end users. It deletes any leading underscores, replaces underscores with spaces, downcase all words (except acronyms), and capitalizes the first word. Basically, it makes your attributes human-readable, which can be helpful for displaying an error message to your user:
1 2 3 4 |
|
titleize
The titleize
method is pretty perfect for our bookstore application. It capitalizes all the words and replaces underscores with spaces:
1 2 |
|
Protip: this method is also aliased as titlecase
.
parameterize
This method replaces special characters in a string so that it can be used in a URL (think sluggable names with hyphens):
1 2 |
|
singularize
The singularize
method does exactly what you think it would do: it returns the singular form of a word in a string:
1 2 3 4 |
|
pluralize
And the pluralize
method does the opposite things: returns the plural form of a word in string format:
1 2 3 4 |
|
There are tons more Inflector methods that are very well-documented. In fact, there are so many great methods that you might be thinking to yourself, why would I ever have to write my own methods?
Well, what if we wanted Specimen
objects, which needed to be pluralized as Specimens
. We could assume that Rails will handle that for us…or we could double-check:
1 2 |
|
Oops! It seems like the predefined inflections are taking hold here and parsing “men” as the plural form of “man”, like we saw earlier. You know what this means…time to write our own inflections!
One of the coolest public instance methods of the `ActiveSupport::Inflector
module is the method that allows us to specify our own inflector rules. This method is appropiately named inflections
, and it does some interesting things.
The inflections
method yields to a singleton instance of ActiveSupport::Inflector::Inflections
. It can be passed an optional locale, which is how we could write inflection rules for other languages; the default locale is English (specified as the argument :en
).
We can write our own inflections inside of the config/initializers/inflections.rb
file. This file actually already exists and will look like this when we first open it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
We can already see how to go about writing our inflections with the examples in this file, including some of the methods we can use, depending on what our edge case is. There are actually a lot of methods available to us inside of our inflections block, some of the most helpful being plural
, singular
, uncountable
, and irregular
. In our case, we’re dealing with an irregular inflection wherein specimen
needs to be pluralized as specimens
, so we’ll use the irregular
method, which takes two arguments: the singular and the plural form of the word as strings.
1 2 3 |
|
Awesome! Now our entire application will know about this inflection rule. And the really great thing about this is that our new rule that we just wrote is added at the top of this file, which means that our irregular rule for specimen
will be the first of the singularization and pluralization rules that is run. This ensures that our rules will always run before any of the preexisting rules that come with ActiveSupport::Inflector
.
Whew — that was quite an inflection adventure! But now the next time we have a grammar mistake, we can fix it easily, just like this slightly strange puppet (is a gopher? A beaver? I don’t know!) keeps telling us to do:
ActiveSupport::Inflector
handles a lot of the grammar rules in Rails. The inflections.rb
file is where we can write our own inflection rules. Check out all the preexisting inflections in the Rails source code.inflections
.I recently went down a little bit of rabbit hole in order to do some digging on database transactions. And when I say “a little bit”, I mostly mean “a lot bit”. I opened up the Rails source code for ActiveRecord::Transactions
, and I saw some interesting terms I hadn’t seen in awhile.
Back when I was first learning Ruby a year ago, I remember reading about keywords. At the time, the only thing that really set them apart for me was the fact that they had special syntax highlighting in my text editor! (Yes, really.) But when I saw them again in the Rails source code, I thought it would be time to get a quick refresher on a few keywords that I saw again and again.
But first: what are keywords, exactly? Well, they’re definitely not objects, but instead are reserved words, which are actually defined in the Ruby parser. In fact, there’s a whole slew of keywords in Ruby, but the ones that I’m the most interested in sharing with you are begin
, end
, ensure
, and rescue
. So let’s start unlock the door to Ruby with these keywords!
The begin
and end
blocks are and interesting way of defining a bunch of code that needs to run on it’s own, in its own context. Between the begin
and end
keywords, we can put all the code that we need to run on its own. Just like with normal methods, whatever is the last expression that is evaluated in the begin end
block is the result that will be returned.
1 2 3 4 5 |
|
Interestingly, the def method_name end
keyword syntax of defining a method is also nothing more than a begin end
block! I think that this RubyLearning tutorial explains this pretty well:
“It is to be noted that the body of a method definition is an implicit begin-end block; the begin is omitted, and the entire body of the method is subject to exception handling, ending with the end of the method.”
So, if the begin end
syntax is just like writing a regular Ruby method, when would we ever use it? Well, it turns out that the begin end
block can be helpful for defining chunks of code that need to execute in a certain order. For example, if we wanted to write a method that would split a group of Book
objects into various batches, we might have something like this:
1 2 3 4 5 6 7 |
|
What we’re trying to do here is twofold: first, we want to calculate our BookBatch
based on some attributes (batch_attrs
) that we’re passing in, and then create
it. And once we’ve done that, we want to update
it.
We’re always going to want to create
our BookBatch
if it doesn’t already exist, definitely before we go about updating it. We can use the begin end
syntax to do the same thing:
1 2 3 4 5 6 7 |
|
In this case, if a @batch
instance doesn’t already exist, the code between the begin end
will run and then the return value (a new BookBatch
instance) will be assigned to the @batch
instance variable. Only then will the @batch.update
line be run.
It turns out that this kind of method architecture takes advantage of the Ruby interpreter’s stack. The ||=
assignment that we are using before the begin end
block just takes the last thing from the stack (in this case, BookBatch.create
), and assigns it to @batch
. Because the code in the begin end
block runs independently in its own context, we can use it to contain and encapsulate a bit of logic. This is especially helpful if we want to rescue
from an error!
The rescue
keyword is pretty cool, and is used by Rubyists quite a lot. It functions to handle exceptions, and takes a single argument: the class/type of error that you want to rescue from.
1 2 3 4 5 6 7 8 9 10 |
|
One important thing about rescue
: it’s always written at the same level as our method signature! In the example above, we have written our own raise_book_batch_error
method, which will handle the exception once we’ve recused from this method. We can pass a specific type of error, or we can allow rescue
to default. If you don’t pass any parameters to the rescue
clause, it defaults to StandardError
and will rescue any error by default.
Another important note about rescue
is that is occurs at the same level as our method signature. So, if we want to rescue
from our create_or_update_batch
method, we need to have rescue
on the same level as def create_or_update_batch
. We could also rescue from inside of a begin end
block:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
In this case, the rescue
clause inside of our begin end
block will rescue any exceptions in its own context. It’s also important to note that only one rescue
clause of a group will ever be executed.
All of these blocks can start to be a little much after awhile. Sometimes, all you want to do is make sure that a specific piece of code will always run! Luckily, that’s what the ensure
keyword is for. This keyword starts a section of code that is always run when an exception is raised. And just like rescue
, it’s written at the same level as our method’s signature.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
In the example above, we’re ensuring that even if a BookBatch
was created and didn’t get associated in the correct way and was orphaned, the clean_up_orphaned_book_batches
method would always run. A good way to think about the ensure
keyword is that its the last thing that will run in the method, and it will run no matter what, every single time.
The unique thing about ensure
is that it runs even if there were any errors that were raised. The best practice is to usually put ensure
at the end, so that the last part of the method will run.
The begin
, end
, rescue
, and ensure
methods are a little tricky to understand all together. But once we break them apart and figure out how they work on their own, things start to make a little more sense. Hopefully, diving into the rabbit hole of the Rails source code will be a little easier now. At the very least, we now have the keys to the wonderful world of Ruby keywords!
begin end
block can be used to execute a block of code in a specific context. Rescue
can be used to handle errors, while ensure
will always run at the end of a method. The Ruby documentation has the complete list of Ruby keywords, and it’s clearly and thoroughly written. Check it out over here!begin
and end
, and how to use them in the context of a method.ensure
works in the context of an application? Here’s a blog post that dives into exactly that!Is there anything more satisfying than writing concise, perfect line of SQL and then watching it query your database exactly as you expected? Probably not. Writing — and subsequently watching! — an efficient database query is one of my favorite parts of building an application.
But if there’s one thing about software development that I’ve learned over the past few months, it’s this: projects can get out of control, rather quickly. You start off with your basic models, but then as you add one feature after another, things can start to get out of hand. At that point, your focus as a developer shifts and spreads out to various things. You can’t just care about how readable your code is; you also have to consider how efficient it is, and how different units of your application might be breaking other parts (hopefully not unbeknownst to you!). In other words, you have to consider how defensive and safe your code actually is.
Recently, while writing some background jobs and creating some service objects for a new feature, I realized the importance of executing and enforcing safe code. The good news is that there’s a really helpful, life-saving ActiveRecord transaction method that allows you to do exactly this. And the really great news? You get to watch your SQL queries execute safely as a result!
As our application grows, there are inevitably going to be different models that depend upon each other. To make things more complicated, those models are going to have to change as our Users take different actions, and that means that we’ll need to update different associated parts of our schema as a result. For example, let’s say that we have a background job that’s responsible for processing an Order
on an User
. This background job has a service class that takes care of saving an Order
when it has been charged, billing the User
, and adding a sale to an Vendor
object, which will then be visible on the vendor’s dashboard panel/admin page.
1 2 3 4 |
|
In other words, we’re basically transferring money from our User
object to our Vendor
objects. At first glance, this might not seem like a potentially “unsafe” set of queries, but here’s where things can get a bit tricky: imagine that our User
’s credit card information is rejected, or for some reason, the charge cannot be created. In that scenario, we’d want to handle the errors and make sure that the add_sale
method is not called on our Vendor
object. However…we aren’t really safeguarding our code against this situation at all, are we?
But, fear not - it’s not a totally hopeless situation! In fact, we can take care of this problem pretty easily by using ActiveRecord’s transaction
blocks.
The transaction
method is defined in the Rails source code under the ActiveRecord::Transactions
module. This method takes a block, and whenever it is invoked, the block that is passed to it will be executed inside of a database transaction. If, in the course of executing that block, an exception
is raised, the database transaction will automatically be rolled back. No SQL will be executed, and no new data will be added to the database
1 2 3 4 5 |
|
So what does this mean, exactly? Well, now that we’ve wrapped the logic of our three methods inside of a transaction
method, we can safely assert that in the case that any of these three methods raises an exception
(in other words, fails for any reason), the entire process should fail.
The important piece of this is that we’ll never be adding or updating any data (or writing to our database) unless all of these methods are successful. It’s crucial for us to ensure that this is the case because we’d never want to call the add_sale
method and write data to our vendor
if the order
didn’t successfully process
, or if our user
wasn’t successfully charged
.
I like to think of these blocks as a “handshake” between your application and your database: your application and database have an understanding that one will hand off information to the other in a “transaction”, and when the deal actually goes through, they shake hands and make it official…or something more poetic. If that made no sense — or if you’re not a big fan of metaphors — here’s how the Rails documentation explains transactions
:
“Transactions are protective blocks where SQL statements are only permanent if they can all succeed as one atomic action. Transactions enforce the integrity of the database and guard the data against program errors or database break-downs. So basically you should use transaction blocks whenever you have a number of statements that must be executed together or not at all.”
Because ActiveRecord transactions can be easily explained and simplified as a single method, it’s easy to forget the idiosyncrasies that make this method work. There are a few things to keep in mind so that we can get the most out of these blocks.
A transaction opens up a single database connection. This means that when we call the transaction
method, the method can only be invoked on the current database connection. This is important to remember if our application writes to multiple database at once; for example, if our Order
and our Vendor
data lived in two different databases, we’d need to nest our transactions:
1 2 3 4 5 6 7 |
|
It’s generally a good idea to avoid nested transactions, mostly because the relationship between parent and child transactions can get complicated. This is especially the case because rollbacks are contained inside of their transactions blocks. I think that Mark Daggett explains this pretty well in his blog:
“ActiveRecord::Rollback does not propagate outside of the containing transaction block and so the parent transaction does not receive the exception nested inside the child. I find it easier to think of nested transactions like the child who dumps its contents into the parent container, leaving the child transaction empty. To ensure a rollback is received by the parent transaction you must add the
requires_new: true
. option to the child transaction.”
Because transactions are bound to database connections, we can mix different types of models inside of a transaction
block. In fact, that’s exactly what we were doing when we wrote our initial transaction:
1 2 3 4 5 |
|
The great part about transaction
is that it is available to us as both a class and an instance method for our ActiveRecord models. What does this mean, exactly? Well, the short answer is that we can write a transaction is lots of different ways, since we can invoke the transaction
method on a class or an instance.
For example, we could have written this:
1 2 3 |
|
Or this:
1 2 3 |
|
Or any of these:
1 2 3 4 5 6 7 8 |
|
And if we were writing a method inside of the Order
, Vendor
, or User
classes, these options would have worked as well:
1 2 3 4 5 |
|
The key here is that the transaction
can be called on any class that inherits from ActiveRecord::Base
. Why is that the key? Well, you might remember that we initially started off wanting to write a transaction inside of our service object…right? In that case, we can’t use something like transaction do
, because self
is the service object class, which does not inherit from ActiveRecord::Base
!
So, what do? Well, just call the transaction method onto ActiveRecord::Base
directly! there’s a quick fix for that.
1 2 3 |
|
When in doubt, we can always just call the transaction
method onto the ActiveRecord::Base
class directly to be sure that it will run.
There’s one golden rule of the transaction
block: it will only rollback the transaction if an error is raised.
Why is this important? Well, calling something like save
or destroy
inside of a transaction will not raise an error; if something goes wrong, these methods will simply return false
. Which means that our transaction
block will continue, since there was no error raised!
Uh oh…how to fix? Just use the save!
and destroy!
methods instead! These are both ActiveRecord methods which raise an exception if they don’t execute successfully:
1 2 3 4 |
|
And that’s exactly what we need in this case, because we want the entire transaction to be closed if one or both of these methods are unsuccessful, and we want to tell the database that no data has changed. If we really, really wanted to use save
instead of save!
, we’d have to manually raise
an error in the block for our transaction to work as expected.
One of the interesting things about how transaction
works under the hood has to do with how the save
and destroy
methods work. It turns out that Rails actually wraps the save
and destroy
methods in their own transaction
s! So, we were using ActiveRecord::Base.transaction
all along, without probably ever knowing what was really happening! Pretty crazy, right?
There are a couple reasons that save
and destroy
are particularly curious. First, because they each occur in their own transactions, this means that we’ll never need to write a transaction
block to update a single record. In fact, that’s exactly what Rails is doing for us when we call something like @user.save
— it’s running a transaction
block behind the scenes.
The second reason this is interesting is because of callbacks that are associated with these two methods. A callback hook like after_save
is actually part of the same active transaction that was opened when we called @user.save
. So, if we wanted our code to execute outside of Rails’ default transaction
that wraps around save
or destroy
, we’d want to use callback hooks like after_commit
or after_destroy
. If we want something specific to happen when the save
transaction
succeeds, we’d have to use the after_commit
callback, and if we want something specific to happen when the save
transaction
fails, we could use the after_rollback
hook.
While reading about transactions and the save
and destroy
methods, I discovered another really interesting method called with_transaction_returning_status
. The transactions source code is a bit of a rabbit hole, but if we spend some time reading through it, there’s a lot to learn.
In a nutshell, the with_transaction_returning_status
is responsible for actually raising an ActiveRecord::Rollback
. Somewhere inside of the black box of Rails magic, when we see an error caused by a save
transaction that looks like this:
1 2 3 4 5 6 |
|
it’s actually a method like with_transaction_returning_status
that’s responsible for causing that rollback to happen! Here’s a truncated example of the source code; we can see that this method defines a local status
variable, sets and returns the status
if the transaction
is successful, and raises
an error, if the status
is not defined:
1 2 3 4 5 6 7 8 9 10 11 |
|
The Rails documentation also briefly explains exactly what’s happening:
Executes
method
within a transaction and captures its return value as a status flag. If the status is true the transaction is committed, otherwise a ROLLBACK is issued. In any case the status flag is returned.
Transactions are all around us, it seems, from the most everyday methods to the more complicated ones that we write ourselves. They’re a great way of keeping our code safe while also defending against things like duplicate SQL queries.
transaction
method takes a block, and will only execute the block and write to your database if no exceptions are raised.transaction
method on any class that inherits from ActiveRecord::Base
, and that transaction will open up a single new database connection.