Intro to Deadlocks

Advertisements

How to Log Formatted JSON Responses in your Rails Application

1. Copy and paste this to app/middleware/log_pretty_json.rb:

class LogPrettyJson
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    
    if defined?(Rails) && headers["Content-Type"] =~ /^application\/json/
      obj = JSON.parse(response.body)
      pretty_str = JSON.pretty_unparse(obj)
      Rails.logger.debug("Response: " + pretty_str)
    end
    
    [status, headers, response]
  end
end

2. Add to app/config/environments/development.rb:

  config.log_level = :debug
  config.middleware.use LogPrettyJson

3. Restart and tail your log file to see what happens!

$ tail -f log/development.log

Seed your Rails App by Importing from SQL

Here’s what you can do if you want to seed by importing a dumped SQL file.

1. Replace /db/seeds.rb with:

unless Rails.env.production?
  connection = ActiveRecord::Base.connection
  connection.tables.each do |table|
    connection.execute("TRUNCATE #{table}") unless table == "schema_migrations"
  end
  
  # - IMPORTANT: SEED DATA ONLY
  # - DO NOT EXPORT TABLE STRUCTURES
  # - DO NOT EXPORT DATA FROM `schema_migrations`
  sql = File.read('db/data.sql')
  statements = sql.split(/;$/)
  statements.pop  # the last empty statement

  ActiveRecord::Base.transaction do
    statements.each do |statement|
      connection.execute(statement)
    end
  end
end

2. Export your data excluding the `schema_migrations` table to db/data.sql (don’t export structure, your migrations handle that).

3. Run $ rake db:seed

The Best Online Resources for Learning Rails

It’s a work in progress so leave me a comment if I’ve left anything out!

Free Websites

  • Rails Guides – the official Rails site, the topics covered in the guide index will get you off to a good start!
  • Pow – Rack server recommended if developing multiple apps
  • Ruby Debug – how else are you gonna squash those bugs?
  • Heroku – Easiest way to deploy your app to the “cloud” free!
  • Capistrano & Nginx – Good if you want to deploy to your own servers. I recommend looking at Rackspace Cloud Servers if you choose this route.
  • Bootstrap – Front-end framework. Scaffolding.. they’ve figured out HTML structure and CSS apparently because I sure haven’t
  • RailsCasts – Many helpful screencasts, highly recommended.
  • Rack Middleware – Ruby webserver interface that Rails is built around, you can inject functionality to your apps easily by developing your own middleware
  • Progress Keynote by David Heinemeier Hansson¬†– Damn.. and I thought my last name was tough!
  • How key-based Cache Expiration Works – Looking to fix some bottlenecks? Begin here
  • Capybara & Selenium – Launch an actual browser for your integration tests, it’s also necessary for testing your JavaScript

Paid Websites

  • PeepCode – helpful screencasts on a variety of Rails-related topics

Rails has_many through with conditions

Does your join table require an extra column for additional context?

Fortunately Rails has got you covered.

class User < ActiveRecord::Base
  has_many :user_groups, :dependent => :destroy

  attr_accessible :name
end

class UserGroup < ActiveRecord::Base
  belongs_to :user
  belongs_to :group

  validates :role, :presence => true,
                   :inclusion => { :in => %w(moderator normal),
                                   :message => "%{value} is not a valid role" }

  attr_accessible :user, :group, :role
end

class Group < ActiveRecord::Base
  # Without conditions
  has_many :user_groups, :dependent => :destroy
  has_many :users, :through => :user_groups

  # Define conditions on the relationship to the join model.
  has_many :moderator_groups, :class_name => 'UserGroup', :conditions => { :role => 'moderator' }

  # Define source on the through relationship.
  has_many :moderators, :through => :moderator_groups, :source => :user

  attr_accessible :name
end

Now to add moderators to a group, we can just do:

group.moderators << @user

or

group.moderators.create(user_attributes)

How to locate missing test files in your Rails app

Wanna make sure you have each of your controllers, models, templates, etc.. all have corresponding tests? I wrote a little bash script to make sure each class has its own spec file. Simple yet effective :). For more in-depth analysis, try a complete code-coverage tool like https://github.com/colszowka/simplecov.

spec/untested.sh:

#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
#echo $DIR

echo ""
echo "Untested Controllers"
echo "===================="
CONTROLLERS="$(find -E "${DIR}/../app/controllers" -iregex ".*\.rb")"
for f in $CONTROLLERS;
do
        CONTROLLER=${f##*/}
        SPEC=${CONTROLLER/.rb/_spec.rb}
        FOUND="$(find "${DIR}" -path "*${SPEC}")"
        if [[ $FOUND == "" ]]; then
                echo "-${CONTROLLER}"
        fi
done

echo ""
echo "Untested Models"
echo "==============="
MODELS="$(find -E "${DIR}/../app/models" -iregex ".*\.rb")"
for f in $MODELS;
do
        MODEL=${f##*/}
        SPEC=${MODEL/.rb/_spec.rb}
        FOUND="$(find "${DIR}" -path "*${SPEC}")"
        if [[ $FOUND == "" ]]; then
                echo "-${MODEL}"
        fi
done

echo ""
echo "Untested Templates"
echo "=================="
TEMPLATES="$(find -E "${DIR}/.." -iregex ".*(_default|_builder|_player).rabl")"
for f in $TEMPLATES;
do
        TEMPLATE=${f##*/views/}
        SPEC=${TEMPLATE/.rabl/_spec.rb}
        #echo $SPEC
        FOUND="$(find "${DIR}" -path "*${SPEC}")"
        #echo $FOUND
        if [[ $FOUND == "" ]]; then
                echo "-${TEMPLATE}"
        fi
done

echo ""