Read my latest article: 8 things I look for in a Ruby on Rails app (posted Thu, 06 Jul 2017 16:59:00 GMT)

Sending email: Controllers versus Models

Posted by Mon, 16 Nov 2009 14:33:00 GMT

While reviewing some code recently, I came across controller code that resembled the following.

if @customer.save
  CustomerMailer.deliver_welcome_message(@customer)
  flash[:message] = "Your account has been successfully created. We've sent you a welcome letter with..."
  redirect_to dashboard_path
else
  ...
end

Fairly typical Rails code. Nothing alarming here, but I wanted to evaluate the call to the mailer in this scenario. When it comes to sending emails from your application, you can choose to do it from the controller as in the example above or in your models. Our team prefers to do this from our model via a callback as we are considering this to be part of our business logic.

Each time a customer is created, we want to send them an email. This can be moved into the model and resembled something like the following..

after_create :send_welcome_message #, other callbacks..

def send_welcome_message
  CustomerMailer.deliver_welcome_message(self)
end

There are a few benefits to doing it this way.

  1. We can test that this is being triggered within our model specs instead of our controller specs. (we prefer to spend more of our time working within models than controllers)
  2. We remove the dependency that all requests must be processed through our controllers.
    • Example: We may one day create rake tasks that data and want these emails to still be sent out. (We’ve had to do this a few times)

I definitely don’t think doing this via controllers is a bad idea, I just lean towards keeping controllers as dumbed down as possible. This allows us to have less controller code that is focused on passing data to/from models and letting our models do the heavy lifting.

UPDATE: DHH was kind enough to post a more detailed response on his blog.

Using BETWEEN for SQL comparisons

Posted by Sat, 14 Nov 2009 19:55:00 GMT

Recently, Carlos, suggested that I should start sharing some basic SQL tips that help with performance and/or general usage. I recently came across some code that I didn’t like to read and/or write. For example, let’s take the following…


SELECT * FROM brochures WHERE published_at <= now() AND archived_at >= now()

Essentially, this is pulling back some data WHERE the the brochures are considered published. (We have a project that allows people to manage their brochure launch dates ahead of time.) In fact, in this project, we have no less than 6-8 dates in the database that we’re comparing data on and it’s easy to get lost in the logic when trying to understand it.

Now, there isn’t anything inheriently wrong with how this condition is constuctued. As a matter of personal taste, I find it annoying to mentally parse. Also, I find having to write now() more than once in a WHERE clause to feel like I’m repeating myself.

Read it outloud…

“WHERE the brochures published at date is less than and/or equal to right now AND the archived date is greater than and/or equal to now.”

Who talks like that?

Luckily, there is a better and in my opinion, a more readable way to express this is with the BETWEEN construct in SQL. (postgresql docs, mysql docs)


SELECT * FROM brochures WHERE now() BETWEEN published_at AND archived_at

Let’s read this outloud…

“WHERE the current date is between the published at and archived at dates.”

This sounds more natural to me.

Additionally, you can also do the inverse with NOT.


SELECT ... WHERE now() NOT BETWEEN brochures.published_at AND brochures.archive_at

Remember kids, “code is for humans first and computers second.”—Martin Fowler

Launching Ruby on Rails projects, the video

Posted by Wed, 11 Nov 2009 17:00:00 GMT

For those of you who didn’t make it to Rails Underground in July to witness my mind-blowing talk, Launching Ruby on Rails projects , it appears that Skills Matter has finally posted a video of it online. :-)

The sound levels are really low… but hopefully you’ll find it helpful.

You can also view the slides.

Related Posts

Planet Argon Podcast, Episode 3: How We Manage Bugs

Posted by Wed, 11 Nov 2009 16:46:00 GMT

Earlier this week, we published Episode 3 of the Planet Argon Podcast. In this latest episode we responded to one of the ideas someone in the audience asked on this brainstormr, which was, “How do you manage bugs?”

We had a round table discussion about how we classify and prioritize bugs with our clients, ticketing systems, and other tools that we use to streamline this process.

You can listen to this on iTunes or online.

Tracking Google Analytics events in development environment with GoogleAnalyticsProxy

Posted by Sun, 01 Nov 2009 18:55:00 GMT

1 comment Latest by Justin Gallagher Sun, 03 Jan 2010 22:11:32 GMT

As mentioned in a recent article1, I’ve been diving deep into Google Analytics lately while working on a few client projects. We’re aiming to use much more of the features of Google Analytics and have been hitting some roadblocks with the development versus production application environments. Once you begin to dive into event tracking and AJAX-driven goal conversions, relying on just the sample code that Google Analytics provides you is going to result in you looking at a handful of JavaScript errors.

pageTracker is not defined

another example from the firebug javascript console…

firebug pageTracker is not defined

We see JavaScript errors like this because we don’t load the google analytics code in our development environments. As you can see, we are only loading this in our production environment.

  <% if RAILS_ENV == 'production' -%>
    <!--// Google Analytics //-->
    <script type="text/javascript">
    var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
    document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
    </script>
    <script type="text/javascript">
    var pageTracker = _gat._getTracker("UA-XXXXXX-1");
    pageTracker._trackPageview();
    </script>
  <% end -%>

To track an event with Google Analytics, you’d need to trigger something like:

  pageTracker._trackEvent('Button', 'Click', 'Get in touch');

As you can see from our code earlier, in development, the pageTracker variable isn’t defined and that’s why we’re getting those JS errors. We also don’t want to add conditionals everywhere in our application to check if we’re in development or production environment.. as that’d just make our views uglier than they need to be. So, I decided that I’d create a proxy class in JavaScript that would allow us to trigger _trackEvent() and _trackPageview() and handle it appropriately.

This class works with the following logic:

  • if google analytics is loaded, pass the parameters to the real pageTracker
  • if google analytics is NOT loaded, output the information to console.log() for debugging purposes

For example, on a gallery on our web site… we track when people navigate next and/or previous through the photos. In our development environment, I can watch the JavaScript console output the following:

Firebug - GAP

And in our production environment, we can see that this was sent to Google Analytics.

Firebug - trackEvent()

We’re able to do this by initializing the GoogleAnalyticsProxy class and calling these functions through it. For example:

  _gap = new GoogleAnalyticsProxy();
  _gap._trackEvent('Video', 'Play', 'Homepage video');
  _gap._trackEvent('Video', 'Pause', 'Homepage video');
  _gap._trackEvent('Button', 'Click', 'Call to action X');

You’ll see that we’re just calling _gap versus pageTracker. We then replace all the instances of pageTracker (except where it is defined in the google analytics code block they provide you). You’ll find this located near the bottom of our application.html.erb file.

<% if RAILS_ENV == 'production' -%>
  <!--// Google Analytics //-->
  <script type="text/javascript">
  var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
  document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
  </script>
  <script type="text/javascript">
  var pageTracker = _gat._getTracker("UA-XXXXXX-1");
  pageTracker._trackPageview();
  </script>
<% end -%>

<script type="text/javascript">
  var _gap = new GoogleAnalyticsProxy();
</script>

We now have _gap available throughout our project and can call _trackEvent() and _trackPageview() with it. Note: You can use any JS variable name that you want, _gap is just what I went with.

Get GoogleAnalyticsProxy

I’ve gone ahead and tossed this small JavaScript class (known as GoogleAnalyticsProxy) on Github for your enjoyment. I have some more articles in the works that will show you some tips for how to make the most of Google Analytics. If you have any questions and/or ideas for related article topics, don’t hesitate to let me know.

1 Tracking AJAX-driven events in Ruby on Rails for Google Analytics conversion goals