The Lesser-Known Features in Rails 5.1

Last week, during RailsConf 2017, Rails 5.1 shipped.

If you followed the announcements, you’ve seen the big features: better integration with modern JavaScript, encrypted secrets, and system tests. And there’s my personal favorite: finally getting rid of the weird combo of form_for and form_tag, and replacing it with form_with. I can’t wait to try it.

But the reason I love Rails isn’t the big new features. It’s the little, constant improvements. It’s those quality-of-life changes that make me happier when I’m writing Rails apps. And Rails 5.1 is full of them.

More consistent tag helpers

Have you used Rails’ tag helpers, like tag and content_tag?

<%= content_tag :p, @user.name, class: "name" %>

Rails 5.1 adds a new tag helper syntax.

Use calls like tag.div or tag.br, and you can stop worrying about parameter order and juggling two different methods:

<%= tag.p @user.name, class: "name" %>
<%= tag.br %>

These new tag helpers support HTML5 by default, and even let you create your own elements:

<%= tag.pea @user.name, class: "name" %> 
<!-- turns into <pea class="name">Justin Weiss</pea> -->

Assert more than just differences

I love assert_difference. Before assert_difference, I spent way too much time juggling local variables in tests:

old_score = @user.score
@user.answer_question!(...)
assert_equal old_score + 10, @user.score

With assert_difference, it’s much clearer what you’re trying to do:

assert_difference "@user.score", 10 do
  @user.answer_question!(...)
end

In Rails 5.1, assert_changes takes this one step further.

assert_difference only checks changes in count. But assert_changes can check non-numerical changes, like changes between two strings, or between nil and something else:

assert_changes "users(:justin).name", from: "Justin", to: "Bob" do
  @user.update_attributes(name: "Bob")
end

Instead of a string, you can give it a lambda:

assert_changes -> { users(:justin).name }, from: "Justin", to: "Bob" do
  @user.update_attributes(name: "Bob")
end

to: can be anything that compares with ===. That’s nice when you know something about the value, but don’t know what it is, specifically:

assert_changes -> { users(:justin).updated_at }, to: ActiveSupport::TimeWithZone do
  @user.update_attributes(name: "Bob")
end

Delegate everything

In some Rails code, you’ll see the delegate method used. Delegation is helpful when you want to add behavior on top of another class, without inheriting from it:

class Player
  delegate :id, :name, to: :@user

  def initalize(user)
    @user = user
  end
  
  def points
    Game.points_for_user(user.id)
  end
end

But sometimes you want to forward everything to the class you’re wrapping.

There are a few ways to do this with Ruby, using method_missing or SimpleDelegator. But to better match the delegate method, delegate_missing_to was added to Rails 5.1. It does exactly what it says:

class Player
  delegate_missing_to :@user

  def initalize(user)
    @user = user
  end
  
  def points
    Game.points_for_user(user.id)
  end
end

Now, any call to a method that’s not in the Player class will search on @user instead.

Bonus: alias_method_chain is gone!

One of my favorite features in Ruby 2 is Module#prepend. I liked it so much, I wrote a post about it. Specifically, about how I hoped Module#prepend would eventually replace alias_method_chain.

And as of Rails 5.1, alias_method_chain is now officially gone – replaced with prepend.


New versions of Rails are always exciting. But it’s the details that give Rails its beauty. The small changes that make you happier with the code you write every day.

How do you find those changes? Dive into the changelogs. Take a look at interesting pull requests. See which of the new, small, 5.1 features will make your life that little bit easier.

And when you find some cool stuff, don’t keep it to yourself. Share it here, so we can all learn something new!

Did you like this article? You should read these:

Finished another Rails tutorial and still don't know how to start?

Have you slogged through the same guide three times and still can't retain enough to write apps on your own?

In my free 7-part course, you’ll discover the fastest way to learn and remember new Rails ideas, so you can use them when you need them. And you'll learn to use what you already know to build your own Rails project.



Comments