Rails 5: what’s new

Test runner, where.or, new test request API, Render From Anywhere and no more alias_method_chain

Kir Shatrov
Evil Martians
Published in
5 min readApr 7, 2015

--

We’ve moved! Check out this post — and other posts by fellow martians — on our new blog, Martian Chronicles!

I’ve found a great post regarding the upcoming changes in Rails 5 by Jeroen van Baarsen, and you should check it out if you’re interested in Rails Edge developments.

However, I felt like this post is just not enough since there are so many interesting things in the upcoming Rails 5 release. So here goes my very own “yet another review of Rails 5 features”.

Note: This post was written before the RailsConf ActionCable/Turbolinks announces. To see our overview of RailsConf 2015 and our thoughts about the new features, check this post: RailsConf 2015 Recap and Thoughts.

Rails Test runner

The new runner is, in fact, my favourite piece of Rails 5. I love minitest, and I always was a bit envy of RSpec users, as they have a great runner that allows you to specify the file and line number of a failing spec.

Now, thanks to Yves Senn, we have the same feature when using Rails’ minitest:

$ bin/rails test test/models/post_test.rb
Run options: — seed 48587
# Running:..FF.Finished in 0.024376s, 205.1198 runs/s, 287.1677 assertions/s.1) Failure:
PostTest#test_failling_one [test/models/post_test.rb:32]:
Failed refutation, no message given
2) Failure:
PostTest#test_has_likes [test/models/post_test.rb:23]:
Failed assertion, no message given.
5 runs, 7 assertions, 2 failures, 0 errors, 0 skipsFailed test:rails test test/models/post_test.rb:32
rails test test/models/post_test.rb:23

At the bottom of this output, you can see the runner suggesting commands to execute only the failing samples line by line.

ActiveRecord::Base#where.or

Previously, to use `OR` conditions with the ActiveRecord query builder, we had to construct the query manually by using Arel:

User.where(users[:name].eq(‘bob’).or(users[:age].lt(25)))

In 2013, Rails 4.0 introduced `where.not` chain method in ActiveRecord, and now in 5.0 we finally have `where.or`:

Post.where("id = 1").or(Post.where("id = 2")) # => SELECT * FROM posts WHERE (id = 1) OR (id = 2)

belongs_to is required by default

DHH wrote that almost every `belongs_to` declaration seemed to be a required association. Later, @simi implemented it.

However, if your `belongs_to` association is not required, you could use the `optional: true` option:

class User
belongs_to :org, optional: true
end

ActiveRecord::Base#has_secure_token

Do you use the `has_secure_password` option introduced back in Rails 3.1?

From now on, for fields like subscription token, we have `has_secure_token`:

class User < ActiveRecord::Base
has_secure_token :token1, :token2, key_length: 30
end
user = User.new
user.save
user.token1 # => “973acd04bc627d6a0e31200b74e2236”
user.token2 # => “e2426a93718d1817a43abbaa8508223”
user.regenerate_token1! # => true
user.regenerate_token2! # => true

No more alias_method_chain

`alias_method_chain` method was there since the very early Rails versions and it was used all over the Rails code base and by various gems.

It was widely used to monkey patch or tweak any previously declared method:

class ActionController::Base
# overriding ActionController::Base load from gem
alias_method_chain :params, :patched
def params_with_patched
result = params_without_patched
# we can access and modify the result here
result
end
end

But now, with `Module#prepend` available since Ruby 2.0 we can use native Ruby features to achieve the same result:

module PatchedParams
def params
result = super
# we can access and modify result here
result
end
end
ActionController::Base.prepend(PatchedParams)

In Rails 5, `alias_method_chain` will be deprecated in favor of the native Module#prepend.

Read more about alias_method chain here:

Keyword arguments in controller & integration tests

Here is an example snippet you could find in a controller test:

get :index, { id: 1 }, nil, { user_id: 1 }

Does it make a lot of sense what every argument means exactly? Not much, so I proposed the new syntax with keyword arguments support for request methods:

post :create, params: { y: x }, session: { a: ‘b’ }
get :view, params: { id: 1 }
get :view, params: { id: 1 }, format: :json

These changes apply when using any test framework — it doesn’t matter if you use RSpec or Minitest. The old syntax works as well, but it’s considered deprecated and will be removed later in Rails 5.1.

Render From Anywhere

Earlier we had to use gems like render_anywhere to render any views outside of controller — for example in Rake tasks or background jobs.

In Rails 5 you’ll have the ability to render your views from anywhere:

ApplicationController.render _render_options_

Besides the usual rendering options, in Rails 5 there is a new `assigns` option for passing instance variables to templates.

Hope you like these new features. We will try to review more of them as we come closer to Rails 5 release candidates.

A great way to stay in touch with Edge Rails development is to subscribe to This week in Rails to receive weekly e-mail with scoop of interesting commits, pull requests and other stuff that is happening with Rails Core.

--

--

Kir Shatrov
Evil Martians

Production Infrastructure @ Shopify, ex-Evil Martians. Around-the-world traveller. Rails committer