Autonomous Machine

Posts tagged with Rails

Use Active Model Serializers with Mongoid

I'm adding some new features to Forkchop using Ember, ember-rails, and the associated active_model_serializers. The only hiccup is that I'm using Mongoid, and Active Model Serializers only hooks into Active Record when it loads. This means that Rails doesn't automatically look for the appropriate serializer when using render json: @object.

To remedy this, I added the following lines from this Gist to config/initializers/mongoid_active_model_initializers:

Mongoid::Document.send(:include, ActiveModel::SerializerSupport)
Mongoid::Criteria.delegate(:active_model_serializer, to: :to_a)
  • May 05, 2012
  • Article
  • Active Model Serializers, Ember, Mongoid, Rails

Tell Sprockets to precompile files other than application.js

I usually bundle all of a Rails project's JavaScript together. Occasionally, only a few pages need a large JavaScript library, and I don't want it to have to be downloaded on every page of the application. In these situations, I don't require the large library file or it's dependencies in application.js so it won't be bundled with the rest of the project's scripts. I'll add a script tag for the library to just the pages that need it, which works locally in development mode. And then inevitably I deploy and the additional files can't be found on the server because they haven't been precompiled.

It is in the docs, but I always seem to forget that for Sprockets to precompile anything other than application.js, the additional files must be specifed in config/application.rb:

config.assets.precompile += ['another_file.js']

That's all there is to it.

  • March 17, 2012
  • Article
  • Rails, Sprockets

Inheritable Page Attributes in Rails

On most webpages there are a number of what I call 'page attributes'. These are little bits of data that have to be set based on the context of the app: the page title, a body class, etc.

It's easy enough to just use content_for to handle this scenario:

# in a view template
content_for(:title, 'Epic Page Title')

# in the page layout
yield :title

But I've found I often want to define these things at a higher level, perhaps at the controller level, either using a class method or inside an action body like this:

class UnicornsController
  page_attr :body_class, 'unicorns'
  def party
    # such a special action deserves a special class
    page_attr :body_class, 'unicorn-party'
  end
end

Or even in a view:

<%- page_attr :body_class, 'out-of-control-unicorn-shindig' -%>

This is a contrived example, but the idea is page attributes are inherited the way one would expect (controller class -> controller action -> template), while potentially being overridden at the lower levels. Here's the code:

# in app/controllers/application_controller.rb
include PageAttributes

# in config/initilizers/requires.rb
require 'page_attributes'

# in lib/page_attributes.rb
module PageAttributes
  def self.included(base)
    base.helper_method :page_attr
    base.class_attribute :page_attributes
    base.page_attributes = {}
    base.class_eval do
      def self.page_attr(key, value)
        self.page_attributes[key] = value
      end
    end
  end

  protected

  def page_attr(key, value=nil)
    @page_attributes ||= {}
    if value.nil?
      @page_attributes[key] || self.class.page_attributes[key]
    else
      @page_attributes[key] = value
    end
  end
end
  • June 20, 2011
  • Article
  • Rails, Ruby

Tweaking Ruby Enterprise Edition's garbage collection settings to speed up tests

I've been looking at ways to get the test suite for a project I'm working on running faster, and I came across slides from a presentation that present several ways to speed up tests. In particular, there are some environment variables that you can use to control the behavior of REE's garbage collector. I've found that using the values suggested in the slides decreases my test run times by 20-30%:

export RUBY_HEAP_MIN_SLOTS=1000000
export RUBY_HEAP_SLOTS_INCREMENT=1000000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
export RUBY_HEAP_FREE_MIN=500000
export RUBY_GC_MALLOC_LIMIT=1000000000

I saved this script to my path, and when I want run Ruby with these settings, I prepend the command I'm running with 'rmem'. Or, as suggested by the slides, you can add the settings to your profile. Be careful, as they cause Ruby processes to use significantly more memory.

  • August 21, 2010
  • Article
  • Code, Rails, Rspec, Ruby

Carmen now supports states for nine countries

