Safe Access for Temporary ActiveRecord Fields in Rails

I run into a fairly common problem in rails views when I'm pulling data from multiple tables.  To optmize on db access, I use :select to pre-load the data from the joined tables.  For example, let's say I want to list all users with their respective cities:

Then I don't have to load the Address model to display a user's city:

The problem is that my user partial is now coupled with my named scope:  if I render the partial without using the scope, I'll throw an exception.  To avoid the problem, I add an accessor method to the User model that will pull the pre-loaded data if available, and revert to using the Address model:

The partial will be inefficient, but I'd prefer to find the error when profiling view times rather than through exceptions.

Use rails date_select without an activerecord model

I actually googled this and found a workable but ugly solution:

 
 ## view code
<%= date_select('range', 'start_date', :order => [:month, :day, :year])%>


## controller code
@start_date = Date.civil(params[:range][:"start_date(1i)"].to_i,params[:range][:"start_date(2i)"].to_i,params[:range][:"start_date(3i)"].to_i) 

I needed to include the hour and minute as well, and didn't want to cram more arguments into the Date.civil call (actually Time.zone.local), so I cleaned up the code a bit.

Hoping to leave the internet a little better for the next guy, I thought I'd post the code.

 
 ## view code
<%= datetime_select('range_start', 'date', :order => [:month, :day, :year, :hour,:minute]) %>


# controller code
@start_date = Time.zone.local(*params[:range_start].sort.map(&:last).map(&:to_i)) 

Rails: Growing Pains With ActiveRecord

Rails, does it scale? 

That horse has been beaten to death, and there is ample evidence that it does scale with a little elbow grease where necessary.  

It's also commonly known that many of the rails convenience methods aren't terribly good at making complex queries.

What I've just realized, is that some of the seemingly simple operations are implemented with horrible efficiency (the current tech-lingo would be "non-performant" which makes me puke a little into my mouth when I write it). 

Today I found two big performance problems:

HABTM relation creation

Take the following:

You would expect that code to do a single insert for all the join entries.  In reality you get something like this, repeated for each bar:

bars_foos Columns (1.1ms) SHOW FIELDS FROM bars_foos SQL (0.6ms) INSERT INTO bars_foos (bar_id, foo_id) VALUES (100, 117200)

I hand coded sql to do the same thing, and found a 7x speedup:

 

HABTM relation deletion

This one should be a layup:

@foo.bars = []

but I was shocked to see this in my sql log:

 

I hand coded the trivial sql and got a 10x speedup:

 

In Conclusion

These aren't difficult or complex operations, and they're extremely common.

I looked into ar-extensions, but there doesn't seem to be any support for HABTM relation creation.

I guess for now these queries should be hand-coded once tables get to a certain size, but I'm still in minor disbelief.  Anyone with a better "Rails Way" to do this, please clue me in.

Sanitizing Names for Files

I use database records for file names when generating reports, but some of those have invalid characters. The attachment_fu plugin has the sanitize_filename method, but I wasn't so happy with the output, e.g.,

 
 >> sanitize_filename("foo & bar") 
=> "foo___bar" 
 >> sanitize_filename("14th @bar") 
=> "14th__bar" 

 
So I wrote a prettier sanitization helper:

 
which gives me:
 
 >> sanitize_for_filename(" foo & bar ") 
=> "foo_and_bar" 
 >> sanitize_for_filename("14th @bar") 
=> "14th_at_bar" 

 
Much better.

shortening urls

@codinghorror posted "trying to formulate an algorithm for collapsing a long URL legibly." This sounded like a fun distraction from a semi-painful monday, and the first thing that occurred to me was using letter frequencies to prune urls down. I couldn't resist coding it up to see how well it would work.
 
First, here's the code:

 
So, for example:

 
>> url = "http://my.com/makethis/longish/url/shorter"
 >> host = "http://my.com/"
 >> shorten_url(url,host,7)
=> "http://my.com/makthis/longish/url/shorter"
 >> shorten_url(url,host,6)
=> "http://my.com/makhis/lngish/url/shortr"
 >> shorten_url(url,host,5)
=> "http://my.com/mkhis/lngsh/url/shorr"
 >> shorten_url(url,host,4)
=> "http://my.com/mkhs/lgsh/url/shrr"
 >> shorten_url(url,host,3)
=> "http://my.com/mks/lgh/url/srr"
 


not bad for a first cut

rails sitemap entries for pages without models

In building a sitemap for my rails app, I went off of this blog post:
 
http://tonycode.com/wiki/index.php?title=Ruby_on_Rails_Sitemap_Generator
 
but I have public-facing pages for which no ActiveRecord model exists.
 
I  added the following to my sitemap controller to add entries for a given
controller:

Then, for example, in my controller I just call:

@info_pages = get_public_action_urls(InformationPagesController)

 

and finally, in my view:

@info_pages.each do |entry|
  xml.url do
  xml.loc entry
  xml.lastmod w3c_date(Time.now)
  xml.changefreq "weekly"
  xml.priority 0.9
  end
end

oh, and in my sitemap_helper:

def w3c_date(date)
     date.utc.strftime("%Y-%m-%dT%H:%M:%S+00:00")
end

 

rails environments with workling

I use mongrel_cluster to manage my rails app settings, and handle the actual start/stop tasks via monit. It would be asking for trouble to hard-code the rails environment in my monitrc file, so I modified listen.rb in the workling plugin to take a config file argument.
 
With that done, i just needed to modify my monitrc file to start my working process with the path to my mongrel_cluster config file.
 
It seems like there should be a better way to handle this, but the documentation on workling is almost non-existent.
 
workling.rb edits:



and then my monit start command for workling:

 
start program = "/path/to/workling_client start -- -c /path/to/mongrel_cluster.yml"