<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Gray Soft / Rails</title>
  <id>tag:graysoftinc.com,2014-03-20:/categories/1</id>
  <updated>2014-04-10T21:25:30Z</updated>
  <link rel="self" href="http://graysoftinc.com/rails/feed.xml"/>
  <link rel="alternate" href="http://graysoftinc.com/rails"/>
  <author>
    <name>James Edward Gray II</name>
  </author>
  <entry>
    <title>The Nice New Italian Restaurant of Server Monitoring</title>
    <link rel="alternate" href="http://graysoftinc.com/rails/the-nice-new-italian-restaurant-of-server-monitoring"/>
    <id>tag:graysoftinc.com,2008-04-23:/posts/50</id>
    <updated>2014-04-10T21:25:30Z</updated>
    <summary>An early announcement about I project I'm very excited to have worked on.</summary>
    <content type="html">&lt;p&gt;David Heinemeier Hanson, the creator of Rails, has made &lt;a href="http://www.37signals.com/svn/posts/981-the-secret-to-making-money-online"&gt;one of his business strategy talks&lt;/a&gt; available recently.  This is a great talk about how we all might be trying just a little too hard at what can be a fairly simple task.&lt;/p&gt;

&lt;p&gt;We all hear advice like this over and over again, but we seem to forget it so fast that we need that constant reminding.  Just today I saw a site redesigned to improve a section users haven't even seen yet (as that section isn't yet public).  Is that really the top use of resources for an unlaunched portion of the site?  How do we know they wouldn't have liked it?  How do we know they will like the new version better?  I'm sure it won't surprise readers to learn that this site is over budget on time and money.&lt;/p&gt;

&lt;p&gt;The point of all of this is that I want to tell you about a new server monitoring tool &lt;a href="http://highgroove.com/"&gt;the company I work for&lt;/a&gt; has recently launched.  The new service is called &lt;a href="http://scoutapp.com/"&gt;Scout&lt;/a&gt; and we've done our dead-level best to keep to the simplicity principal both because we agree with David and because we flat out need it to work that way.&lt;/p&gt;

&lt;p&gt;We build Rails applications for clients.  That involves monitoring servers, naturally.  If that process is heavy, it hurts our business in a very real way.  We need to spend our time writing Rails code, not fiddling with server configurations.  We've used many tools available for this in the past, but none of them hit our sweet spot.  In short, we need to be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup a new client for monitoring in minutes&lt;/li&gt;
&lt;li&gt;Have a centralized interface where we can check up on all of our client machines&lt;/li&gt;
&lt;li&gt;Receive timely notification when events we deem important occur (or fail to occur)&lt;/li&gt;
&lt;li&gt;Be able to examine seemingly random data points side by side to locate possible trends&lt;/li&gt;
&lt;li&gt;Add any new data we can think up to the tracking quickly and easily&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;That's exactly what Scout does.  Installing it on a new client involves filling out a short web form, installing a gem, and setting up a Cron job.  You can then check in on all of your client machines at any time through the web interface or even have daily reports emailed to you.  Scout can also email you alerts, say when a client fails to check-in or when your free disk space falls below a number you are comfortable with.  You can graph any data from the clients that makes sense to graph, separately or with other data points.  Oh, and adding a plugin to track anything you can think of is as simple as building a simple little Ruby script.&lt;/p&gt;

&lt;p&gt;If that sounds like the low-hassle server monitoring you have been waiting for, bounce on over to the site and &lt;a href="https://scoutapp.com/subscriptions"&gt;test drive one of our free trials&lt;/a&gt;.  My hope is that you will find, as we did, that this dramatically reduces the work needed to keep tabs on servers.&lt;/p&gt;</content>
    <author>
      <name>James Edward Gray II</name>
    </author>
  </entry>
  <entry>
    <title>Five ActiveRecord Tips</title>
    <link rel="alternate" href="http://graysoftinc.com/rails/five-activerecord-tips"/>
    <id>tag:graysoftinc.com,2008-04-10:/posts/49</id>
    <updated>2014-04-10T21:19:41Z</updated>
    <summary>Here's my best effort at showing some ActiveRecord voodoo.</summary>
    <content type="html">&lt;p&gt;This article was written for the &lt;a href="http://railscasts.com/contest"&gt;Railcasts 100th Episode Contest&lt;/a&gt;.  I think the idea is great and I look forward to reading great tips from all who decide to participate.&lt;/p&gt;