Thanks to Andriy Tyurnikov and Tobias Schmidt for recently adding support for the Ukraine and Germany, respectively. And to the others that have fixed bugs or brought issues to my attention.

Carmen is a collection of country and state names and abbreviations, along with replacements for the state_select and country_select plugins that leverage this data.

  • December 16, 2009
  • Article
  • Code, Rails, Ruby

Convert HTML to Haml within Textmate

I have been integrating a lot of well built HTML templates into Rails applications this week. I've found Haml to be the best templating language, and I like to convert preexisting templates to use it as I add them to a project.

The Haml gem installs a command line executable that performs this conversion, html2haml. The program takes whatever is passed as standard input, performs the conversion, and writes the result to standard out. For a while I was using command this in combination with the pbcopy/pbpaste commands (I work on a Mac) to apply this to the content of the clipboard:

pbpaste | html2haml | pbcopy

This worked, but the extra copying and pasting was annoying. So I made a TextMate command to eliminate the tedium:

Screenshot of the TextMate bundle editor

The actual command is this (it's a bit hard to see above):

echo $TM_SELECTED_TEXT | html2haml

You could add a key binding as well, but so far I haven't bothered to.

  • November 13, 2009
  • Article
  • Code, Mac, Rails, Ruby

Add an ActiveRecord scope for easier eager loading

In the optimization phase of a project, one of the first things I do is look for pages that could benefit from the use of ActiveRecord's eager loading. Since named_scopes were introduced in Rails 2.1, most of my model loading has involved a chain of scopes, and it is always frustrating to have to change

@blogs = Blog.published.active

to

@blogs = Blog.published.active.scoped(:include => [:slugs, :topic => :slugs])

It's a small difference, but one I've never really liked. It seems like an obvious choice would be to add a named_scope to all subclasses of ActiveRecord::Base and have that handle the :include parameter. I finally wrote the 11 lines of code required to do this today:

module ActiveRecord
  module EagerLoadScope
    def self.included(base)
      base.named_scope :eager_load, lambda { |*inclusion|
        {:include => inclusion}
      }
    end
  end
end

ActiveRecord::Base.class_eval { include ActiveRecord::EagerLoadScope }

And now that line looks like this:

@blogs = Blog.published.active.eager_load(:slugs, :topic => :slugs)

Again, it's a small improvement, but one I consider worthwhile.

  • October 28, 2009
  • Article
  • Code, Rails, Ruby

Hiding parts of a view while in development

Most of my recent projects have involved working with a front end developer, who would provide HTML/CSS templates with dummy content to be integrated into a Rails backend. During the process of wiring up the views, I often wish to hide a section of a template or partial until the models and controllers are setup to support them.

I've started using this little view helper to hide code in a view, while providing a console message to remind me to go back and address the issue when the time is right:

def hide(&block)
  if Rails.env == 'development'
    match, file, line = caller.first.match(/([^:]+):(\d+).+/).to_a
    Rails.logger.info "** Hiding content on line #{line} of #{file}"
  end
end

It's simple to use, especially in HAML:

- hide do
  = some_view_code_that_will_not_execute

The helper will print something like this to your console:

** Hiding content on line 14 of /Users/jimb/Projects/demo/app/views/objects/show.html.haml
  • September 11, 2009
  • Article
  • CSS, Rails, Ruby

Install Passenger and nginx from source on Ubuntu

Passenger 2.2.3 came out this week, and while up until now I was using the Ubuntu packages from Brightbox (great blokes, really), I was having some problems with serving caches files and I didn't want to wait for the package to be updated. The package itself can be found on Github if you'd like to see it in more detail.

I used a combination of two guides to get everything working: one at Slicehost's wiki and another blog post by someone whose name may or may not be Johnny Pez.

It can be a little confusing to jump back and forth between the two, so I've posted a compiled set of steps here. After working through this article, you can continue on with the second Slicehost article for setting up the rest of your environment.

Passenger

I'm going to assume you have Ruby and RubyGems installed. If not, do that first before continuing.

Install the Passenger gem:

sudo gem install passenger

Then you need to build the nginx extension, which will be needed when we compile it.

cd `passenger-config --root`
sudo rake nginx

nginx

You'll need to install nginx's prerequisites:

sudo apt-get install libpcre3 libpcre3-dev libpcrecpp0 libssl-dev

Then, download the nginx source and unpack it. Everyone seems to be using the legacy stable version of nginx, and I haven't tried any of the newer ones yet.

wget http://sysoev.ru/nginx/nginx-0.6.37.tar.gz
tar xzvf nginx-0.6.37.tar.gz

Now we need to configure nginx.

cd nginx-0.6.37
./configure --sbin-path=/usr/local/sbin --with-http_ssl_module  \
--add-module=`passenger-config --root`/ext/nginx

You can change the configure flags if you want (see the comments on the Slicehost article), but I've left them alone so the rest of Slicehost's articles can be followed without modification.

Assuming the configure succeeded, all that's left is to compile and install.

make
sudo make install

All Systems Go

To make sure everything is working, start nginx:

sudo /usr/local/sbin/nginx

Visit your server's IP, and you should see the nginx welcome screen. This is good! Kill nginx:

sudo kill `cat /usr/local/nginx/logs/nginx.pid`

Now continue on with the Slicehost series to complete your nginx configuration. You'll also probably want to mirror the default configuration layout (these articles specify Intrepid, but the steps will be pretty close on most recent versions of Ubuntu).

  • June 19, 2009
  • Article
  • Code, Installation, Rails, Ruby

Interrogation creates boolean accessors from named_scope declarations

This is a little hack I came up with today when I got tired of duplicating logic in scopes and accessor methods. If I define a method in a model like this:

class Submarine < ActiveRecord::Base
  named_scope :on_surface, :conditions => {:location => 'surface'}
  named_scope :submerged, :conditions => {:location => 'under water'}
end

I think I should be able to interrogate the model to see if it is in these scopes without needing to define Submarine#on_surface? or Submarine#submerged? This is what I want to be able to do:

sub = Submarine.first => #<Submarine id: 1, location: 'surface'>
sub.on_surface? => true
sub.submerged? => false

Interrogation will allow for exactly this. The first version would fire a database query on each call, but I've since added in an attempt at parsing simple conditions against a model's attributes, with a fallback to the database for complicated conditions.

One last thing

The largest problem with this approach is an object's state is not always in sync with the database. I've thought about this a lot, and at this point I think it's best to raise an exception when using these methods on dirty objects. I think handling dirty objects is beyond the scope of this little hack.

The code is on Github.

  • June 05, 2009
  • Article
  • Code, Rails, Ruby

Reloading Rails plugins in development mode

In Rails 2.3 you can cause your plugins to be reloaded with each request by adding this to your development.rb file:

config.reload_plugins = true

This was possible before, but it required altering Dependencies.load_once_paths and other black magic. I've always had issues with these approaches, and so it's nice to see official support for such a useful feature.

  • April 23, 2009
  • Article
  • Code, Rails, Ruby

Carmen: A Rails plugin for geographic names and abbreviations

On a recent project I became tired of state select and country select, the ubiquitous Rails plugins for providing a list of state or country names in views. I didn't like that their data was defined in code. Or that their data was defined in the view, so validating a model field against them was messy.

I started to refactor country select by moving the list of countries into a Geography module. But then I needed a list of states, and their abbreviations, and it struck me as odd that I needed two plugins that worked differently in order to provide what seemed to be some very basic functionality to my app.

Well she sneaks around the world, from Kiev to Carolina...

Carmen is the result of my frustration: a small unified library that handles country and state names and abbreviations. It stores its data lists in YAML, so it's easy to edit and add new state lists.

Carmen's primary use is providing a list of countries (or states within country), and, optionally, their abbreviations.

Carmen::states('US') => [['Alabama', 'AL'], ['Arkansas', 'AR'], ... ]
Carmen::state_names('US') => ['Alabama', 'Arkansas', ... ]
Carmen::state_codes('US') => ['AL', 'AR', ... ]

Similar methods are available for countries. It also has some convenience methods to assist in converting between names and abbreviations:

Carmen::country_name('US') => 'United States'
Carmen::country_code('Canada') => 'CA'
Carmen::state_code('Manitoba', 'CA') => 'MB'
Carmen::state_name('AZ', 'US') => 'Arizona'

Any of the state methods that require a country code will use a default country code if none is supplied. This defaults to 'US', but can be easily changed for those outside the US:

Carmen.default_country = 'CA'

And of course, it's simple to use Carmen in your model validations:

class Address < ActiveRecord::Base
  validates_inclusion_of :country, :in => Carmen::country_codes
end

Carmen also supplies view helpers that work the same as those in country select or state select, so it should be a drop in replacement in most cases. I've posted the docs, and the code is on Github.

  • April 01, 2009
  • Article
  • Code, Rails, Ruby

Git Error: fatal: reference is not a tree error

If you do what I do and keep your Rails plugins in separate git repos using git submodules, you will encounter a git error if you've made changes to the local repositories for a plugin and try to deploy without pushing the changes up to the server:

fatal: reference is not a tree: 17f1db7f33c986f0d4a9dc0c5846322095cda96b

To resolve this, cd into the relevant directory (vendor/plugins/whatever/) and push to the repo. It seems obvious, but I've made this mistake once or twice.

  • February 07, 2009
  • Article
  • Code, Rails

Using blocks in Rails custom date formats

A not-so-well known feature of ActiveSupport is its ability to handle blocks as definitions for custom date and time formats. Here's one I just added to a project to give nice short dates, stripping out any leading zeros:

ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(
  :shorty => lambda {|date| date.strftime("%m/%d/%y").gsub(/0?(\d+)\/0?(\d+)\/(\d+)/, '\1/\2/\3')}
)

You can drop that in your environment.rb; a better option is to place it in a file inside config/initializers.

  • January 15, 2009
  • Article
  • Rails, Ruby

Simple Rspec Markup Matcher

It seems like every project I've worked on recently involves some kind of markup processing. Here's what I've been using to test my markup processing:

module Spec
  module Matchers
    module Markup
      class MatchMarkup
        def initialize(expected)
          @expected = expected
        end

        def matches?(target)
          @target = target
          standardize(@target).eql?(standardize(@expected))
        end

        def failure_message
          "expected\n#{@target}\nto match\n#{@expected}"
        end

        def negative_failure_message
          "expected\n#{@target}\nto not match\n#{@expected}" 
        end

        # alphabetize the order of attributes
        def standardize(markup)
          clean_whitespace(markup).gsub(/( [a-zA-Z_]*="[^"])+"/) do |match|
            ' ' + match.strip!.split(' ').sort.join(' ')
          end
        end

        def clean_whitespace(markup)
          markup.
          gsub(/\s+/, ' '). # cleanup whitespace
          gsub(/>\s/, '>'). # kill space after tags
          gsub(/\s</, '<'). # space before tags
          gsub(/\s\/>/, '/>'). # space inside self-closing tags
          strip
        end
      end

      def match_markup(markup)
        MatchMarkup.new(markup)
      end
    end
  end
end

This matcher does two things that are helpful. It standardizes the order of attributes, which is crucial since most of the time HTML attributes are specified in Ruby using a hash and therefore their eventual order can't be guaranteed. It also removes all whitespace, so your specs can be easier on you.

Here's a totally contrived example:

it "should wrap with a div" do
  input = <<-HTML
    <p>
        In order to attain the greatest possible clearness,
        let us return to our example of the railway carriage supposed
        to be travelling uniformly.
    </p>
  HTML
  
  output = <<-HTML
      <div class="klass" id="div_3">
        <p>
          In order to attain the greatest possible clearness,
          let us return to our example of the railway carriage supposed
          to be travelling uniformly.
        </p>
      </div>  
  HTML
  
  wrap_with_div(input, :class => 'klass', :id => 'div_3').should match_markup(output)
end
  • October 01, 2008
  • Article
  • Rails, Rspec, Ruby