Solving [DEPRECATION] last_comment is deprecated when upgrading to rails 4.2.6

We ran into the deprecation warning above when we upgraded to Rails 4.2.6.

The issue was an older version of rspec-rails 3.3.3 and upgrading to 3.4.2 removed the warning.

To resolve all dependencies we edited our Gemfile to:

gem 'rspec-rails' , '3.4.2'
gem "rspec-activemodel-mocks" #, "~> 1.0.1"
gem "rspec-mocks", "~> 3.4.0"

then ran:
bundle update rspec-rails rspec-mocks accept_values_for

Getting Glyphicons to work with static Bootstrap 3 CSS and Rails 3.2

Glyphicons will not work correctly on production Rails apps in the default static Bootstrap 3 installation. The issue is that the compiled (static) Bootstrap CSS file has hardwired location ../fonts for the fonts that will not work with the default Rails asset pipeline. I’ve seen several solutions on the web that involve editing the Bootstrap CSS file, but I dislike that approach since it breaks the next time you install an updated Bootstrap unless you remember to re-make the same edits.

Copy the entire Glyicons /fonts folder to the app/assets/stylesheets folder, e.g., put the fonts in a fonts subdirectory of the stylesheets folder.

Add the following to bootstrap_and_overrides.css

/* Override Bootstrap 3 font locations */ 
@font-face { 
  font-family: 'Glyphicons Halflings'; 
  src: url('/assets/fonts/glyphicons-halflings-regular.eot'); 
  src: url('/assets/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),
  url('/assets/fonts/glyphicons-halflings-regular.woff') format('woff'), 
  url('/assets/fonts/glyphicons-halflings-regular.ttf') format('truetype'), 
  url('/assets/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); 
}

How to specify Fancybox2 options to manually open() a box (the docs are wrong)

Fancybox is a superb tool for adding a lightbox-style popup to your web app. And Fancybox2 (the paid version) adds some very nice features and occasional updates, all well worth the trivial cost. The docs are incorrect however as to how to specify some of the open() options.

The fancybox2 v2.1.5 docs for the API call open() says

$.fancybox.open( [group], [options] )

However the docs go into detail about [ group ] and say nothing about the format expected for the [ options ]

Furthermore the options seem to be ignored.

When I use

$.fancybox.open([{ href : ‘#popup_panel’ }], [ { ‘title’ : ‘Title Two’, ‘minWidth’ : 500 }] );

or

$.fancybox.open([{ href : ‘#popup_panel’ }], [ { title : ‘Title Two’, minWidth : 500 }] );

Fancybox seems to ignore the options… it opens, but there is no title and the minWidth is ignored.

Turns out, the fancybox documentation is wrong; options go inside the [group] apparently:

$.fancybox.open([{ href : ‘#popup_panel’, title : ‘Title Two’, minWidth : 500 }], [] );

Getting S3Object.exists? to work correctly with IAM policies

When we updated our Rails 3.2 apps to each use their own IAM users and policies (instead of sharing a root S3 key/secret), we found that the aws-s3 (0.6.3) gem was causing S3Object.exists?() to always return true.

Although an updated aws-s3 gem may eventually fix the issue, the quick wrokaround was to modify the IAM policy to include both BUCKET and BUCKET/* (normally we need just the latter). Specifically:

{ "Version": "2012-10-17", 
"Statement": [ 
   { "Sid": "Stmt1234567890", 
    "Effect": "Allow", 
    "Action": [ "s3:*" ], 
    "Resource": 
         [ "arn:aws:s3:::SOMEBUCKET", 
          "arn:aws:s3:::SOMEBUCKET/*" ] 
}  ] }

Getting RSpec, Postgres, DatabaseCleaner to play nicely together

Did a quick benchmark last week to find the optimal way to configure Rspec on our projects that use Postgres and DatabaseCleaner

One of our test suites takes 3.5 minutes to run when we do NOT use DatabaseCleaner, the default rspec setup:

# spec_helper.rb
#config.use_transactional_examples = false 
#config.before(:suite) do 
# DatabaseCleaner.strategy = :transaction 
# DatabaseCleaner.clean_with(:truncation) 
#end 
#config.before(:each) do 
# DatabaseCleaner.start 
#end 
#config.after(:each) do 
# DatabaseCleaner.clean 
#end

When we enabled database cleaner (with default .strategy = :transaction), the test still took 3.5 minutes, but we got lots of warnings:**WARNING: there is already a transaction in progress
NOTICE: there is no transaction in progress
**

# spec_helper.rb
 #config.use_transactional_examples = false 
config.before(:suite) do 
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation) 
end 
config.before(:each) do 
DatabaseCleaner.start 
end 
config.after(:each) do 
DatabaseCleaner.clean 
end

However, when we changed the .strategy to :trunctation, it eliminated the warnings, but slowed the tests down to 8 minutes!# spec_helper.rb

#config.use_transactional_examples = false 
config.before(:suite) do 
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean_with(:truncation) 
end 
config.before(:each) do 
DatabaseCleaner.start 
end 
config.after(:each) do 
DatabaseCleaner.clean 
end

The best results were to leave the strategy set to :transaction, but set config.use_transactional_examples = false. That yielded a runtime of about 3.5 minutes.

# spec_helper.rb
 config.use_transactional_examples = false 
config.before(:suite) do 
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation) 
end 
config.before(:each) do 
DatabaseCleaner.start 
end 
config.after(:each) do 
DatabaseCleaner.clean 
end

We used the following addition spec to verify that the database was being cleaned. (run this with –order default )

#dbclean_spec.rb

require "spec_helper" 
Refer.destroy_all 
describe Refer do 
it "has none to begin with" do 
  Refer.count.should == 0 
end 
it "has one after adding one" do 
Refer.create 
Refer.count.should == 1 
end 
it "has none after one was created in a previous example" do Refer.count.should == 0 
end 
end

Rspec gotcha – instance variables are not cleared between ‘get’s

It seems that (unlike when controller methods are invoked via browser) if you do two consecutive get’s with rspec, instance variables are not cleared with each get, so data crossover is possible.

Here’s a failing test, showing that a variable set in ‘vartest1′ is still present when another controller method ‘vartest2′ is run:

Controller methods:

def vartest1 
  @this_var = "foo" 
  render :text => @this_var
end 
def vartest2 
  render :text => @this_var # should be EMPTY! 
end

Rspec controller spec (note: we use render_views so the views are rendered in the spec)

describe "instance variable crossover example", :focus => true  do 
  describe "THIS PASSES put each get in separate contexts" do 
    it "vartest1 outputs foo" do 
      get "vartest1" 
      response.body.should include("foo") 
    end 
    it "vartest2 does NOT output foo" do 
      get "vartest2" 
      response.body.should_not include("foo") 
    end 
  end 
  describe "THIS FAILS put both gets in SAME context" do 
    it "should not crossover controller instance varables" do 
      get "vartest1" 
      response.body.should include("foo") 
      get "vartest2" 
      response.body.should_not include("foo") # THIS FAILS 
    end 
  end 
end

Rspec results:

instance variable crossover example 
THIS PASSES 

put each get in separate contexts 
vartest1 outputs foo 
vartest2 does NOT output foo 
THIS FAILS 

put both gets in SAME context should not crossover 
controller instance varables (FAILED - 1)

>

What’s happening in the failing test is that when rspec does get ‘vartest1′ the controller method set an instance variable to ‘foo’, and when rspec does get ‘vartest2′ the instance variable (which should be nil) is still set, so the test fails.

ActiveRecord find_each ignores any order() criteria

One of the many benefits of test driven development is the ability to catch somewhat subtle bugs like this during development…

The ActiveRecord find_each method is a great way to loop through large numbers of records. However, find_each will silently discard any order() criteria. Seems to me like a bug in find_each. However it was nice to find it in our rspec tests that verified certain things would be processed in a certain order.

How to specify traits for model associations in FactoryGirl

If you’re using RSpec and FactoryGirl to automate testing for your Rails app, you probably know that when creating a factory for a model that has association you can simply specify the factory of the associated model. For example, suppose your Contact model has associations with Phone and Store models:

FactoryGirl.define do factory :contact do |f| f.name { Faker::Name.name } phone store end end

And you probably know you can have traits for factories, for example, different settings for different types of stores:

FactoryGirl.define do 
  factory :store do |f| 
    after(:create) { |store| 
      store.update_attributes :name => Faker::Name.last_name + " LLC" 
    } 

    trait :unknown do 
      after(:build) { |store| store.init_blank(Settings.feature_set_unknown) } 
    end 

    trait :restaurant do 
      after(:build) { |store| store.init_blank(Settings.feature_set_restaurant) } 
    end 

    trait :retailer do 
      after(:build) { |store| store.init_blank(Settings.feature_set_retailer) } 
    end 
  end
end

However, what we could not find documented anywhere was how to specify a trait for an associations. Say when you create a contact factory you want specify which type of store that contact belongs to:

Here’s the magic decoder ring… use
:factory => [:association_factory_name, :trait_name]

FactoryGirl.define do 
  factory :contact do |f| 
    f.name { Faker::Name.name } 
    phone association :store, :factory => [:store, :unknown] 

    trait :foodie_contact do 
      association :store, :factory => [:store, :restaurant] 
    end 

    trait :retailer_contact do 
      association :store, :factory => [:store, :retailer] 
    end 
  end 
end

Which you can then invoke as follows in your examples:

c = FactoryGirl.create(:contact, :retailer_contact)

Getting Rmagick to work again

Although we are running Lion on all our dev machines, we had an issue where a project using RMagick suddenly stopped working in dev mode, giving the error

Incompatible library version: RMagick2.bundle requires version 10.0.0 or later, but libltdl.7.dylib provides version 9.0.0

http://tech-blog.blogbin.info/blog/2012/08/18/gem-install-rmagick-on-apple-macos-x-mountain-lion-10-dot-8/

Managed to fix it following these steps:

Ran this in terminal:

gem uninstall rmagick
brew uninstall imagemagick
brew install –fresh imagemagick
gem install rmagick

After this, RMagick worked flawlessly again!

A subtle problem with using update_attributes in Rails migrations

It’s fairly common to create a Rails migration that adds a column, then stuffs data into that column for legacy data, for example the addition of a guid field.

However, using update_attributes can quietly bungle your database by skipping certain records if you have added any new validations which did not apply to legacy data in the database.

For example, suppose you’ve had a Widgets table for a long time, and it has lots of existing Widgets in it. Originally, the name of a Widget could be any length, but a few months ago you added a validation so a Widget name should be at least 10 characters going forward.

Now you want to add an 8 character guid to Widgets. If you run the following migration using update_attributes (instead of a save(:validate => false) as I show here) your migration will pass, so you’ll think everything is fine, BUT any widgets with a too-short name will not receive their guid because the valiation fails.

Obviously there ARE times when you want validations when adding data, but probably not in a case like this where you are adding a new field with a use that is independent of any prior data values.

class AddGuidToWidgets < ActiveRecord::Migration
  def self.up
    add_column :widgets, :public_guid, :string

      # MUST reset to ensure new column info used
    Widget.reset_column_information
    Widget.find(:all).each do |w|
      g = (0...8).map { 65.+(rand(25)).chr}.join
      while !FinderItem.find_by_public_guid(g).nil?
        g = (0...8).map { 65.+(rand(25)).chr}.join
      end
        # can NOT use update_attributes because might have validation errors
        # due to new validations added on certain other fields
      w.public_guid = g 
      w.save( :validate => false )
      #DONT USE: w.update_attributes :public_guid => g 
  end
  ...