&lt;h4&gt;1. &lt;code&gt;create_or_find_by_…&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;I imagine most of you know that &lt;code&gt;ActiveRecord&lt;/code&gt; can handle finders like:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="no"&gt;MyARClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_or_create_by_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will attempt to find the object that has &lt;code&gt;some_name&lt;/code&gt; in its &lt;code&gt;name&lt;/code&gt; field or, if the find fails, a new object will be created with that &lt;code&gt;name&lt;/code&gt;.  It's important to note that the order is exactly as I just listed it:  find then create.  Here are the relevant lines from the current Rails source showing the process:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find_initial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;
  &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:attributes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;guard_protected_attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;#{'yield(record) if block_given?'}&lt;/span&gt;
  &lt;span class="c1"&gt;#{'record.save' if instantiator == :create}&lt;/span&gt;
  &lt;span class="n"&gt;record&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="n"&gt;record&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above code is inside a &lt;code&gt;String&lt;/code&gt; literal fed to &lt;code&gt;class_eval()&lt;/code&gt;, which is why you see interpolation being used.&lt;/p&gt;

&lt;p&gt;Unfortunately, this process is subject to race conditions because the object could be created by another process (or &lt;code&gt;Thread&lt;/code&gt;) between the find and the creation.  If that happens, you are likely to run into another hardship in that calls to &lt;code&gt;create()&lt;/code&gt; fail quietly (returning the unsaved object).  These are some pretty rare happenings for sure, but they can be avoided under certain conditions.&lt;/p&gt;

&lt;p&gt;I find myself typically using &lt;code&gt;find_or_create_by_…&lt;/code&gt; for things like category groupings or geocoded locations.  In my case, there always seems to be two unique properties I can count on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I don't allow duplicate listings&lt;/li&gt;
&lt;li&gt;I don't have to worry about entries being deleted from the database&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;When both of those conditions are true, you can rewrite the Rails helper method to be multiprocessing safe.  The steps are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build validations so that attempts to save the duplicate fail&lt;/li&gt;
&lt;li&gt;Be sure to use &lt;code&gt;create!()&lt;/code&gt; instead of &lt;code&gt;create()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reverse the order to &lt;code&gt;create!()&lt;/code&gt; then &lt;code&gt;find()&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Here's the practical example of how this plays out:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;validates_uniqueness_of&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_or_find_by_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;create!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="n"&gt;find_by_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The idea here is that we try the &lt;code&gt;create!()&lt;/code&gt; first and just let it fail if it doesn't validate (because it is a duplicate).  I use &lt;code&gt;create!()&lt;/code&gt; because it doesn't fail silently and the truth is that I generally prefer it for that very reason.  You could also use &lt;code&gt;create()&lt;/code&gt; and check the returned object with &lt;code&gt;new_record?()&lt;/code&gt;, if you prefer.  When the &lt;code&gt;create!()&lt;/code&gt; fails, we know it's safe to call the finder because there is definitely a matching entry in the database.&lt;/p&gt;

&lt;h4&gt;2. &lt;code&gt;find_all_in_chunks&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;I often want to scan whole tables in a Rails application, usually to generate reports about the data.  Of course, for very large tables, a call to &lt;code&gt;find(:all)&lt;/code&gt; is not generally a great idea as it uses up too much memory to slurp all of that data into Ruby objects.&lt;/p&gt;

&lt;p&gt;I have a tiny little library I drop in most Rails projects now to help with this.  It requires &lt;a href="http://github.com/mislav/will_paginate/tree/master"&gt;will_paginate&lt;/a&gt;, so be sure to install that plugin first.  Then just drop this code in &lt;code&gt;lib/find_all_in_chunks.rb&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;FindAllInChunks&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_all_in_chunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;upto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:per_page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_page&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FindAllInChunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and add this line to &lt;code&gt;config/environment.rb&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"find_all_in_chunks"&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The code is simple.  It just fetches the data in chunks by paginating the results and walking through the pages until it reaches the last one.  Each entry in the page is then &lt;code&gt;yield&lt;/code&gt;ed to the block you pass this finder.  This makes it seem like you are working with a simple &lt;code&gt;each()&lt;/code&gt; iterator, though it will eventually fetch all of the entries.  You can pass &lt;code&gt;will_paginate&lt;/code&gt;'s &lt;code&gt;:per_page&lt;/code&gt; parameter to adjust how many entries are retrieved at one time.&lt;/p&gt;

