Flowdock

Notes posted by hosiawak

RSS feed
May 31, 2010
4 thanks

Naming fragment cache

One of the common ways of using fragment caching is to cache content that’s shared across the site (eg. left navigation, menus, widgets etc.) that looks and works the same regardless of the name of the action or controller calling it. In such cases it’s very easy to just use named fragment caching eg.:

<% cache('left_nav') do -%>
  <%= display_left_nav -%>
<% end -%>
March 4, 2010 - (>= 1.2.8)
5 thanks

stub_chain is very useful when testing controller code

or any other chained method call type that you’d like to stub, example:

in your controller:

def new
  @user = current_site.users.new
end

in your spec:

it "#new should assign a @user" do 
  u = mock("User")
  controller.stub_chain(:current_site, :users, :new).and_return(u)
  assigns[:user].should == u
end

whereas before you had to stub each chained method call separately:

it "#new should assign a @user" do 
  u = mock("User")
  users = mock("Users collection", :new => u)
  site = mock("Site", :users => users)
  controller.stub!(:current_site).and_return(site)
  assigns[:user].should == u
end

Please note that stub_chain was added to RSpec in version 1.2.6

August 17, 2009
1 thank

Freezing Time.now with Time.is

Sometimes when writing unit tests/specifications our code sets an attribute of an object using Time.now because running specs/test takes time.

The solution is to “freeze” Time.now with the following Time.is method:

class Time

  def self.metaclass
    class << self; self; end
  end

 # useful for unit testing
 # Time.is(Time.now) do
 #   Time.now # => Tue Nov 13 19:31:46 -0500 2007
 #   sleep 2
 #   Time.now # => Tue Nov 13 19:31:46 -0500 2007
 # end
 #
 # Time.is("10/05/2006") do
 #   Time.now # => Thu Oct 05 00:00:00 -0400 2006
 #   sleep 2
 #   Time.now # => Thu Oct 05 00:00:00 -0400 2006
 # end
  def self.is(point_in_time)
    new_time = case point_in_time
               when String then Time.parse(point_in_time)
               when Time then point_in_time
               else raise ArgumentError.new("argument should be a string or time instance")
               end
    class << self
      alias old_now now
    end
    metaclass.class_eval do
      define_method :now do
        new_time
      end
    end
    yield
    class << self
      alias now old_now
      undef old_now
    end
  end

end

It’s a good idea to add this to your spec_helper/test_helper and “freeze” time whenever you’re testing functionality that depends on a specific time value.

August 17, 2009
2 thanks

Time in fixtures

When creating fixtures you should use this method to set created_at/updated_at timestamps correctly:

eg:

This won’t work as expected (created_at/updated_at will be nil) a

one:
  episode: active1
  play_id: 1
  play_time: 20
  country: United Kingdom
  created_at: <%= Time.parse('22:00 14 Aug 2009') %>
  updated_at: <%= Time.parse('22:00 14 Aug 2009') %>

but this will work as expected:

one:
  episode: active1
  play_id: 1
  play_time: 20
  country: United Kingdom
  created_at: <%= Time.parse('22:00 14 Aug 2009').to_s(:db) %>
  updated_at: <%= Time.parse('22:00 14 Aug 2009').to_s(:db) %>
August 17, 2009
1 thank

Time in fixtures

When creating fixtures you should use this method to set created_at/updated_at timestamps correctly:

eg:

This won’t work as expected (created_at/updated_at will be nil) a

one:
  episode: active1
  play_id: 1
  play_time: 20
  country: United Kingdom
  created_at: <%= Time.parse('22:00 14 Aug 2009') %>
  updated_at: <%= Time.parse('22:00 14 Aug 2009') %>

but this will work as expected:

one:
  episode: active1
  play_id: 1
  play_time: 20
  country: United Kingdom
  created_at: <%= Time.parse('22:00 14 Aug 2009').to_s(:db) %>
  updated_at: <%= Time.parse('22:00 14 Aug 2009').to_s(:db) %>
June 19, 2009
2 thanks

Re: How to test different responses

In addition to using:

@request.accept = "text/javascript" #=> request JS

as rubymaverick and nachocab suggested, you can also pass :format when calling your action, eg:

it "GET #most_viewed renders #most_viewed.js.rjs template if js requested" do
  get :most_viewed, :format => 'js'
  response.should render_template('most_viewed')
end
June 4, 2009
2 thanks

A typical usage for a mock

You want to use a mock when you’re testing a behaviour of one of your methods that interacts with some outside world service (eg. an FTP server).

it "should login to ftp server" do
  ftp = mock('Ftp server', :null_object => true)
  Net::FTP.should_receive(:new).and_return(ftp)
  ftp.should_receive(:login).with('username', 'password')
  some_obj.connect
end

