Time to do something about validate & validates?

I think it’s about time we did something about the validate and validates methods in ActiveModel.

Having two methods with such similar names that do similar things but in a totally different way is extremely confusing. What’s more, if you do use validate instead of validates by mistake, no exceptions are raised and MyModel.valid? will return true.

I have trouble remembering which one I should be calling, and I’ve been working with Rails for years now. I can’t imagine how confused a novice programmer would be…

Perhaps renaming validate would be the way to go (with proper deprecation warnings, of course)?

Adapted from a message to the Ruby on Rails: Core mailing list, all constructive discussion should happen there.

New Yorker cover story: Nelson Mandela

New Yorker cover story: Nelson Mandela

(December 16th, 2013)

Mandarin liqueur

Mandarin liqueur

Yup, that’s 12kg of malt, hops, and other stuff like that…

Yup, that’s 12kg of malt, hops, and other stuff like that…

My mandarin liqueur is on the way!

My mandarin liqueur is on the way!

Middleman on Heroku (with Nginx)

nginx ❤️ Middleman


⚠️ This article is outdated, please see the Middleman on Heroku – 2017 edition post for a more up to date guide on how to deploy Middleman sites to Heroku.


In my last blog post about Middleman on Heroku, Middleman was configured to be served via the Puma application server.

By following this guide, you can setup your middleman site to be served by Nginx, which should be a lot more robust for static sites. If you already have a Middleman site in a git repo, you can skip the first few steps.

Install Middleman (if you haven’t already):

gem install middleman

Create a new Middleman site (and change into that directory):

middleman init beer_catalogue
cd beer_catalogue

Initialise the git repository and commit everything:

git add .
git commit -am "Everything"

Create a new Heroku app (if you omit the name Heroku will generate one for you):

heroku create beer-catalogue

Configure Heroku to use the multi-buildpack (with the Nginx and Ruby buildpacks):

heroku config:set BUILDPACK_URL='https://github.com/ddollar/heroku-buildpack-multi.git'
echo 'https://github.com/ryandotsmith/nginx-buildpack.git' >> .buildpacks
echo 'https://codon-buildpacks.s3.amazonaws.com/buildpacks/heroku/ruby.tgz' >> .buildpacks
git add -f .buildpacks
git commit -m 'Add multi-buildpack'

Create a file called nginx.conf.erb in the config directory (create the directory if it doesn’t already exist) and give it the following contents:

daemon off;
# Heroku dynos have 4 cores.
worker_processes 4;


events {
  use epoll;
  accept_mutex on;
  worker_connections 1024;
}


http {
  gzip on;
  gzip_comp_level 2;
  gzip_min_length 512;


  log_format l2met 'measure#nginx.service=$request_time request_id=$http_heroku_request_id';
  access_log logs/nginx/access.log l2met;
  error_log logs/nginx/error.log;


  include mime.types;
  default_type application/octet-stream;
  sendfile on;


  # Must read the body in 5 seconds.
  client_body_timeout 5;


  server {
    listen <%= ENV["PORT"] %>;
    server_name _;
    keepalive_timeout 5;
    root <%= ENV["HOME"] + "/build" %>;
  }
}

In the root of your project, update create the Procfile with the following contents:

web: bundle exec middleman build && bin/start-nginx -f sleep infinity

Commit these changes:

git add .
git commit -am "Nginx configuration"

And finally, push your Middleman site to Heroku:

git push heroku master

Once the push completes, you should be able to access the app at yourappname.herokuapp.com

HTTP Headers

If you want to, feel free to edit the nginx and Middleman config files to suit your needs (e.g. add additional cache headers or turn on directory indexes).

Whoop!

Whoop!

New version of plupload-rails is out

Log rotation on OS X (for projects in development)

Logs on your development machine can quickly grow to a silly size, especially if you have long running projects.

An easy cure for this is to set-up logrotate (newsyslog on OS X) to rotate the logs once they grow past a certain point (1MiB in the example below), after all most of the time you’ll only be interested in the last few lines of your logs…

Create a new file in /etc/newsyslog.d called dev-logs.conf with the following contents:

# logfilename [owner:group] mode count size when flags [/pid_file] [sig_num]
/Users/USER/Programming/**/log/*.log USER:staff 644 2 1024 * G

You’ll need sudo rights in order to do this (the config file should be owned by root:wheel).

Note:

  1. Replace /Users/USER/Programming with the full path to your projects folder, e.g. /Users/bob/Programming
  2. Replace the USER in USER:staff with your username, e.g. bob:staff

The globbing pattern explained:

All log files within a log directory in any of your projects within your programming folder

Using MockSMTP or MailCatcher only if it's running (with Ruby on Rails)

MockSMTP screenshot

MockSMTP (€8,99) and MailCatcher (open-source) are great tools when you’re trying to debug emails, but not everyone on your team necessarily has one of them installed (or maybe you just don’t have one of them running constantly).

In case you don’t know what MockSMTP and MailCatcher do: they’re essentially SMTP servers for development. Instead of sending emails to their intended recipients, they collect them and give you a nice UI where you can inspect them at your leisure.

Using MailCatcher or MockSMTP conditionally in development is actually pretty easy and only requires you to add a few lines of code to your development.rb file:

require "net/smtp"

ThanksForAllTheFish::Application.configure do
  # … other settings redacted …

  # Try to sniff out if MockSMTP or MailCatcher is running
  begin
    smtp = Net::SMTP.start "localhost", 1025
    if smtp.started?
      smtp.quit
      puts ">> WARNING: Found an SMTP server on port 1025"
      puts "   Assuming that it is MockSMTP or MailCatcher..."
      puts ">> Emails WILL be sent to the SMTP server on port 1025"

      config.action_mailer.delivery_method = :smtp
      ActionMailer::Base.smtp_settings = {
        address: "localhost",
        port: 1025
      }
    end
  rescue Errno::ECONNREFUSED
  end

  # … other settings redacted …
end

What does this code do? First of all we require NET::SMTP so that we can use it to detect whether there is a server on port 1025 (luckily both MockSMTP and MailCatcher use port 1025 by default).

Secondly we try to start an SMTP connection to port 1025. If the connection starts, we know that there’s an SMTP server running there and thus we can configure Rails to use it to send emails. If the connection doesn’t start, we don’t need to do anything.

Port 1025 isn’t a standard port for SMTP, so there’s little danger that we’d end up sending real emails to people from our development machine. If someone has a live SMTP server running on a non-standard port on their development machine we can assume that they know what they’re doing and can deal with the consequences.