&lt;h4&gt;3. &lt;code&gt;FasterCSV&lt;/code&gt; as an Import Tool&lt;/h4&gt;

&lt;p&gt;If you need to jump start the database by importing some content, &lt;a href="http://rubyforge.org/projects/fastercsv/"&gt;FasterCSV&lt;/a&gt; can be a big help.  It can easily feed CSV data into an &lt;code&gt;ActiveRecord&lt;/code&gt; subclass using code like:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="no"&gt;FCSV&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;csv_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:headers&lt;/span&gt;           &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="ss"&gt;:header_converters&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:symbol&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;begin&lt;/span&gt;
    &lt;span class="no"&gt;MyARClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;RecordNotSaved&lt;/span&gt; &lt;span class="c1"&gt;# in current Rails&lt;/span&gt;
    &lt;span class="c1"&gt;# handle save failures here…&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This uses the first line of your CSV data as the field names, so be sure they match up to the names in your database.  It's also a good idea to make sure the CSV data is in UTF-8 and set &lt;code&gt;$KCODE = "U"&lt;/code&gt; when using an older version of Rails that doesn't do this for you.&lt;/p&gt;

&lt;p&gt;I tend to just vendor the &lt;code&gt;FasterCSV&lt;/code&gt; source and add a require for it in &lt;code&gt;config/environment.rb&lt;/code&gt;, so I don't have to worry about installing the gem everywhere.&lt;/p&gt;

&lt;h4&gt;4. Learn to Love &lt;code&gt;ActiveRecord&lt;/code&gt;'s &lt;code&gt;:select&lt;/code&gt; Parameter&lt;/h4&gt;

&lt;p&gt;I think the most under used feature of &lt;code&gt;ActiveRecord&lt;/code&gt;'s finders is the &lt;code&gt;:select&lt;/code&gt; parameter.  You really owe it to yourself to play with this sucker until you get the "Ah ha!" moment.&lt;/p&gt;

&lt;p&gt;The concept is simple:  &lt;code&gt;:select&lt;/code&gt; tells &lt;code&gt;ActiveRecord&lt;/code&gt; which columns to fetch from the database.&lt;/p&gt;

&lt;p&gt;By default, everything is fetched, but there are great reasons to exclude some fields.  For example, if you are grabbing a bunch of objects from a sizable table (meaning that it has many fields) but you only need certain fields, throw the rest out!  It will take &lt;code&gt;ActiveRecord&lt;/code&gt; less time to fetch the data and convert it to Ruby and use less memory, possibly making it practical for you to fetch more entries at once.  That's a lot of great gains!&lt;/p&gt;

&lt;p&gt;Another thing to know is that &lt;code&gt;ActiveRecord&lt;/code&gt; takes the field names it uses from the names provided here so use SQL's &lt;code&gt;AS&lt;/code&gt; to get what you want.  You can even add aggregate fields and alias them so they are just like normal fields for this query.&lt;/p&gt;

&lt;p&gt;This has a million different applications, but, to give an example, I pull some email campaign statistics by type using a query like:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="n"&gt;statistics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt;
  &lt;span class="ss"&gt;:select&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"profiles.type, "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
             &lt;span class="s2"&gt;"COUNT(DISTINCT users.id) AS emailed, "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
             &lt;span class="s2"&gt;"COUNT(IF(profiles.viewed_offer = 1, 1, NULL)) AS viewed, "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
             &lt;span class="s2"&gt;"COUNT(IF(profiles.signed_up = 1, 1, NULL)) AS accepted, "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
             &lt;span class="s2"&gt;"COUNT(IF(users.email_status = 'Opted Out', 1, NULL)) AS unsubscribed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:joins&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"INNER JOIN users ON users.id = profiles.user_id "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
             &lt;span class="s2"&gt;"INNER JOIN emailings ON emailings.user_id = users.id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:group&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"profiles.type"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this database a &lt;code&gt;User&lt;/code&gt; &lt;code&gt;has_many&lt;/code&gt; &lt;code&gt;Profile&lt;/code&gt;s and &lt;code&gt;Emailing&lt;/code&gt;s are associated with &lt;code&gt;User&lt;/code&gt; objects.  I use &lt;code&gt;:joins&lt;/code&gt; to link all of that together here.  (The &lt;code&gt;:include&lt;/code&gt; option seems to override your custom &lt;code&gt;:select&lt;/code&gt; so I just use &lt;code&gt;:joins&lt;/code&gt; instead.)  Note that I &lt;code&gt;INNER JOIN&lt;/code&gt; these tables to cut down on the data fetched.  It's handy to remember that there are more options to SQL than just what &lt;code&gt;ActiveRecord&lt;/code&gt; uses.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;:select&lt;/code&gt; parameter is the juicy part here.  I setup a group of aggregate fields to track the statistics we care about, aliasing each of these to nice method names for the returned objects.&lt;/p&gt;

