Digging Into Rails 4
Rails 4 is rapidly approaching. In this article, let’s take a look at some of the new features that it offers, as well as the changes that may affect your current applications.
Some Bookkeeping
Cache digests are Rails 4′s solution for tracking the changes of aggressively cached templates.
There are several configuration and structural changes that comes with Rails 4.
Ruby >= 1.9.3
Rails 4 will only support Ruby 1.9.3+. Get ready for an upgrade if haven’t yet done so.
Threadsafe by Default
Rails 4 will be thread-safe by default, removing overhead and improving performance on threaded servers, like thin and puma. You need to ensure that your application (and its dependencies) are thread-safe, which typically means avoiding global state (e.g. class or global variables).
Aaron Patterson wrote and spoke about this subject. Definitely check those out!
No More vendor/plugins
Rails 3 embraced the idea of using gems to add custom functionality to Rails, and deprecated the use of plugins. Rails 4 completes this transition by removing the vendor/plugins
directory altogether.
New Testing Directories
The default test directory naming scheme is more clear than in Rails 3.
The following directories will now be generated: test/models
, test/helpers
, test/controllers
, test/mailers
, and test/integration
.
Executables
The script
directory has been removed in favor of a new bin
directory. This is where your app’s executables will live, and running rake rails:update:bin
will put bundle
, rake
, and rails
binstubs into your app’s bin
directory.
This change can be useful in development, especially on a machine with multiple Ruby versions and gems. You can use bin/rails
instead of bundle exec rails
to ensure you run your executables in the correct environment.
Strong Parameters
Rails 4 tackles the mass assignment problem with the new Strong Parameters gem. A Rails 3 application might have a create
action similar to the following example:
class UsersController < ApplicationController def create @user = User.create(params[:user]) # ... check validity, redirect, etc. end end
You can protect against unexpected input with declarations in the model:
class User < ActiveRecord::Base # Only allow the following attributes to be mass-assigned attr_accessible :name, :email end
Using Rails 4′s Strong Parameters gem moves user input into the controller:
class UsersController < ApplicationController def create @user = User.create(user_params) # ... check validity, redirect, etc. end def user_params params.require(:user).permit(:name, :email) end end
As you can see, the params
hash in your controller is not a normal hash. It’s actually an instance of ActionController::Parameters
, which exposes the require
and permit
methods.
The require
method ensures that the specified key is available in the params
hash, and raises an ActionController::ParameterMissing
exception if the key doesn’t exist.
The
permit
method protects you from unexpected mass assignment.
The call User.create(params[:user])
raises an ActiveModel::ForbiddenAttributesError
exception, but using User.create(params.require(:user).permit(:name, :email))
makes it work without complaint.
The Rails 3 mass-assignment functionality is not only disabled in Rails 4, but has been extracted to a gem, in case you require that functionality.
Turbolinks
Rails 4 will be thread safe by default, removing overhead and improving performance.
A controversial new feature in Rails 4 is Turbolinks, a JavaScript plugin designed to make app navigation faster in the browser.
In browsers with pushState
support, clicking a link causes the Turbolinks plugin to kick in. It makes an Ajax request, updates the URL with pushState
(so your back button works) and uses JavaScript to update the and
in the DOM. The speed gains come from not having to download and reparse JavaScript and CSS assets.
Turbolinks gracefully degrade for browsers which do not support pushState
. In these situations, the page’s links behave as normal—causing a full page refresh.
Events and Cache
It’s common in applications to wait for a page to completely load before executing any JavaScript. For example:
$(document).ready(/* some function to run */) { // or event just $(/* some function to run */) }
With Turbolinks, the page load events won’t fire when users navigate from “page” to “page” because the DOM never actually reloads. The library, therefore, adds new events that you can listen for, in order to perform any subsequent initializations that your app might need:
page:fetch
– starting to fetch a page from the serverpage:change
– a page has been loadedpage:load
– a page has been loaded from a server fetchpage:restore
– a page has been loaded from a cache fetch
The page:change
event always fires when Turbolinks loads a page, followed by page:load
or page:restore
, depending on whether the load came from the server or the cache.
Potential Issues
Rails 4 is coming, and it brings a slew of changes to the framework.
Turbolinks have a few issues that you might need to address:
- Memory leaks: Turbolinks does not clear or reload your JavaScript when the page changes. You could potentially see the effects of memory leaks in your applications, especially if you use a lot of JavaScript.
- Event Bindings: You have to take older browsers into consideration. Make sure you listen for
page:*
events, as well asDOMContentLoaded
. - Client-side frameworks: Turbolinks may not play nicely with other client-side frameworks like Backbone, Angular, Knockout, Ember, etc.
Opting Out
You may opt out of Turbolinks by:
- removing
turbolinks
from your Gemfile, and - removing the
//= require turbolinks
line fromapplication.js
Caching
Rails 4 brings an overhauled caching strategy. First, action and page caching, as you may know it from previous versions of Rails, have been removed and extracted to gems: action and page, respectively.
Russian Dolls
The new kid on the block is Russian doll caching, or nested fragment caching. The easiest way to understand this system is to look at some code. Suppose that you have a project management application. You may have the following models:
class Milestone < ActiveRecord::Base has_many :todos end class Todo < ActiveRecord::Base belongs_to :milestone, :touch => true end
The :touch
option is required for this caching strategy to work properly. If a todo is added to a milestone, we need to break cache on the milestone to avoid serving stale views.
We now have finely-grained caches in our views. Consider this file as an example (app/views/milestones/show.html.erb
):
<% cache @milestone do %> <h1><%= @milestone.name %></h1> <div class="description"><%= @milestone.description %></div> <ul class="todos"> <%= render @milestone.todos %> </ul> <% end %>
And in app/views/todos/_todo.html.erb
:
<% cache todo do %> <li class="todo"> <%= todo.description %> <span class="status"><%= todo.status %></span> </li> <% end %>
Now, suppose that you have a milestone with ten todos. Editing only one todo causes the milestone’s cache to break, but when generating the HTML, all but one of the todo partials can be fetched from the cache, thus improving render times.
PATCH is now the new HTTP verb for updating resources.
You’re trading time for space, as this generates a lot of cruft in your cache. But, as DHH points out, cache stores like Memcached just chuck out old data to make space for new data. So this isn’t an issue in most cases.
Cache Digests
Cache digests are Rails 4′s solution for tracking the changes of aggressively cached templates. Rails 4 tracks templates and their dependencies, and it suffixes fragment cache keys with the MD5 digest of the template (and its dependencies). When you edit one of your templates, its cache key recieves the update, and you won’t have to manually version your templates.
For more information (and for use in Rails 3), check out the README for the cache digests gem.
Streaming, via ActionController::Live
The new ActionController::Live
module provides the ability to stream data to clients. Simply include
the module into a controller to enable your app to send arbitrary streamed data. You’ll have to use a threaded server, like thin and puma, in order to stream data; actions from streaming controllers run in a separate thread.
Here’s an example from the Rails 4 documentation:
class MyController < ActionController::Base include ActionController::Live def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello worldn" sleep 1 } response.stream.close end end
As the docs note, there are three things to keep in mind:
- You must write any headers before you call
write
orclose
on the response stream. - You have to call
close
on the response stream when you’re finished writing data. - Ensure that your actions are thread-safe, as they will run in a separate thread.
Niceties and Other Things
We’ve talked about the “headline” features in Rails 4. But this release is a big one, and includes a number of smaller changes to be aware of.
PATCH
As described in the Rails blog, PATCH is now the HTTP verb for updating resources.
This change will typically be transparent to developers, as PUT requests will still route to the
update
action for RESTful-style routes.
But it is a change that you should be aware of; PUT routing may change in the future.
Custom Flash Types
This small feature may help clean up some code. You can register your own flash types to use in redirect_to
calls and in templates. For example:
# app/controllers/application_controller.rb class ApplicationController add_flash_types :error, :catastrophe end # app/controllers/things_controller.rb class ThingsController < ApplicationController def create # ... create a thing rescue Error => e redirect_to some_path, :error => e.message rescue Catastrophe => e redirect_to another_path, :catastrophe => e.message end end # app/views/layouts/application.html.erb <div class="error"><%= error %></div> <div class="catastrophe"><%= catastrophe %></div>
Deprecated Finders
Rails 4 deprecates the old-style finder option hashes, as well as all dynamic finder methods (with the exception of find_by_...
and find_by_...
). Instead, you’ll use where
:
find_all_by_...
can be rewritten usingwhere(...)
.find_last_by_...
can be rewritten usingwhere(...).last
.scoped_by_...
can be rewritten usingwhere(...)
.find_or_initialize_by_...
can be rewritten usingwhere(...).first_or_initialize
.find_or_create_by_...
can be rewritten usingfind_or_create_by(...)
orwhere(...).first_or_create
.find_or_create_by_...!
can be rewritten usingfind_or_create_by!(...)
orwhere(...).first_or_create!
.
The deprecated finders gem will be included as a dependency in 4.0. and removed in 4.1. The gem, however, will be around and maintained until 5.0.
Routing Concerns
Routing Concerns is an attempt to DRY up your config/routes.rb
. The basic idea is to define common sub-resources (like comments) as concerns and include them in other resources/routes. Here’s the obvious example:
concern :commentable do resources :comments end concern :remarkable do resources :remarks end resources :posts, :concerns => :commentable resources :articles, :concerns => [:commentable, :remarkable] # can include several
The above is equivalent to the following Rails 3 code:
resources :posts do resources :comments end resources :articles do resources :comments resources :remarks end
Personally, I’m not sure this adds much value; perhaps it makes sense for large applications with hundreds of routes.
Renamed Callbacks
Action callbacks in controllers have been renamed from *_filter
to *_action
. For example:
class UsersController < ApplicationController before_action :set_user, :except => [:index, :new, :create} before_action :require_the_president, :only => [:fire_the_missiles] private def set_user @user = somehow_find_and_set_the_user(params[:id]) end def require_the_president @user.is_the_president? end end
The old *_filter
callbacks still work and are not deprecated; so, you can still use them if you wish. DHH’s reason for the change was:
“To avoid the misconception that these callbacks are only suited for transforming or halting the response. With the new style, it’s more inviting to use them as they were intended, such as setting shared ivars for views.”
Wrapping Up
Rails 4 is coming, bringing with it a slew of changes. I hope that this article has given you a sense of what to expect, and perhaps a launching point into investigating what this new version has to offer.
If you really want to wade into the deep end, check out our Tuts+ Premium course on Rails 4!
Source: Nettuts+
I used to be suggested this website by way of my cousin.
I am no longer sure whether this submit is written by him as nobody
else recognise such certain approximately my trouble.
You are incredible! Thank you!
Hurrah, that’s what I was searching for, what a material! present here at this weblog, thanks admin of this website.
Hi there, You have performed a fantastic job. I will certainly digg it and for my part suggest to my friends. I’m confident they’ll be benefited from this site.
As the admin of this website is working, no doubt very shortly it
will be renowned, due to its feature contents.
Magnificent goods from you, man. I’ve have in mind your stuff previous to and you’re simply
too magnificent. I actually like what you have got here, certainly like
what you’re stating and the best way by which you are saying it. You are making it enjoyable and you still care for to keep it sensible. I can’t wait to learn much more from you.
That is really a tremendous site.
Ηellо i аm kаѵіn, іtѕ my first occаsіοn to commentіng
anyρlace, when i гeaԁ this paгagгaph
i thought i сοulԁ аlso crеаtе comment due to this goοd articlе.
I have learn some good stuff here. Definitely value bookmarking for revisiting.
I wonder how so much attempt you put to create one of these magnificent informative website.
You truly constructed several great tips throughout your article, “Digging Into Rails 4 –
Fire Bull Design Studio”. I may be heading back to your website
soon enough. Thx ,Pansy
It’s really a cool and useful piece of info. I’m glad that you just
shared this helpful information with us. Please stay us up to date
like this. Thanks for sharing.
Its such as you read my mind! You seem to know so much about this, like you wrote the e-book in it or something. I believe that you simply could do with some % to force the message house a bit, however instead of that, this is wonderful blog. A great read. I’ll certainly be back.
Very nice post. I simply stumbled upon your blog and wished to mention that I have truly enjoyed surfing around your blog posts.
After all I’ll be subscribing on your feed and I’m hoping you write
once more soon!
Hi, Theге’s no doubt that your blog could be having browser compatibility issues. When I take a look at your site in Safari, it looks fine however when opening in IE, it’ѕ gοt somе overlapping іssues.
I just ωanteԁ to proνіde yоu with а quісk heaԁs uρ!
Apart fгοm thаt, еxcellеnt sitе!
It’s going to be ending of mine day, except before end I am reading this great article to improve my experience.
obviously like youг wеbsite howeνеr you need to сheck the ѕpеllіng
on sеveгal of уour posts. Many οf them are
rife with sрelling problеms and I in fіndіng іt very tгoublesome to tell
the truth οn the other hand I will defіnitely
come bacκ agaіn.
I read this post completely on the topic of the difference of hottest
and earlier technologies, it’s awesome article.
This is reallу interеstіng, Yοu’re a very skilled blogger. I’ve joіned your feeԁ and looκ forωard to
seeking more of уour excellent ρost. Also, I’ve shared your web site in my social networks!
There are definitely a lot of particulars like that to take into consideration. That may be a nice level to bring up. I provide the thoughts above as general inspiration but clearly there are questions just like the one you deliver up where an important thing might be working in trustworthy good faith. I don?t know if best practices have emerged around issues like that, but I am positive that your job is clearly identified as a fair game. Both girls and boys feel the affect of just a second’s pleasure, for the rest of their lives.
I have learn several excellent stuff here. Certainly price bookmarking for revisiting.
I wonder how so much attempt you place to make one of these magnificent informative website.