Pluralize your own way in Ruby on Rails

I have faced a situation on a project where we needed the distinction between a single 'media' and multiple 'media.' By default, Rails will pluralize 'media' to the same thing:

'media'.pluralize #=> 'media'

In our Rails app, that was unacceptable; we had a Media model, and multiple media could belong to a single other model. We needed a way to distinguish between a single media and multiple media. After some discussion about what we should go with, we decided with 1 'media' and 2 'medias.' How to get Rails to recognize this?

You can create an initializer where you can keep all of your non-default pluralizations: config/initializers/inflectors.rb. In that file you can add the following:

ActiveSupport::Inflector.inflections do |inflect|
  inflect.irregular 'media', 'medias'
end

Restart your app, and now it should pluralize 'media' correctly:

'media'.pluralize #=> 'medias'

If you don't want Rails to try to pluralize at all, then you can tell the inflector to not count that word with inflect.uncountable 'media'. This means that when .pluralize is called on that string, it will always return that same unchanged string.

Note that the inflectors initializer usually comes with pretty descriptive commented out instructions already in the file to help you along. That's a good resource to turn to, as well as the great documentation out there on the internets.

Testing &block Arguments with Rspec

In my example, I have a service that calls OpenURI's open, which accepts a block as one of its arguments:

class MyService

  def call_response
    open("http://website.com/api", http_basic_authentication: ["username","password"], &:read)
  end
end

In this case, that last argument calls .read on the response automatically to get to its body. Now I'd like to test the following:

  1. A block argument gets passed in to open
  2. The block argument that gets passed in is specifically the &:read

You can do both very simply all in one spec with Rspec:

require 'spec_helper'

describe MyService do

  describe "#open"

    it "calls read on response" do
      my_service = MyService.new
      expect(my_service).to receive(:open) do |url, authentication, &block|
        expect(block).to eq :read.to_proc
      end

      my_service.call_response
    end
  end
end

Track the Activity History of Your Embedded Mongoid 3 Documents with the mongoid-history Gem

Recently on my Rails 3 project, we had to keep track of all the updates made to our mongoid documents. There are multiple gems out there to help with this, but the best ones were only compatible with Mongoid 4 (and Rails 4), not functioning with embedded documents, or only recording that something was updated without keeping track of the previous values. We had to settle for the most basic gem for the job: the mongoid-history gem. The biggest struggle was figuring out how to get the gem to keep track of history of embedded documents. This is why I would like to share the solution.

To set up history tracking for your embedded (and the embedders), follow the these steps:

  1. Add the following to your Gemfile:

    gem 'mongoid-history', '~> 0.4'
    gem 'mongoid_userstamp', '~> 0.4'
    

    The mongoid_userstamp gem is for letting mongoid-history track the users who made the changes.

  2. Run bundle install in the command line to install your gems.

  3. Create an initializer under config/initializers called mongoid_history.rb and add the following to it:

    Mongoid::History.tracker_class_name = :history_tracker
    Mongoid::History.current_user_method = :current_user
    
    Rails.env == 'development' and require_dependency(Mongoid::History.tracker_class_name.to_s)
    

    The reason you must add that last line about requiring the history track dependency, is because the development environment doesn't necessarily load all of the classes; you must make sure the history tracker gets loaded. And with Mongoid::History.current_user_method you're letting the mongoid_userstamp know where to get the user for the change. In this case, I'm using Devise in my app, so the current_user method will do the job.

  4. Add the tracker to your parent model, and setup its children (the embedded documents) to get tracked as well:

    class Parent
      include Mongoid::Document
      include Mongoid::History::Trackable
    
      field :name, type: String
    
      embeds_many :children, cascade_callbacks: true
      accepts_nested_attributes_for :children
    
      track_history on: [:name]
    end
    
  5. Add the tracker to your child model:

    class Child
      include Mongoid::Document
      include Mongoid::History::Trackable
    
      field :name, type: String
    
      embedded_in :parent
    
      track_history 
    end
    
  6. Now try updating a parent instance's name, then go to your console and you should be able to view that parent's update history with parent.history_tracks.to_a.

  7. Next, update a child instance's name, and you should be able to view that child's update history through its parent with child.history_tracks.to_a.

How to Set Up and Run a Separate Set of Tests with Their Own Spec Helper File

There may come a time when you don’t want to run all of your tests together. A common example is wanting to split out running slow integration tests and unit test. On one of my projects we needed a separate set of tests to run at intervals just to make sure some of the numbers were within safe bounds, so we had to set up completely separate tests. This involved setting up a different spec_helper configuration for the different set of tests. Here, I will do a quick walkthrough of how to set up and run those tests.

  1. Create a directory for your test set under your main application directory (not under spec). I’ll use the directory name 'separate_verification' as an example.
  2. Create a spec helper file under the separate_verification directory, and call it separate_verification_spec_helper.rb and configure it as you need to. I personally prefer to copy from spec/spec_helper.rb and tweak from there—it’s much less scary when you don’t have to start completely from scratch.
  3. Add your tests to separate_verification directory. Make sure to include require "separate_verification" at the top of your spec files.
  4. To run your tests, you have to specify the directory of the spec_helper file to use, in addition to specifying the tests to run: rspec -I separate_verification/ separate_verification/

And that’s it!

Note that it is advisable to also create a separate test environment for your tests (in my example, you would create a separate 'separate_verification' environment) if you’re messing around with specific data. It would be safe so that there aren’t any unexpected side-effects due to leftover data when running your regular specs.

The Basics of How to Take Advantage of the Rails Asset Pipeline (for v3.2)

