Martian Chronicles
Evil Martians’ team blog
Back-end

Rails 5: What’s new

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

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 skips
Failed 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: { key: 'value' }
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.