March 11, 2013Posted by Tom Meier
Keeping specs fast is a never ending battle for the average Rails developer. There are 2 quick lines of javascript that can make excellent and stable improvements to spec speed performance.

Most people are aware of JQuery giving the option to disable animations (see – fx.off), we can disable this in test mode making all browser based specs faster by skipping JS animation. This is acceptable, as we know it works, it’s still being triggered but skips the time-consuming part for our specs.
The same can be said for CSS transformations; sliding a menu down and hiding a div for example. We know they work, but don’t want our specs held up by the animation.
To acheive this, simply apply the following code to your Rails app :
app/views/layouts/_spec_performance.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
<% if Rails.env.test? -%>
<%= content_for :head do %>
<style type="text/css">
.notransition * {
/*CSS transitions*/
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
-ms-transition: none !important;
transition: none !important;
/*CSS transition properties*/
-webkit-transition-property: none !important;
-moz-transition-property: none !important;
-o-transition-property: none !important;
-ms-transition-property: none !important;
transition-property: none !important;
/*CSS transforms*/
-webkit-transform: none !important;
-moz-transform: none !important;
-o-transform: none !important;
-ms-transform: none !important;
transform: none !important;
/*CSS animations*/
-webkit-animation: none !important;
-moz-animation: none !important;
-o-animation: none !important;
-ms-animation: none !important;
animation: none !important;
}
</style>
<% end %>
<script type="text/javascript">
$.fx.off = true;
$('body').addClass('notransition');
</script>
<% end -%>
|
app/views/layouts/any_layout.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
|
<html>
<head>
<%= yield :head %>
</head>
<body>
...
<%= yield %>
...
<%= render partial: "layouts/spec_performance" %>
</body>
</html>
|
Thats it. I’m seeing ~31% speed improvements on our mobile specs, and ~18% speed improvements on our normal Capybara features.
Tagged ruby, rails, programming, rspec, testing, capybara, selenium
April 11, 2011Posted by Tom Meier
A recent rabbit hole that I fell in, related to a rather obscure Ruby 32bit → 64 bit Time parsing issue. I’ll lay it all out here in the hope that no-one else falls into it.