You may have heard of the term "asset pipeline" used in the Rails context and wondered what it was and how to set it up. I've recently read up on the details about it (http://guides.rubyonrails.org/asset_pipeline.html) and had to set up my project to use it, and I'm happy to explain in brief the why and how if you want to just jump right into it.

The most basic point of the asset pipeline is to speed up page load time for your users. Most applications have many javascript libraries and css stylesheets that may take a while to load fully when somebody goes onto your site—especially for the first time.

There are a few things Rails can do for your javascript and css libraries to make them smaller and more likely to get cached:

  1. Put all the code into a single file.
  2. Compress that file; make it the smallest file possible (remove extra spaces, shorten variable names, and even things like turning if/else statements into ternaries just to save room).
  3. Digest that file; this is also known as 'fingerprinting.' This will make a unique sha based on the contents of the file, which will automatically change if the contents are changed in any way. The sha is stuck to the end of the filename. This takes advantage of the fact that some caching is based on file name. So if nothing changes in your code, then there's no need for your user to have to wait for their browser to download the file again.

To take advantage of this, you need to take a few steps. Please note that these are instructions for Rails 3.2, since that is the version my project is currently using. To see the most up-to-date instructions and notes of any updates to the process, please go to the official guide: http://guides.rubyonrails.org/asset_pipeline.html. Tip: for instructions for a specific version, you can add your rails version number into that url, like so http://guides.rubyonrails.org/v3.2.19/asset_pipeline.html

Now let's get on with it!

  1. Place all of your javascript files under app/assets/javascripts and all of your css files under app/assets/stylesheets
  2. Add //=require_tree . to app/assets/javascripts/application.js and *= require_tree . to app/assets/stylesheets/application.css. require_tree will recursively grab your script files and load them in an order you cannot control. If you need to control the order, you can specify the name of your files beforehand with require [filename without the extension]
  3. Add gem 'uglifier' to the assets group in your Gemfile. This will figure out how to make your javascript file much smaller.
  4. In your config/environments/development.rb, I advise you to add config.assets.debug = true. This will stop your asset files from being converted to one huge file when running your application locally, so when you're debugging in the console it'll be easier.
  5. In all of your other environments add the following to your config/environments/[environment_name].rb:

    config.assets.digest = true
    config.assets.compress = true
    config.assets.debug = false
    config.assets.js_compressor  = :uglifier
    
  6. run the following in your application's directory, and add it to your deployment script: rake RAILS_ENV=[environment_name] RAILS_GROUP=assets assets:precompile

And that's it, folks. Please note that I left out a lot of details deliberately so you can get up and running with the asset pipeline fast, but I recommend that you read the official rails documentation on it when you have a chance.

How to get to the source code of a Ruby gem

Often enough I’ve followed the instructions to installing a gem in my rails application, just to see it not work. Eventually, I would have to uninstall the gem since it wasn’t working for me, and would have to either settle for a not-as-good other gem, or reinvent the wheel and write a solution to the problem again.

What I didn’t know was that you could reveal the gem’s source code in your text editor of choice. You’re actually able to do some debugging to--hopefully--get that gem working with your app.

All you have to do is go to your project’s directory in your terminal, and

  1. Set up your editor (using vim as my editor as an example): export BUNDLER_EDITOR=vim
  2. Reveal the gem’s source (using jquery-rails gem as an example): bundle open jquery-rails

And now you can not only view the directory and file composition of the gem, but you can also debug it by placing a binding.pry within it—this will stop the execution of your application at that line, and you can interact with your application at that point in the terminal where your rails server is running.

How to write more readable url strings that have parameters in Ruby

On my current project, we are using many queries to Solr in the form of a url. In some instances, this could mean unreadable and confusing and I’m-not-even-going-to-try-to-change-this url strings. For example, we could have something like (and this is an easier version of urls we use!):

number_of_rows = 10

url = "http://path.to.my.solr.instance.com/solr?q=(!field_1:* AND !field_2:* AND !field_3:\"VALUE1\" AND !field_4:\"VALUE2\")&rows=#{number_of_rows}&fl=field_5&wt=json&indent=true"

uri = URI.encode url

I personally find it hard to read, and change. Not to mention that this line runs really long—you’d have to scroll to the right to get all of it. And notice how we also have to call URI.encode on the url to uri encode special characters. What if I told you that it can be better?

The answer to this problem is transforming the query parameters in your url to a hash, like so:

number_of_rows = 10

url_path = "http://path.to.my.solr.instance.com/solr"
url_parameters = {
     "q" => "(!field_1:* AND !field_2:* AND !field_3:\"VALUE1\" AND !field_4:\"VALUE2\")",
     "rows" => number_of_rows,
     "fl" => "field_5",
     "wt" => "json",
     "indent" => "true"
}

uri = "#{url_path}?#{url_parameters.to_query}"

Now you can clearly see the url path, as well as each parameter clearly. Also note how number_of_rows doesn’t have to be interpolated anymore, allowing your text editor to highlight the fact that it’s a variable. By creating a parameter hash and calling .to_query on it, you get another bonus: the uri encoding. Pretty cool stuff!

Note that .to_query method is only available within Rails. You can have the same functionality, though, if you are writing Ruby without Rails by making use of Rack::Utils:

require "rack/utils"

number_of_rows = 10

url_path = "http://path.to.my.solr.instance.com/solr"
url_parameters = {
     "q" => "(!field_1:* AND !field_2:* AND !field_3:\"VALUE1\" AND !field_4:\"VALUE2\")",
     "rows" => number_of_rows,
     "fl" => "field_5",
     "wt" => "json",
     "indent" => "true"
}
uri = "#{url_path}?#{Rack::Utils.build_query url_parameters}" 

And there you have it, folks: much more readable and editable url strings.