def connect
  session = Net::FTP.new('server.com')
  session.login('username', 'password')
  session.close
end
June 4, 2009
5 thanks

A catch-all format

If you’d like to specify a respond_to only for 1 or a few formats and render something else for all other formats, eg: (action.rss returns a feed but action.html or action.js should just render 404), use format.all:

respond_to do |format|
  format.rss { render_rss }
  format.all { render_404 }
end

Rails will render an empty string for all formats that don’t specify a response explicitly.

May 12, 2009
2 thanks

form_authenticity_token

Instead of disabling the CSRF check you can pass the authenticity_token field in your forms, eg:

<%= hidden_field_tag :authenticity_token, form_authenticity_token -%>
May 6, 2009
1 thank

Formatted route helpers are gone

In Rails >= 2.3 you can’t use formatted_xxx url helpers anymore.

However, you can still pass a :format option to url helpers, eg:

articles_path(:format => :csv) # => /articles.csv
January 13, 2009
7 thanks

Universal partial

polymorphic_url is very useful if you want to create an universal partial that works for more than 1 type of object passed to it.

For example in you sidebar you might have a _sidebar.html.erb partial that’s supposed to display links to “Edit” and “Delete” actions. You can write it in such a way that it can be reused for different types of objects (in the example below we pass either a Post or a Note).

your_template.html.erb

<%= render :partial => 'shared/sidebar', :locals => { :obj => Post.new -%>

other_template.html.erb

<%= render :partial => 'shared/sidebar', :locals => { :obj => Note.new -%>

_sidebar.html.erb

<%= link_to "Edit", polymorhpic_url(obj, :action => 'edit') -%>
<%= link_to "Delete", polymorphic_url(obj), :method => :delete -%>
September 2, 2008
5 thanks

Useful in migrations

The most common usage pattern for this method is probably in a migration, when just after creating a table you want to populate it with some default values, eg:

class CreateJobLevels < ActiveRecord::Migration
  def self.up
    create_table :job_levels do |t|
      t.integer :id
      t.string :name

      t.timestamps
    end

    JobLevel.reset_column_information
    %w{assistant executive manager director}.each do |type|
      JobLevel.create(:name => type)
    end
  end

  def self.down
    drop_table :job_levels
  end
end
August 12, 2008
6 thanks

Helper method taking a block

Following the similar egzample by autonomous, here’s a simpler version when you just need to write a flexible helper method that takes a block.

For example, suppose you have a method that renders a tree:

def render_tree(ary, &block)
  concat("<ul>", block.binding)
  for elem in ary
    concat("<li>", block.binding)
    yield elem
    concat("</li>", block.binding)
  end
  concat("</ul>", block.binding)
end

You can use it in your view, eg:

<% render_tree(@objects) do |elem| -%>
  <%= elem.title -%>
  <%= link_to 'delete', elem -%>
<% end -%>

that would return for egzample:

<ul>
  <li>
    Test title
    <a href="delete">/elems/1</a>
  </li>
</ul>

Testing concat

To test such helper methods, use the following pattern (a utility method added to your Rspec/unit test suite:

def render_for(root, options = {})
  _erbout = ''
  render_tree(root, options) do |node|
    _erbout.concat(node.title)
  end
  _erbout
end

and test like this (RSpec example):

it "should return abc" do
  render_for(object).should == 'abc'
end
August 12, 2008
1 thank

Overview of all routes

To see all defined routes type in your console:

rake routes

This produces (eg.):

reorder_toolbox_items   PUT   /toolbox_items reord {:controller=>"toolbox_items", :action=>"reorder"}
channels   GET  /channels {:controller=>"channels", :action=>"index"}
...
etc.
August 12, 2008
1 thank

Overview of all routes

To see all defined routes type in your console:

rake routes

This produces (eg.):

reorder_toolbox_items   PUT   /toolbox_items reord {:controller=>"toolbox_items", :action=>"reorder"}
channels   GET  /channels {:controller=>"channels", :action=>"index"}
...
etc.
August 12, 2008
12 thanks

Overriding the default div class="fieldWithErrors"

By default fields that are invalid are wrapped in:

<div class="fieldWithErrors">
  <input type="text" name="blah">
</div>

To override and wrap in spans instead of divs place the following in your environment.rb:

ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| "<span class=\"fieldWithErrors\">#{html_tag}</span>" }

or to not use wrapping at all:

ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| "#{html_tag}" }
August 12, 2008
9 thanks

Overriding the default div class="fieldWithErrors"

By default fields that are invalid are wrapped in:

<div class="fieldWithErrors">
  <input type="text" name="blah">
</div>

To override and wrap in spans instead of divs place the following in your environment.rb:

ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| "<span class=\"fieldWithErrors\">#{html_tag}</span>" }

or to not use wrapping at all:

ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| "#{html_tag}" }