&lt;p&gt;This single query combs through a ton of data very quickly and returns all the vital details we care about.  Now it's important to note that what is returned here aren't really &lt;code&gt;Profile&lt;/code&gt; objects as we typically think of them.  These are more summary objects that have a new set of methods we defined in this query (&lt;code&gt;emailed()&lt;/code&gt;, &lt;code&gt;viewed()&lt;/code&gt;, &lt;code&gt;accepted()&lt;/code&gt;, &lt;code&gt;unsubscribed()&lt;/code&gt;).&lt;/p&gt;

&lt;h4&gt;5. Sneaking in a &lt;code&gt;HAVING&lt;/code&gt; Clause&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;ActiveRecord&lt;/code&gt; doesn't have a parameter for including a &lt;code&gt;HAVING&lt;/code&gt; clause in your database queries and I sometimes find myself needing it.  Luckily, you can sneak it in on the end of your &lt;code&gt;:group&lt;/code&gt; parameter without needing to resort to a &lt;code&gt;find_by_sql()&lt;/code&gt; call.  (I don't recall ever using &lt;code&gt;HAVING&lt;/code&gt; without &lt;code&gt;GROUP BY&lt;/code&gt;, though there probably are some cases where it would make sense to do so.)&lt;/p&gt;

&lt;p&gt;As an example, here's a query from one of my Rails applications that finds all duplicate email addresses in the database:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="n"&gt;duplicates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:select&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"email, COUNT(email) AS duplicate_count"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"email IS NOT NULL AND email != ''"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:group&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"email HAVING duplicate_count &amp;gt; 1"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</content>
    <author>
      <name>James Edward Gray II</name>
    </author>
  </entry>
  <entry>
    <title>What Not to Test</title>
    <link rel="alternate" href="http://graysoftinc.com/rails/what-not-to-test"/>
    <id>tag:graysoftinc.com,2006-01-15:/posts/4</id>
    <updated>2014-03-27T15:47:39Z</updated>
    <summary>Even test junkies like me have some things we don't test.  Let me tell you about one that might just surprise you.</summary>
    <content type="html">&lt;p&gt;I've now seen multiple claims amounting to something like, "I built this Rails application with just testing."  I think it's great that people can do that.  They are obviously smarter than me.  I need a browser to build a Web application.&lt;/p&gt;

&lt;p&gt;I do test my Rails projects, of course.  I'm a huge fan of testing and I'm always telling people how much it could help with their work.  However, I believe there's a time to test and a time not to, if you can imagine that.  Yes, you heard me right, there are things I &lt;em&gt;don't&lt;/em&gt; test and I'm sure this next revelation will shock you even more:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I don't test Rails views.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now before everyone fires up their mail client and pours on the hate mail, let's make sure we are very clear about what I just said.  I do write thorough unit tests for all of my model classes, of course.  I also test the controllers as much as possible.  I make sure the data I expect ends up in the right instance variables with the magic &lt;code&gt;assigns()&lt;/code&gt;.  I also use the &lt;code&gt;session&lt;/code&gt; &lt;code&gt;Hash&lt;/code&gt; to validate what I am remembering about the user.  If a controller action is a complex logic branch that can end up in several different places, I will also make sure I add some assertions to verify that the right template handled the response.&lt;/p&gt;

&lt;p&gt;All I said is that I don't test the view layer.  I'm talking about the final HTML pages here.  Those are what I don't validate.&lt;/p&gt;

