Posted by admin Fri, 29 May 2009 22:23:00 GMT

‘jaap’ wrote a rake task to convert your Rails application from using Gettext translation into the new I18n support, which is really great!

WARNING: Before you run the new rake task rake gettext_to_i18n:transform, read “So How Do You Fix It?” below

OK, so you’ve followed along in the article and now you want to test out your new localization system. Problem is when you try to start the server up script/server you get this error message:

/Users/cblackburn/Source/ruby/bols/lib/active_support/memoizable.rb:71:in `path': can't modify frozen object (TypeError)

…or something similar.

What happened? Since you have frozen Rails and the rake task does not exclude the frozen vendor/rails directory, it modified memoizable.rb in ActiveSupport causing this error.

So How Do You Fix It?

Do one of the following:

  • Backup lib/active_support/memoizable.rb before you run the rake task, then restore it after.
  • Restore lib/active_support/memoizable.rb using your SCM.

For this project in my case it was

svn revert lib/active_support/memoizable.rb

Posted by admin Wed, 13 May 2009 18:55:00 GMT

Recently I upgraded my blog here and lost permalinks to several articles, as well as the articles themselves. For that I apologize, if you are looking for something unfound. One such article that I referred to often was ‘Scripting Mac Terminal Using Ruby’. Though this is not the original article, here is a script I recently needed. As will all source code published herein, this is hereby released into the public domain with no warranties of any kind.

This humble little script uses rb-appscript, to change the background color, in Terminal, of the current tab you are running. I like to change colors of tabs to mean different things. For instance, where I am tailing log files – dark green… running irb – dark blue, etc.

Maybe, like me, you stay logged into several machines around the world and want to color-code your tabs based on location.

I called mine colorme.rb. The command line expects a color in this format:

  • array: [0,32767,65535] of color values [Red, Green, Blue], 0 to 65535
  • string: ‘red’, ‘green’, ‘black’, etc., only the basic colors work as strings

Have fun and let me know if you are doing something interesting with Terminal using Appscript on Ruby.

#!/usr/bin/env ruby

require 'rubygems'
require 'appscript'
include Appscript

_color = (ARGV.length > 0) ? ARGV[0] : 'black'

begin
  term = app('Terminal')
  current_window = term.windows.first
  tab = current_window.tabs.first
  current_color = tab.background_color.get
  puts "Current Color is: #{current_color.inspect}"
  tab.background_color.set(_color)
rescue Exception => e
  puts "#{e}"
  puts "Usage: colorme.rb array"
  puts "  ...where array is an array of 3 color values like this [0,32767,65535]"
  puts "  ...values can be anywhere between 0 and 65535"
  puts "  ...values, in order, represent 'Red, Green Blue'"
end

Posted by admin Tue, 18 Nov 2008 06:00:00 GMT

A few people have asked me for the module I’ve been using to profile my code in my “Double Quotes vs. Single Quotes”:/2008/06/10/ruby-performance-use-double-quotes-vs-single-quotes article. It is merely a wrapper around “RubyProf”:http://ruby-prof.rubyforge.org/, dead simple and nothing worth commenting on, but since some keep asking – here it is:

require 'rubygems'
require 'ruby-prof'

module PeepcodeProfiler
  def time_this(comment, &block)
    RubyProf.measure_mode = RubyProf::PROCESS_TIME
    RubyProf.start
    yield
    result = RubyProf.stop
    puts "\nTimings for #{comment}"
    printer = RubyProf::FlatPrinter.new(result)
    printer.print(STDOUT, 0)
  end
end

I wrote this for some work on a “Scaling Rails” minibook for “Peepcode”:http://peepcode.com/, which I seem to be unable to finish. I hope Geoffrey forgives me.

Posted by admin Thu, 06 Nov 2008 06:00:00 GMT

Between the time your migration files get generated and deploying to production with your new application you will likely need to add indexes to one or more of your tables. How do you know which tables need indexes and which fields in those tables to index?

Here are some tips to help figure out where the likely bottlenecks will occur with regard to your database tables:

  1. Always index @*_id@ foreign_key fields. Let’s say you have 2 tables, @users@ and @addresses@. You may have migration file code in @./db/migrate@ that looks like this:
  ...
  def self.up
    create_table "users", :force => true do |t|
      t.column :login, :email             :string
    end
  end
  ...
  ...
  def self.up
    create_table "addresses", :force => true do |t|
      t.column :user_id       :integer
      t.column :address       :string
    end
  end
  ...

You will always want to index the foreign_key @user_id@, with few exceptions. So simply add the @add_index@ line like this:

  ...
  def self.up
    create_table "addresses", :force => true do |t|
      t.column :user_id       :integer
      t.column :address       :string
    end
    add_index "addresses", :user_id
  end
  ...

This will facilitate much faster associations when you lookup related models like this view code:

  <%=h user.address.address %>
  
  # OR as the case may be...
  
  <%=h address.user.email %>
  1. As a rule of thumb index any column for which you will be using to lookup a row or set of rows. For example, if you will be doing something like this:
  u = User.find_by_email('test@example.com')

… then you will want to index the email field.

  1. Run explain plans on your associations to determine where indexes would benefit the queries. Now this one is more tricky unless you know about the query_analyzer plugin. This nifty little tool will automatically dump out explain plans into your logfiles in development mode that look like this example from the README file:
# development.log

P Load (0.008669)
 => SELECT p.* FROM p INNER JOIN d ON p.id = d.p_id WHERE (d.p_id = 2 AND ((d.type = 'P')))

Analyzing P Load

select_type | key_len | type   | Extra       | id | possible_keys | rows | table  | ref    | key
 ----------------------------------------------------------------------------------------------------
SIMPLE      |         | ALL    | Using where | 1  |               | 74   |    d   |        |
SIMPLE      | 4       | eq_ref | Using where | 1  | PRIMARY       | 1    |    p   | d.p_id | PRIMARY

Now what this tells you is that the table @d@ is missing an index because MySQL is having to look at “ALL” the records. Whenever you see a @type@ of @ALL@ and/or @possible_keys@ is empty it should be a red flag telling you to index something.

If we had followed tips 1 and 2 this explain plan would be much different, showing reference types of @ref@ and @eq_ref@ which is typically a good thing.

For more information see the README file here: http://agilewebdevelopment.com/plugins/query_analyzer.

Posted by admin Tue, 18 Sep 2007 05:00:00 GMT

If you are getting an error message like this:

ActiveRecord::StatementInvalid: Mysql::Error: Table configurable_settings doesn't exist

… when trying to use Jacob Radford’s http://agilewebdevelopment.com/plugins/acts_as_configurable

Just do this:

./script/console development ConfigurableSetting.create_table

Of course replace ‘development’ above with whatever environment you need.

Posted by admin Thu, 31 May 2007 23:48:00 GMT

If you are experiencing the error: “undefined class/module MyClass” when fetching data from memcached, be assured that you are not alone. It is a known bug and the simplest way I know of to get around it is to reference the class or classes right before you retrieve data from the cache.

For example, if the following code causes the problem:

if not (genres = Cache.get(key))
  genres = Genre.find(:all, :condition => "platform_id = 1")
  Cache.put(key, genres, 60*60*24) # cache for 1 day
end

… then this code will work around it:

Genre
if not (genres = Cache.get(key))
  genres = Genre.find(:all, :condition => "platform_id = 1")
  Cache.put(key, genres, 60*60*24) # cache for 1 day
end

Notice the ‘Genre’ reference before the if statement. Some have reported success by using the ‘model’ statement within the controller, however that is deprecated. This workaround will get you going again.

Posted by admin Wed, 23 May 2007 23:47:00 GMT

I am fairly anal about my code and the code that my firm (CBCI) produces. I like it to be formatted perfectly. It makes me cringe to even have a single extra space out of place, borking the indentation. Using tabs for indentation instead of spaces should be grounds for termination. :-D

In addition to perfect indentation, I don’t like scrolling to the right in my editor to view long lines of code. This can usually be handled properly by adding linefeeds. Consider the following example:

sql = %Q{
  SELECT
    users.id,
    users.username,
    users.email,
    users.created_at,
    users.activated_at,
    users.confirmed_at,
    affiliations.custom1 as affiliation_custom1,
    affiliations.custom2 as affiliation_custom2,
    affiliations.custom3 as affiliation_custom3,
    campaigns.name as affiliation_campaign_name
  FROM users
  LEFT OUTER JOIN affiliations ON affiliations.user_id = users.id
  LEFT OUTER JOIN campaigns ON campaigns.id = affiliations.campaign_id
}

There are several ways to handle this type of long string. First, for SQL statements, extra spaces in front of each line don’t matter, nor do the linefeeds. So the code above, using the ‘%Q’ method, would work just fine for building a string with spaces embedded. We could also use the lowercase ‘%q’ method which would wrap the string with single-quotes and prevent any escape sequences or interpolation of embedded expressions, which is fine since we don’t have any need for that in the above string. You could also wrap the quotation marks, single or double, around the string explicitly.

If you are working with a long character string, and are fussy about your code being formatted consistently, the indents will embed groups of spaces into your strings. As stated above, this technically doesn’t matter when considering SQL statements. In other cases where it does matter we use the Ruby HERE document as follows:

# first we extend the String class
class String
  def here_with_pipe
    lines = self.split("\n")
    lines.map! {|c| c.sub!(/\s*\|/, '')}
    new_string = lines.join(" ")
    self.replace(new_string)
  end
end

This strips off the leading whitespace and pipe character that gets embedded in the string using the HERE document like this:

  s = <<-end.here_with_pipe
    |This string will be concatenated
    |into a single line
    |containing no extra embedded spaces
    |and no line feeds.
  end

Isn’t Ruby cool!

Posted by admin Tue, 22 May 2007 23:46:00 GMT

Have you ever wanted to look at the call stack without raising an exception to do it?

caller.each {|c| puts c}

Posted by admin Fri, 06 Oct 2006 05:00:00 GMT

I have found myself needing to sort a hash collection often, by a value within the hashes. The last instance where I needed this was to sort an aggregated result set of multiple union queries. So sorting with an order by clause would not work across the unions.

The solution is below. I pass a sort_clause into the method that would look like this company_name asc or company_name desc.

def stats(sort_clause)

    # queries, etc.
    ...

    find_by_sql(sql).each do |acct|
      aid = acct.id.to_i
      results[aid] = {} unless results[aid]
      month = acct.monthname
      case (month)
        when 'last'
          results[aid][:spend_last] = acct.spend.to_f
        when 'this'
          results[aid][:spend_this] = acct.spend.to_f
        when 'total'
          results[aid][:company_name] = acct.company_name
          results[aid][:balance]      = acct.bal.to_f
          results[aid][:campaigns]    = acct.campaign_count.to_i
          results[aid][:keywords]     = acct.keyword_count.to_i
      end
    end

    sort_col, order = sort_clause.split(' ')
    logger.debug("sort_clause: #{sort_clause}")
    results = results.sort_by{ |item|
      item[1][sort_col.intern]
    }
    if (order =~ /desc/i)
      results.reverse!
    end
    results
end

Posted by admin Wed, 03 Jan 2007 06:00:00 GMT

I’ve used SmartWhois at all-nettools.com for years. It is usually very fast and returns pertinent data, yet leaving out the normal ARPA registration junk that I don’t often care about.

Here is a Ruby script that will post an IP address to the online tool and parse the results for the command line, showing information about the party that owns the particular IP being searched. It will also accept hostnames.

You’ll need Hpricot and hpricot_helper.rb along with some other standards.

You can script it using a list of ip addresses like this:

cat iplist | while read ip; do
    ./smartwhois.rb $ip
done

Enjoy