Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Rails 3 responders to make you controllers DRY

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 app
Octocat-spinner-32 lib
Octocat-spinner-32 test
Octocat-spinner-32 .document
Octocat-spinner-32 .gitignore
Octocat-spinner-32 .travis.yml
Octocat-spinner-32 Gemfile
Octocat-spinner-32 Gemfile.lock
Octocat-spinner-32 LICENSE.txt
Octocat-spinner-32 README.md
Octocat-spinner-32 Rakefile
Octocat-spinner-32 VERSION
Octocat-spinner-32 wiserespond.gemspec
README.md

Build Status

wiserespond

Rails 3 responders to make you controllers DRY.

Installation

Add this to your Gemfile:

gem 'wiserespond'

then do:

bundle

How does it work?

Without wiserespond

I a lot of Rails projects I see code like:

class BrandsController < ApplicationController
  before_filter :fetch_brand

  def edit
    # Here is some code 
  end

  def update
    authorize! :update, @brand
    if @brand.update_attributes(params[:brand])  
      respond_to do |format|
        format.html{ redirect_to brand_url(@brand) }
        format.js # Here will be rendered something like 'brands/update.js.erb'
      end
    else
      respond_to do |format|
        format.html{ render :action => :edit }
        format.js # Here again be rendered 'brands/update.js.erb'
      end                  
    end
  end
end

Then your brands/update.js.erb can look like this:

<% if @brand.errors.any? %>
  $('#brand').replaceWith('<%= escape_javascript(render :partial => "brands/form", :locals => { :brand => @brand }) %>')
<% else %>
  window.location.href="<%= brand_url(@brand).html_safe %>";
<% end %>

Or, if you use History API, or maybe Fancybox and you have to setup some features in you form and show flash message, it will be a bit more complex:

<% if @brand.errors.any? %>
  $('#brand').replaceWith('<%= escape_javascript(render :partial => "brands/form", :locals => { :brand => @brand }) %>')
  appSetupAllFeatures(#brand);      
  Flash.notification('An error occured while saving your brand');
<% else %>
  $.fancybox.close();
  History.replaceState({timestamp: (new Date().getTime()), slide: true}, document.title, "<%= brand_url(@brand).html_safe %>");            
<% end %>

If you have to do this only once – this is OK. But what if out app consists of more then one controller and every controller has more then two actions?

Of course we can create

  • brands/update.js.erb
  • brands/create.js.erb
  • brands/some_other_action.js.erb
  • other_model/some_other_action.js.erb

and so on… This list can be rather long. Not a Rails-way at all.

With wiserespond

Wiserespond does not try to invent some new way of writing controllers, it also does not have any magic. All is clear and easy to understand. Lets start with refactored example of out controller:

class BrandsController < ApplicationController
  before_filter :fetch_brand

  def edit
    # Here is some code 
  end

  def update
    authorize! :update, @brand
    if @brand.update_attributes(params[:brand])  
      respond_with_redirect :url => brand_url(@brand)
    else
      respond_with_content :action => :edit, :id => '#brand', :partial => 'brands/form'
    end
  end
end

Looks great? For me – yes! And works great too.

Wiserespond aggregates html and js content types responds, make redirection or action rendering on html content type and adds default templates to js content type. Here is wiserespond/content.js.erb:

<% if local_assigns[:id].present? && local_assigns[:partial].present? %>
  $('#<%= id %>').replaceWith('<%= escape_javascript(render :partial => "#{partial}", :locals => locals) %>')
<% end %>

and here wiserespond/redirect.js.erb:

<% if local_assigns[:url].present? %>
  window.location.href="<%= url.html_safe %>";
<% end %>

Of course you can redefine this templates in your application. Just create then in app/views/wiserespond directory.

For example, I use History API and want to pass some additional information to my JS code, here is what I have in app/views/wiserespond/redirect.js.erb:

History.replaceState({timestamp: (new Date().getTime()), slide: true}, document.title, "<%= url.html_safe %>");

$.fancybox.close();

<% if local_assigns[:ids].present? %>
  $('.sidebar').trigger('update.cells_liens_tree', {ids: <%= ids %>});
  $('.sidebar').trigger('update.cells_auctions_tree', {ids: <%= ids %>});
  $('.sidebar').trigger('update.cells_liens_shared', {ids: <%= ids %>});
<% end %>

And here is how I call in controller:

if @portfolio.update_attributes(params[:portfolio])
  respond_with_redirect :url => portfolio_url(@portfolio), :ids => @portfolio.affected_widget_ids, :flash => 'Portfolio was successfully updated.'
else

Make your controllers as DRY as you can!

Production?

wiserespond is used at:

Know other projects? Then contact me and I will add them to the list.

Note on Patches / Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

Credits

JetRockets

Wiserespond is maintained by JetRockets.

Contributors:

License

It is free software, and may be redistributed under the terms specified in the LICENSE file.

Something went wrong with that request. Please try again.