&lt;p&gt;Now that we are clear about what I don't test, let's cover why I don't.  I assure you this isn't some random choice or even an attempt to avoid work.  I have found that not testing the views works out better for me and I want to share my reasons with you.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; As I've already hinted at, I'm constantly viewing my Rails work in a Web browser.  If there's a problem, I'm going to see it pretty quickly.  In fact, I have a much better chance of seeing some browser oddities than I do of successfully coding a test to catch them, I think.&lt;/li&gt;
&lt;li&gt; If you are doing Rails correctly, the only programming logic in your templates is flow control, right?  (Helpers are a legitimate exception here, but you can test them normally.)  That makes your templates little more than data files in my eyes and I don't validate the contents of data files.&lt;/li&gt;
&lt;li&gt; HTML pages change rapidly.  Practically each time I look at a page, I will tweak something.  If that breaks a test, I just have to change two things instead of one.  To me, that's the whole point of data files, I can change them without worrying about the code that relies on them.&lt;/li&gt;
&lt;li&gt; The main tool for testing views, &lt;code&gt;assert_tag()&lt;/code&gt;, is a clever but flawed helper.  Have you seen what it spits out when the test starts failing?  "I couldn't find tag xyz in this-giant-mess-of-unformatted-HTML."  To me, that's like saying, "I couldn't find this needle in this haystack.  You try."  Even a great tool like &lt;code&gt;unit_diff&lt;/code&gt; can't fix that.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;All of that adds up to the fact that I am already visually checking what view tests would be checking.  I feel I am more thorough and accurate than the tests I know how to write for this process.  It's also a low risk area, since I'm not hiding any important functionality in the templates.  Given all of the above, I feel I lose nothing and gain speed by not writing those tests.&lt;/p&gt;

&lt;p&gt;This is just my system, of course.  Obviously, others are doing things differently.  I just wanted to share what is working for me.&lt;/p&gt;</content>
    <author>
      <name>James Edward Gray II</name>
    </author>
  </entry>
  <entry>
    <title>Add to Subversion</title>
    <link rel="alternate" href="http://graysoftinc.com/rails/add-to-subversion"/>
    <id>tag:graysoftinc.com,2006-01-04:/posts/1</id>
    <updated>2014-03-28T20:40:02Z</updated>
    <summary>A quick tip for building a Subversion Rake task that will add new files to your project.</summary>
    <content type="html">&lt;p&gt;I love Rails generators and I love Subversion, but I'm not so sure they love each other.&lt;/p&gt;

&lt;p&gt;Little is worse than generating some scaffold files or a login system, tediously typing &lt;code&gt;svn add ...&lt;/code&gt; a bunch of times, and later learning that you missed a file.  Oops.&lt;/p&gt;

&lt;p&gt;Given that, here's my hack to get the Rails generators and Subversion to kiss and make up:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Add generated files to Subversion"&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:add_to_svn&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="sx"&gt;%Q{svn status | ruby -nae 'system "svn add \\&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vg"&gt;$F&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;" if $F[0] == "?"'}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I put that in "lib/tasks/add_to_svn.rake" for all my Rails projects.  You can then access it whenever you need with &lt;code&gt;rake add_to_svn&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I've seen similar tasks posted, but they've always been Unix specific and I work with some Windows programmers.  This is my attempt to help both on platforms.&lt;/p&gt;

&lt;h4&gt;How does it work?&lt;/h4&gt;

&lt;p&gt;You're probably not use to seeing ugly Ruby code like that, but Ruby supports a lot of command-line shortcuts that it inherited from Perl.  Here's a breakdown of the options used:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;-e The code to execute directly follows this option.
-n Wrap my code in a standard Unix filter style processing loop.
-a Auto-split each line of input.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Together they mean that Ruby sees the above input as something close to:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="no"&gt;ARGF&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each_line&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="vg"&gt;$F&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;

  &lt;span class="c1"&gt;# my custom code is inserted here...&lt;/span&gt;
  &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="s2"&gt;"svn add &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vg"&gt;$F&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vg"&gt;$F&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"?"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That just asks Ruby to call &lt;code&gt;svn add ...&lt;/code&gt; for each file &lt;code&gt;svn status&lt;/code&gt; flagged with a "?".  Those will be all the files Subversion doesn't yet recognize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;:  Make sure you've told Subversion to ignore files you don't want it messing with (like Rails's log files), or they will be added!&lt;/p&gt;</content>
    <author>
      <name>James Edward Gray II</name>
    </author>
  </entry>
</feed>
