Wednesday, May 20, 2015

Deprecated Finders With Rails 4

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 using where(...).
  • find_last_by_... can be rewritten using where(...).last.
  • scoped_by_... can be rewritten using where(...).
  • find_or_initialize_by_... can be rewritten using where(...).first_or_initialize.
  • find_or_create_by_... can be rewritten using find_or_create_by(...) or where(...).first_or_create.
  • find_or_create_by_...! can be rewritten using find_or_create_by!(...) or where(...).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.

Accessing helper modules into decorate with Rails 4

Additionally, a decorator has access to Rails helper modules via the helper proxy method. This is useful when you want to hide complex logic from the templates.

class PersonDecorator < Draper::Decorator
  delegate_all

  def author_headline
    if author == helper.current_user
      h.content_tag(:h3, 'You')
    else
      h.content_tag(:h3, author.name)
    end
  end
end

Now in your template you just call @person.author_headline and you are done. No conditions in the template. Your designers will be thankful!

Access current_user into decorate like below.

h.current_user

Friday, May 15, 2015

Custom Flash Types In Rails 4

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>




Thursday, May 14, 2015

Renamed Callbacks in Rails 4

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.

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 world\n"
        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 or close 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.

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.