As per usual, all the code was working swimmingly on my own machine (macbook pro – 64 bit with the trimmings, hold the fat), but the minute it was deploying onto multiple servers and the testing environment (see – Jenkins or whatever continuos integration philosophy you employ), a few inserts into the database were chucking nasty “ArgumentError: time out of range” errors.
First picked up when attempting to load fixtures for the test suite. With a bit of hunting this narrowed down to simply one of the date values being set at ‘3000-01-01’ (legacy systems groan), as you can see here:
my 64 bit machine:
1
2
3
4
|
>> Time.parse('3000-01-01')
=> Wed Jan 01 00:00:00 +1100 3000
>> DateTime.parse('3000-01-01')
=> Wed, 01 Jan 3000 00:00:00 +0000
|
on 32 bit testing server:
1
2
3
4
5
6
7
8
|
ree-1.8.7-2011.03 :001 > Time.parse('3000-01-01')
ArgumentError: time out of range
from /usr/local/rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/time.rb:184:in `local'
from /usr/local/rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/time.rb:184:in `make_time'
from /usr/local/rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/time.rb:243:in `parse'
from (irb):1
ree-1.8.7-2011.03 :002 > DateTime.parse('3000-01-01')
=> Wed, 01 Jan 3000 00:00:00 +0000
|
So the long and short of it is that Ruby in a 32 bit environment, when running Time.parse tends to have a ‘bit’ of a hissy fit with any years greater than 2038. Time has a limited range of 1901 – 2038, anything, and I mean anything, even a second outside this range, requires DateTime to be used instead.
With my particular issue, I had to track down where it was calling Time.parse, and why the festicky was it not using a superior DateTime.parse call on the input data. Long live the testing suite! A quick change added to the spec_helper.rb:
spec/spec_helper.rb
1
2
3
4
5
6
|
#Raise on the method call - REMOVEME
class Time
def self.parse(date, now=self.now)
raise "THIS LITTLE BUGGER CALLED ME : #{caller.inspect}"
end
end
|
On the next run of the relevant spec, which loaded the problematic date times, I could then see the cause of my current despair was none other than Sequel . Sequel has been a fantastic utility, and I’m preferring it over Arel and ActiveRecord for the extra control it gives me. However, this was the root cause.
Turns out Sequel is well aware of the issue and had an immediate fix to hand already, boomshanka!
http://sequel.rubyforge.org/rdoc/classes/Sequel.html
datetime_class [RW] Sequel can use either Time or DateTime for times returned from the database. It defaults to Time. To change it to DateTime:
Sequel.datetime_class = DateTime
For ruby versions less than 1.9.2, Time has a limited range (1901 to 2038), so if you use datetimes out of that range, you need to switch to DateTime. Also, before 1.9.2, Time can only handle local and UTC times, not other timezones. Note that Time and DateTime objects have a different API, and in cases where they implement the same methods, they often implement them differently (e.g. + using seconds on Time and days on DateTime).
Job done. Setting the Sequel default to use DateTime instead of time resolves this issue for both 32 bit and 64 bit machines, and will work on any modern ruby version.
Tagged ruby, rails, programming
January 30, 2011Posted by Tom Meier
To auto-generate static pages in Rails 3, other than by simply adding html files to the ‘public’ directory, is very easy.
The most simple way is to just; add a controller such as ‘PagesController’, redirect all unmatched routes there, create a view and it will be displayed if the html/haml view exists – with any others raising a template not found error (display 500 to the production user).
However, I usually want to capture whats going on behind the scenes, or share variables across a group of pages.
Disclaimer – this isn’t the ideal or the best way, but it is my convenient way, let me know if you have any tips ’n tricks to improve it further!

My usual setup can be handy, if you want custom static pages for both scoped areas of those logged in and those not, or even subdomains, anything is possible really with the Rails 3 routing setup. Simply add the following:
Create a pages controller class, under any submodule or folder structure you like.
This will simply check if the view template exists (even haml) and render that, otherwise render out your custom 404 page, the only params being sent are ‘base_page’ which will be set by the routes.
app/controllers/pages_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class PagesController < ApplicationController
def base_page_processor
view_prefix = "pages"
if params[:base_page].present? && template_exists?(params[:base_page], view_prefix)
render "#{view_prefix}/#{params[:base_page]}"
else
#TODO : Notify missing url via email error or error notification service
render '/public/404.html', :status => 404
end
end
end
|
To ensure all routes are matched, that aren’t specifically set in the config/routes.rb file, add this line right at the very end of the file (or at the end of a specific scope, such as a logged in section) :
config/routes.rb
1
|
match ':base_page', :controller => 'pages', :action => 'base_page_processor', :as => :page_processor
|
Some specs to help you along the way (using RSpec), and ensure you don’t break the setup as time goes on:
spec/controllers/pages_controller_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
require 'spec_helper'
describe PagesController, 'automatic paths' do
before(:all) do
@routes = Rails.application.routes
end
it "should route all traffic and render if template exists" do
["/some_random_path", "/something_else", "/doesnt_exist"].each do |dynamic_path|
@routes.recognize_path(dynamic_path).should == {:controller => 'pages', :action => 'base_page_processor', :base_page => dynamic_path.gsub(/^\//,'')}
end
end
it 'should not route any traffic with sub paths' do
["/some_random_path/with_sub/lines", "/something_else/123/something.csv", "/doesnt_exist/nope"].each do |dynamic_path|
lambda { @routes.recognize_path(dynamic_path) }.should raise_error(ActionController::RoutingError)
end
end
describe 'with templates existing' do
it 'should render the template' do
controller.stub!(:template_exists?).and_return(true)
controller.stub!(:render)
controller.should_receive(:render).with( 'pages/something_that_exists' )
get 'base_page_processor', :base_page => 'something_that_exists'
response.status.should == 200
end
end
describe 'when template doesnt exist' do
it 'should render the 404 page' do
get 'base_page_processor', :base_page => 'something_that_doesnt_exist'
response.status.should == 404
response.should render_template('public/404')
end
end
end
|
Now simply add any view template in your set page prefix, in the above example this would be ‘/app/views/pages/any_template_file’, this will now immediately load in your app. Easy.
Tagged ruby, rails, programming