<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sean Huber]]></title><description><![CDATA[Software Engineer - San Francisco - Ruby, Rails, PHP, JS, Docker, Postgres, Vim]]></description><link>http://shuber.io/</link><generator>Ghost 0.5</generator><lastBuildDate>Sat, 04 Apr 2026 10:57:14 GMT</lastBuildDate><atom:link href="http://shuber.io/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Awesome Awesomeness]]></title><description><![CDATA[<p>I just came across this curated list of awesome curated lists! So meta, I love it!</p>

<ul>
<li><a href="https://github.com/bayandin/awesome-awesomeness">https://github.com/bayandin/awesome-awesomeness</a></li>
<li><a href="https://awesome-awesomeness.zeef.com/alexander.bayandin">https://awesome-awesomeness.zeef.com/alexander.bayandin</a></li>
</ul>]]></description><link>http://shuber.io/awesome-awesomeness/</link><guid isPermaLink="false">b044ed0f-bb33-4b2d-b968-c2724164b60e</guid><category><![CDATA[development]]></category><category><![CDATA[resource]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Tue, 23 Jun 2015 23:58:00 GMT</pubDate></item><item><title><![CDATA[Use the timestamptz shorthand for time zones in Postgres]]></title><description><![CDATA[<p>The following <code>CREATE TABLE</code> statements are equivalent:</p>

<pre><code>CREATE TABLE users (  
  id          serial PRIMARY KEY,
  username    text NOT NULL,
  created_at  timestamptz
);

CREATE TABLE users (  
  id          serial PRIMARY KEY,
  username    text NOT NULL,
  created_at  timestamp WITH TIME ZONE
);
</code></pre>

<p>Sure, it only saves us a few words, but now we're aware of it for future use!</p>

<p>Read more about <a href="http://www.postgresql.org/docs/9.1/static/datatype-datetime.html">Postgres Date/Time types</a> if you're interested!</p>]]></description><link>http://shuber.io/use-the-timestamptz-shorthand-for-time-zones-in-postgres/</link><guid isPermaLink="false">dbaf6180-8cc6-4544-aa3d-377bc12ae07d</guid><category><![CDATA[postgres]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Fri, 22 May 2015 01:22:00 GMT</pubDate></item><item><title><![CDATA[Porting ActiveRecord "soft delete" behavior to Postgres]]></title><description><![CDATA[<p>Let's try to implement the behavior of libraries like <a href="https://github.com/radar/paranoia">paranoia</a> and <a href="https://github.com/ActsAsParanoid/acts_as_paranoid">acts_as_paranoid</a> in Postgres!</p>

<p><a href="http://shuber.io/#tldr">tldr</a> - jump to the summary below!</p>

<p>We'll make it possible to restore deleted user accounts! Let's assume that we already have an existing <code>users</code> table with a few records.</p>

<pre><code>CREATE TABLE users (  
  id        serial PRIMARY KEY,
  username  text NOT NULL
);

INSERT INTO users (username) VALUES ('sean'), ('sam'), ('doug');  
</code></pre>

<p>Now let's <code>SELECT * FROM users</code> to see what we're working with.</p>

<pre><code> id | username 
----+----------
  1 | sean
  2 | sam
  3 | doug
(3 rows)
</code></pre>

<p>The first thing we can do is add a <code>deleted_at</code> <a href="http://www.postgresql.org/docs/9.1/static/datatype-datetime.html">timestamptz</a> column to <code>users</code>. We should also add an index for records with <code>deleted_at IS NULL</code> since those are the ones that we'll want to scope most of our queries to.</p>

<pre><code>ALTER TABLE users ADD COLUMN deleted_at timestamptz;

CREATE INDEX not_deleted ON users WHERE deleted_at IS NULL;  
</code></pre>

<p>Let's <code>SELECT * FROM users</code> again to see the changes.</p>

<pre><code> id | username | deleted_at 
----+----------+------------
  1 | sean     | 
  2 | sam      | 
  3 | doug     | 
(3 rows)
</code></pre>

<p>Now that we've got our new column, let's create a <code>TRIGGER</code> that intercepts <code>DELETE</code> statements and set's <code>deleted_at</code> instead of actually removing the record.</p>

<pre><code>CREATE TRIGGER soft_delete_user  
  BEFORE DELETE ON users
  FOR EACH ROW EXECUTE PROCEDURE soft_delete();
</code></pre>

<p>Let's check out out the implementation of <code>soft_delete()</code>.</p>

<pre><code>CREATE FUNCTION soft_delete()  
  RETURNS trigger AS $$
    DECLARE
      command text := ' SET deleted_at = current_timestamp WHERE id = $1';
    BEGIN
      EXECUTE 'UPDATE ' || TG_TABLE_NAME || command USING OLD.id;
      RETURN NULL;
    END;
  $$ LANGUAGE plpgsql;
</code></pre>

<p>There are a few interesting things here to note:</p>

<ul>
<li><code>TG_TABLE_NAME</code> - this variable contains the name of the table or view that initiated the <code>TRIGGER</code> call. In our case this variable evaluates to <code>users</code>. This allows us to reuse this same <code>soft_delete</code> function as a trigger on multiple tables! Check out the other special <a href="http://www.postgresql.org/docs/9.2/static/plpgsql-trigger.html">trigger variables</a>.</li>
<li><code>current_timestamp</code> - this returns the current timestamp with time zone. Check out the other built in <a href="http://www.postgresql.org/docs/9.1/static/functions-datetime.html">date/time functions</a>.</li>
<li><code>RETURN NULL</code> - this instructs Postgres to do nothing instead of deleting the row.</li>
</ul>

<p>Let's <code>DELETE FROM users WHERE id = 1</code> and then <code>SELECT * FROM users</code> to test!</p>

<pre><code> id | username |          deleted_at           
----+----------+-------------------------------
  2 | sam      | 
  3 | doug     | 
  1 | sean     | 2015-05-21 15:33:50.164675-07
(3 rows)
</code></pre>

<p>Soft delete works! Now we can restore deleted records by calling <code>SET deleted_at = NULL</code>.</p>

<p>But hold on, there's a couple of issues with this implementation!</p>

<ul>
<li>We can't actually <code>DELETE</code> records since the <code>TRIGGER</code> prevents it! What if we want to truncate users that we're deleted over a year ago?</li>
<li>We'll probably need to add <code>WHERE deleted_at IS NULL</code> conditions to multiple user related queries since we want to interact with the active ones most of the time.</li>
</ul>

<p>We can solve these issues by <a href="http://www.postgresql.org/docs/9.4/static/sql-createview.html">creating a view</a>!</p>

<pre><code>CREATE VIEW users_without_deleted AS  
  SELECT * FROM users WHERE deleted_at IS NULL;
</code></pre>

<p>Let's check out <code>SELECT * FROM users_without_deleted</code> to see if it works.</p>

<pre><code> id | username | deleted_at 
----+----------+------------
  2 | sam      | 
  3 | doug     | 
(2 rows)
</code></pre>

<p>Success! The user with <code>id = 1</code> does not exist in the results!</p>

<p>Most of the time we want to work with active users, not ALL users including the deleted ones. For convenience, let's rename our table and view.</p>

<pre><code>ALTER TABLE users RENAME TO users_with_deleted;  
ALTER VIEW users_without_deleted RENAME TO users;  
</code></pre>

<p>Now we can <code>SELECT</code> from <code>users</code> and not have to worry about adding <code>WHERE deleted_at IS NULL</code> all over the place! Since it's a simple view, we can <code>INSERT</code>, <code>UPDATE</code>, and <code>DELETE</code> to <code>users</code> as well!</p>

<p>Let's move our <code>TRIGGER</code> from our <code>users_with_deleted</code> table over to the <code>users</code> view instead. This allows us to soft delete when working with <code>users</code> and hard delete when working with <code>users_with_deleted</code>!</p>

<pre><code>ALTER TABLE users_with_deleted DROP TRIGGER soft_delete_user;

CREATE TRIGGER soft_delete_user  
  INSTEAD OF DELETE ON users
  FOR EACH ROW EXECUTE PROCEDURE soft_delete();
</code></pre>

<p>Let's review what we've got using <code>SELECT * FROM users_with_deleted</code>.</p>

<pre><code> id | username |          deleted_at           
----+----------+-------------------------------
  2 | sam      | 
  3 | doug     | 
  1 | sean     | 2015-05-21 15:33:50.164675-07
(3 rows)
</code></pre>

<p>We should be able to soft delete from the <code>users</code> view.</p>

<pre><code>DELETE FROM users WHERE id = 2;

SELECT * FROM users_with_deleted;

 id | username |          deleted_at           
----+----------+-------------------------------
  2 | sam      | 2015-05-21 15:34:30.164675-07
  3 | doug     | 
  1 | sean     | 2015-05-21 15:33:50.164675-07
(3 rows)
</code></pre>

<p>Now let's try to hard delete from the <code>users_with_deleted</code> table.</p>

<pre><code>DELETE FROM users_with_deleted WHERE id = 2;

SELECT * FROM users_with_deleted;

 id | username |          deleted_at           
----+----------+-------------------------------
  3 | doug     | 
  1 | sean     | 2015-05-21 15:33:50.164675-07
(2 rows)
</code></pre>

<p>Success! When we <code>SELECT * FROM users</code> there should only be one record!</p>

<pre><code> id | username |          deleted_at           
----+----------+-------------------------------
  3 | doug     | 
(1 row)
</code></pre>

<p>Thaigo brought up a great question in the <a href="http://shuber.io/porting-activerecord-soft-delete-behavior-to-postgres/#comment-2039740930">comments below</a>:</p>

<blockquote>
  <p>What if we want to add a <code>UNIQUE</code> index to <code>username</code>, but only for the non-deleted ones?</p>
</blockquote>

<p>If someone deletes their account, we need to allow them to recreate a new account in the future. This means that we can't solve it with a regular unique index like the following because the old deleted user still actually exists in the table.</p>

<pre><code>CREATE UNIQUE INDEX unique_username ON users_with_deleted (username);  
</code></pre>

<p>Instead, we can solve this issue by using a <a href="http://www.postgresql.org/docs/9.4/static/indexes-partial.html">partial index</a>!</p>

<pre><code>CREATE UNIQUE INDEX unique_username ON users_with_deleted (username) WHERE deleted_at IS NULL;  
</code></pre>

<p>Now the index is only applied to non-deleted users!</p>

<h2 id="tldr">tldr</h2>

<p>Here's a summary of what we ended up with:</p>

<pre><code>CREATE TABLE users_with_deleted (  
  id          serial PRIMARY KEY,
  username    text NOT NULL,
  deleted_at  timestamptz
);

CREATE INDEX not_deleted ON users_with_deleted WHERE deleted_at IS NULL;

CREATE UNIQUE INDEX unique_username ON users_with_deleted (username) WHERE deleted_at IS NULL;

CREATE VIEW users AS  
  SELECT * FROM users_with_deleted WHERE deleted_at IS NULL;

CREATE FUNCTION soft_delete()  
  RETURNS trigger AS $$
    DECLARE
      command text := ' SET deleted_at = current_timestamp WHERE id = $1';
    BEGIN
      EXECUTE 'UPDATE ' || TG_TABLE_NAME || command USING OLD.id;
      RETURN NULL;
    END;
  $$ LANGUAGE plpgsql;

CREATE TRIGGER soft_delete_user  
  INSTEAD OF DELETE ON users
  FOR EACH ROW EXECUTE PROCEDURE soft_delete();
</code></pre>

<p>If you enjoyed this, check out how to port ActiveRecord <a href="http://shuber.io/porting-activerecord-validations-to-postgres">validations</a> and <a href="http://shuber.io/porting-activerecord-counter-cache-behavior-to-postgres">counter cache</a> behavior to Postgres as well!</p>]]></description><link>http://shuber.io/porting-activerecord-soft-delete-behavior-to-postgres/</link><guid isPermaLink="false">ae551395-3664-4e56-8b76-c122e5228bd8</guid><category><![CDATA[rails]]></category><category><![CDATA[ruby]]></category><category><![CDATA[postgres]]></category><category><![CDATA[database]]></category><category><![CDATA[plpgsql]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Thu, 21 May 2015 23:25:00 GMT</pubDate></item><item><title><![CDATA[Porting ActiveRecord "counter cache" behavior to Postgres]]></title><description><![CDATA[<p>Let's try to mimic the following <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-belongs_to">belongs_to</a> relationship with <code>counter_cache</code> behavior in Postgres!</p>

<p><a href="http://shuber.io/#tldr">tldr</a> - jump to the summary below!</p>

<pre><code>class Comment &lt; ActiveRecord::Base  
  belongs_to :post, counter_cache: true
end

class Post &lt; ActiveRecord::Base  
end  
</code></pre>

<p>First we need to create the relevant tables and columns.</p>

<pre><code>CREATE TABLE posts (  
  id              serial PRIMARY KEY,
  title           text NOT NULL,
  body            text NOT NULL,
  comments_count  integer NOT NULL DEFAULT 0
);

CREATE TABLE comments (  
  id       serial PRIMARY KEY,
  post_id  integer NOT NULL REFERENCES posts(id),
  body     text NOT NULL
);
</code></pre>

<p>Then let's <code>INSERT</code> a sample post.</p>

<pre><code>INSERT INTO posts (title, body) VALUES  
  ('My first post!', 'Sample content.');
</code></pre>

<p>Now we can <code>SELECT * FROM posts</code> to see what we're working with.</p>

<pre><code> id |     title      |      body       | comments_count 
----+----------------+-----------------+----------------
  1 | My first post! | Sample content. |              0
(1 row)
</code></pre>

<p>Since we don't have any comments yet, the <code>comments_count</code> is already correctly set to <code>0</code>. We need to define a <code>TRIGGER</code> to increment or decrement the counter cache for a few different cases:</p>

<ul>
<li>when a new comment is added with <code>INSERT</code></li>
<li>when a comment is removed with <code>DELETE</code></li>
<li>when a comment's <code>post_id</code> is changed with <code>UPDATE</code></li>
</ul>

<pre><code>CREATE TRIGGER update_post_comments_count  
  AFTER DELETE OR INSERT OR UPDATE ON comments
  FOR EACH ROW EXECUTE PROCEDURE counter_cache('posts', 'comments_count', 'post_id');
</code></pre>

<p>Now that our trigger is in place we'll need to define the  functions that it relies on. Let's start by creating a function called <code>increment_counter</code> to handle the actual increment and decrement updates.</p>

<pre><code>CREATE FUNCTION increment_counter(table_name text, column_name text, id integer, step integer)  
  RETURNS VOID AS $$
    DECLARE
      table_name text := quote_ident(table_name);
      column_name text := quote_ident(column_name);
      conditions text := ' WHERE id = $1';
      updates text := column_name || '=' || column_name || '+' || step;
    BEGIN
      EXECUTE 'UPDATE ' || table_name || ' SET ' || updates || conditions
      USING id;
    END;
  $$ LANGUAGE plpgsql;
</code></pre>

<p>If we call <code>increment_counter('posts', 'comments_count', 99, 1)</code> then it executes the following SQL statement:</p>

<pre><code>UPDATE posts SET comments_count = comments_count + 1 WHERE id = 99;  
</code></pre>

<p>Now we just need to define the <code>counter_cache</code> function that ties our <code>TRIGGER</code> and <code>increment_counter</code> behavior together.</p>

<pre><code>CREATE FUNCTION counter_cache()  
  RETURNS trigger AS $$
    DECLARE
      table_name text := quote_ident(TG_ARGV[0]);
      counter_name text := quote_ident(TG_ARGV[1]);
      fk_name text := quote_ident(TG_ARGV[2]);
      fk_changed boolean := false;
      fk_value integer;
      record record;
    BEGIN
      IF TG_OP = 'UPDATE' THEN
        record := NEW;
        EXECUTE 'SELECT ($1).' || fk_name || ' != ' || '($2).' || fk_name
        INTO fk_changed
        USING OLD, NEW;
      END IF;

      IF TG_OP = 'DELETE' OR fk_changed THEN
        record := OLD;
        EXECUTE 'SELECT ($1).' || fk_name INTO fk_value USING record;
        PERFORM increment_counter(table_name, counter_name, fk_value, -1);
      END IF;

      IF TG_OP = 'INSERT' OR fk_changed THEN
        record := NEW;
        EXECUTE 'SELECT ($1).' || fk_name INTO fk_value USING record;
        PERFORM increment_counter(table_name, counter_name, fk_value, 1);
      END IF;

      RETURN record;
    END;
  $$ LANGUAGE plpgsql;
</code></pre>

<p>There are some interesting things here to note:</p>

<ul>
<li>We're using some special <a href="http://www.postgresql.org/docs/9.2/static/plpgsql-trigger.html">trigger variables</a>!</li>
<li><code>TG_ARGV</code> - this variable contains an array of the arguments that the trigger function was called with. Trigger functions do not support declaring named parameters!</li>
<li><code>TG_OP</code> - contains the name of the operation that fired the trigger e.g. <code>DELETE</code>, <code>INSERT</code>, or <code>UPDATE</code>.</li>
<li><code>NEW</code> and <code>OLD</code> - the <code>NEW</code> object refers to the newly inserted row. The <code>OLD</code> object refers to a deleted row. Since our trigger supports both <code>INSERT</code> and <code>DELETE</code> statements, we need to make sure that we're referring to the correct object.</li>
<li>Only triggers fired by <code>UPDATE</code> statements have both <code>NEW</code> and <code>OLD</code> objects present.</li>
<li><code>RETURN record</code> - our trigger needs to return the <a href="http://www.postgresql.org/docs/9.0/static/plpgsql-declarations.html#PLPGSQL-DECLARATION-RECORDS">record</a> being inserted or deleted, either <code>NEW</code> or <code>OLD</code> in this case.</li>
</ul>

<p>Let's <code>INSERT</code> some comments to see if the <code>comments_count</code> increments correctly for the post.</p>

<pre><code>INSERT INTO comments (post_id, body) VALUES  
  (1, 'This is a comment!'),
  (1, 'And this is another comment!'),
  (1, 'One more comment!');
</code></pre>

<p>If we <code>SELECT * FROM posts</code> again we should see an updated <code>comments_count</code>.</p>

<pre><code> id |     title      |      body       | comments_count 
----+----------------+-----------------+----------------
  1 | My first post! | Sample content. |              3
(1 row)
</code></pre>

<p>Success! Now if we delete the first comment then it should decrement the post's <code>comments_count</code> as well!</p>

<pre><code>DELETE FROM comments WHERE id = 1;

SELECT * FROM posts;

 id |     title      |      body       | comments_count 
----+----------------+-----------------+----------------
  1 | My first post! | Sample content. |              2
(1 row)
</code></pre>

<p>Let's try changing the a comment's <code>post_id</code> to make sure it handles that case correctly. First we'll need to add a second post.</p>

<pre><code>INSERT INTO posts (title, body) VALUES  
  ('Another post!!', 'Sample content.');
</code></pre>

<p>Then let's <code>SELECT * FROM posts</code> and <code>SELECT * FROM comments</code> to review our data.</p>

<pre><code> id |     title      |      body       | comments_count 
----+----------------+-----------------+----------------
  1 | My first post! | Sample content. |              2
  2 | Another post!! | Sample content. |              0
(2 rows)

 id | post_id |   body    
----+---------+-----------
  2 |       1 | Comment 2
  3 |       1 | Comment 3
(2 rows)
</code></pre>

<p>If we <code>UPDATE comments SET post_id = 2 WHERE id = 2</code> then we should see <code>comments_count</code> change for both posts!</p>

<pre><code>SELECT * FROM posts;

 id |     title      |      body       | comments_count 
----+----------------+-----------------+----------------
  1 | My first post! | Sample content. |              1
  2 | Another post!! | Sample content. |              1
(2 rows)
</code></pre>

<pre><code>SELECT * FROM comments;

 id | post_id |   body    
----+---------+-----------
  2 |       2 | Comment 2
  3 |       1 | Comment 3
(2 rows)
</code></pre>

<p>Awesome! It's pretty cool that we can define "macro" like triggers that are reusable across tables!</p>

<h2 id="tldr">tldr</h2>

<p>Here's a summary of what we ended up with:</p>

<pre><code>CREATE TABLE posts (  
  id              serial PRIMARY KEY,
  title           text NOT NULL,
  body            text NOT NULL,
  comments_count  integer NOT NULL DEFAULT 0
);

CREATE TABLE comments (  
  id       serial PRIMARY KEY,
  post_id  integer NOT NULL REFERENCES posts(id),
  body     text NOT NULL
);

CREATE FUNCTION increment_counter(table_name text, column_name text, id integer, step integer)  
  RETURNS VOID AS $$
    DECLARE
      table_name text := quote_ident(table_name);
      column_name text := quote_ident(column_name);
      conditions text := ' WHERE id = $1';
      updates text := column_name || '=' || column_name || '+' || step;
    BEGIN
      EXECUTE 'UPDATE ' || table_name || ' SET ' || updates || conditions
      USING id;
    END;
  $$ LANGUAGE plpgsql;

CREATE FUNCTION counter_cache()  
  RETURNS trigger AS $$
    DECLARE
      table_name text := quote_ident(TG_ARGV[0]);
      counter_name text := quote_ident(TG_ARGV[1]);
      fk_name text := quote_ident(TG_ARGV[2]);
      fk_changed boolean := false;
      fk_value integer;
      record record;
    BEGIN
      IF TG_OP = 'UPDATE' THEN
        record := NEW;
        EXECUTE 'SELECT ($1).' || fk_name || ' != ' || '($2).' || fk_name
        INTO fk_changed
        USING OLD, NEW;
      END IF;

      IF TG_OP = 'DELETE' OR fk_changed THEN
        record := OLD;
        EXECUTE 'SELECT ($1).' || fk_name INTO fk_value USING record;
        PERFORM increment_counter(table_name, counter_name, fk_value, -1);
      END IF;

      IF TG_OP = 'INSERT' OR fk_changed THEN
        record := NEW;
        EXECUTE 'SELECT ($1).' || fk_name INTO fk_value USING record;
        PERFORM increment_counter(table_name, counter_name, fk_value, 1);
      END IF;

      RETURN record;
    END;
  $$ LANGUAGE plpgsql;

CREATE TRIGGER update_post_comments_count  
  AFTER INSERT OR UPDATE OR DELETE ON comments
  FOR EACH ROW EXECUTE PROCEDURE counter_cache('posts', 'comments_count', 'post_id');
</code></pre>

<p>If you enjoyed this, check out how to port ActiveRecord <a href="http://shuber.io/porting-activerecord-validations-to-postgres">validations</a> and <a href="http://shuber.io/porting-activerecord-soft-delete-behavior-to-postgres">soft delete</a> behavior to Postgres as well!</p>]]></description><link>http://shuber.io/porting-activerecord-counter-cache-behavior-to-postgres/</link><guid isPermaLink="false">f1a7f7e6-7557-40fb-b42e-d6424c0bf28e</guid><category><![CDATA[rails]]></category><category><![CDATA[ruby]]></category><category><![CDATA[postgres]]></category><category><![CDATA[ plpgsql]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Thu, 21 May 2015 04:01:00 GMT</pubDate></item><item><title><![CDATA[Porting ActiveRecord validations to Postgres]]></title><description><![CDATA[<p>Let's try to port some <a href="http://edgeguides.rubyonrails.org/active_record_validations.html">ActiveRecord validations</a> to Postgres using constraints!</p>

<h4 id="validates_presence_of">validates_presence_of</h4>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_presence_of :email
end

ALTER TABLE users ALTER COLUMN email SET NOT NULL;  
ALTER TABLE users ADD CONSTRAINT email_presence CHECK (char_length(email) &gt; 0);  
</code></pre>

<h4 id="validates_uniqueness_of">validates_uniqueness_of</h4>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_uniqueness_of :email
end

ALTER TABLE users ADD CONSTRAINT email_uniqueness UNIQUE (email);  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_uniqueness_of :email, case_sensitive: false
end

ALTER TABLE users ALTER COLUMN email TYPE citext;  
ALTER TABLE users ADD CONSTRAINT email_uniqueness UNIQUE (email);  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_uniqueness_of :email, scope: :account_id
end

ALTER TABLE users ADD CONSTRAINT email_uniqueness UNIQUE (email, account_id);  
</code></pre>

<h4 id="validates_numericality_of">validates_numericality_of</h4>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_numericality_of :age, greater_than_or_equal_to: 18
end

ALTER TABLE users ADD CONSTRAINT age_numericality check (age &gt;= 18);  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_numericality_of :age, equal_to: 50
end

ALTER TABLE users ADD CONSTRAINT age_numericality check (age = 50);  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_numericality_of :age, odd: true
end

ALTER TABLE users ADD CONSTRAINT age_numericality check (age % 2 != 0);  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_numericality_of :age, even: true
end

ALTER TABLE users ADD CONSTRAINT age_numericality check (age % 2 = 0);  
</code></pre>

<h4 id="validates_inclusion_of">validates_inclusion_of</h4>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_inclusion_of :age, in: [1, 2, 3]
end

ALTER TABLE users ADD CONSTRAINT age_inclusion check (age IN (1, 2, 3));  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_inclusion_of :age, in: 18..25
end

ALTER TABLE users ADD CONSTRAINT age_inclusion check (age IN generate_sequence(18, 25));  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_inclusion_of :age, in: (1..100).step(2)
end

ALTER TABLE users ADD CONSTRAINT age_inclusion check (age IN generate_sequence(1, 100, 2));  
</code></pre>

<h4 id="validates_exclusion_of">validates_exclusion_of</h4>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_exclusion_of :age, in: [1, 2, 3]
end

ALTER TABLE users ADD CONSTRAINT age_exclusion check (age NOT IN (1, 2, 3));  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_exclusion_of :age, in: 18..25
end

ALTER TABLE users ADD CONSTRAINT age_exclusion check (age NOT IN generate_sequence(18, 25));  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_exclusion_of :age, in: (1..100).step(2)
end

ALTER TABLE users ADD CONSTRAINT age_exclusion check (age NOT IN generate_sequence(1, 100, 2));  
</code></pre>

<h4 id="validates_length_of">validates_length_of</h4>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_length_of :password, minimum: 6, maximum: 32
end

ALTER TABLE users ADD CONSTRAINT password_length CHECK (char_length(password) BETWEEN 6 AND 32);  
</code></pre>

<h4 id="validates_format_of">validates_format_of</h4>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
end

ALTER TABLE users ADD CONSTRAINT email_format CHECK (email ~* '\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z');  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_format_of :email, with: /.+@.+/, allow_nil: true
end

ALTER TABLE users ADD CONSTRAINT email_format CHECK (email IS NULL OR email ~* '.+@.+');  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_format_of :email, with: /.+@.+/, allow_blank: true
end

ALTER TABLE users ADD CONSTRAINT email_format CHECK (email = '' OR email ~* '.+@.+');  
</code></pre>

<pre><code>class User &lt; ActiveRecord::Base  
  validates_format_of :email, with: /.+@.+/, allow_blank: true, allow_nil: true
end

ALTER TABLE users ADD CONSTRAINT email_format CHECK (email IN (NULL, '') OR email ~* '.+@.+');  
</code></pre>

<h4 id="customvalidations">custom validations</h4>

<pre><code>class User &lt; ActiveRecord::Base  
  validate :validate_email_domain

  def domain
    email.to_s.split('@').last
  end

  private

  def validate_email_domain
    if banned_domains.include?(domain)
      errors.add(:email, 'domain is invalid')
    end
  end

  def banned_domains
    %w(gmail.com live.com)
  end
end

CREATE OR REPLACE FUNCTION validate_email_domain()  
  RETURNS trigger
AS $$  
  DECLARE
    banned text[];
    domain text;
  BEGIN
    banned := ARRAY['gmail.com', 'live.com'];

    FOREACH domain IN ARRAY banned LOOP
      IF NEW.email ~* (domain || '$') THEN
        RAISE EXCEPTION 'Invalid email domain %', domain;
      END IF;
    END LOOP;

    RETURN NEW;
  END;
$$ language plpgsql;

CREATE TRIGGER email_domain_validation  
  BEFORE INSERT OR UPDATE ON users
  FOR EACH ROW EXECUTE PROCEDURE validate_email_domain();
</code></pre>

<h2 id="caveats">Caveats</h2>

<ul>
<li><p>You'll need convert these constraint exceptions into user friendly error messages within your applications. The exceptions contain the name of the failed constraint like <code>email_domain_validation</code> so a common way to accomplish this is to  map the name to a hash containing messages like <code>Your email domain #{domain.inspect} has been banned</code>.</p></li>
<li><p>Postgres returns the first raised exception that is encountered. This means that you can't get a list of ALL failing validations when calling <code>save</code>, only one at a time as each error is fixed.</p></li>
</ul>

<p>If you enjoyed this, check out how to port ActiveRecord <a href="http://shuber.io/porting-activerecord-counter-cache-behavior-to-postgres">counter cache</a> and <a href="http://shuber.io/porting-activerecord-soft-delete-behavior-to-postgres">soft delete</a> behavior to Postgres as well!</p>]]></description><link>http://shuber.io/porting-activerecord-validations-to-postgres/</link><guid isPermaLink="false">ee85ebfc-59c3-41f1-af6e-3a33260f0f57</guid><category><![CDATA[rails]]></category><category><![CDATA[ruby]]></category><category><![CDATA[postgres]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Wed, 20 May 2015 06:52:00 GMT</pubDate></item><item><title><![CDATA[Postgres treats table rows like composite types]]></title><description><![CDATA[<p>Let's create a basic <code>users</code> table with sample data:</p>

<pre><code>CREATE TABLE users (  
  id    serial PRIMARY KEY,
  name  text
);

INSERT INTO users ('name') VALUES ('Bob'), ('Tom'), ('Sam');  
</code></pre>

<p>Then <code>SELECT * FROM users</code> to see what we're working with:</p>

<pre><code> id | name
----+------
  1 | Bob
  2 | Tom
  3 | Sam
</code></pre>

<p>Now check out what happens when we <code>SELECT users FROM users</code>:</p>

<pre><code>  users
----------
 (1,Bob)
 (2,Tom)
 (3,Sam)
</code></pre>

<p>That's pretty interesting! Postgres returns a tuple containing all of the columns for each row in <code>users</code>.</p>]]></description><link>http://shuber.io/postgres-treats-table-rows-like-composite-types/</link><guid isPermaLink="false">2a0dabb1-9cbd-451b-b78f-54e5f7b25b7a</guid><category><![CDATA[postgres]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Wed, 20 May 2015 05:49:00 GMT</pubDate></item><item><title><![CDATA[Case insensitive UNIQUE constraints in Postgres]]></title><description><![CDATA[<p>Adding <code>UNIQUE</code> constraints to tables in Postgres is very easy! </p>

<p>Imagine we have the following table:</p>

<pre><code>CREATE TABLE users (  
  id     uuid PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
  email  text
);
</code></pre>

<p>If we want to ensure that each user has a unique email we simply add:</p>

<pre><code>ALTER TABLE users ADD CONSTRAINT email_unique UNIQUE (email);  
</code></pre>

<p>Let's try it out by inserting some data:</p>

<pre><code>INSERT INTO users (email) VALUES ('test@example.com');  
INSERT INTO users (email) VALUES ('test@example.com');

ERROR:  duplicate key value violates unique constraint "email_unique"  
DETAIL:  Key (email)=(test@example.com) already exists.  
</code></pre>

<p>But there's a problem, the <code>UNIQUE</code> constraint is case sensitive!</p>

<pre><code>INSERT INTO users (email) VALUES ('test@example.com');  
INSERT INTO users (email) VALUES ('TEST@example.com');

SELECT * from users;

                  id                  |      email       
--------------------------------------+------------------
 ccfcddd2-bdc5-4cf4-9475-4171960e6262 | test@example.com
 431308b4-8df8-44c9-bed4-7c44cf4e1ec1 | TEST@example.com
(2 rows)
</code></pre>

<p>Unfortunately, Postgres does now allow us to define a unique constraint using <code>LOWER</code> like:</p>

<pre><code>ALTER TABLE users ADD CONSTRAINT email_unique UNIQUE (LOWER(email));

ERROR:  syntax error at or near "("  
</code></pre>

<p>But don't worry there's a workaround! Instead of using the <code>text</code> data type, we can use the <code>citext</code> (case insensitive text) type! First we need to enable the <a href="http://www.postgresql.org/docs/current/interactive/citext.html">citext</a> extension:</p>

<pre><code>CREATE EXTENSION IF NOT EXISTS citext;  
</code></pre>

<p>Then we'll need to change the <code>email</code> data type in the <code>users</code> table:</p>

<pre><code>ALTER TABLE users ALTER COLUMN email TYPE citext;  
</code></pre>

<p>Now our existing <code>UNIQUE</code> constraint should be case insensitive!</p>

<pre><code>INSERT INTO users (email) VALUES ('test@example.com');  
INSERT INTO users (email) VALUES ('TEST@example.com');

ERROR:  duplicate key value violates unique constraint "email_unique"  
DETAIL:  Key (email)=(TEST@example.com) already exists.  
</code></pre>

<p>Another solution is to add a <code>UNIQUE INDEX</code> instead of a <code>CONSTRAINT</code> like:</p>

<pre><code>CREATE UNIQUE INDEX email_unique_idx on users (LOWER(email));  
</code></pre>]]></description><link>http://shuber.io/case-insensitive-unique-constraints-in-postgres/</link><guid isPermaLink="false">1af23bab-ee2d-4857-a189-bce2b9cdcae3</guid><category><![CDATA[postgres]]></category><category><![CDATA[database]]></category><category><![CDATA[plpgsql]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Tue, 19 May 2015 07:05:00 GMT</pubDate></item><item><title><![CDATA[Parsing tags from text content in Postgres]]></title><description><![CDATA[<p>While experimenting with building a simple <a href="https://github.com/shuber/postgres-twitter">Twitter clone in Postgres</a>, I found that I needed a way to parse hashtags and mentions from tweets like:</p>

<pre><code>#example tweet - #testing with @postgresql
</code></pre>

<p>Imagine that we have a table called <code>tweets</code> defined with the following structure:</p>

<pre><code>CREATE TABLE tweets (  
  id        uuid PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
  post      text NOT NULL,
  hashtags  text[] NOT NULL DEFAULT '{}',
  mentions  text[] NOT NULL DEFAULT '{}'
);
</code></pre>

<p>Wouldn't it be nice if the hashtag and mention tokens were automatically parsed when we <code>INSERT</code> posts into the <code>tweets</code> table like the following:</p>

<pre><code>INSERT INTO tweets (post)  
VALUES ('#example tweet - #testing with @postgresql');

SELECT * FROM tweets;

                   id                  |                     post                   |      hashtags     |   mentions
---------------------------------------+--------------------------------------------+-------------------+--------------
 e133820e-7329-4852-b40b-6e9b7e2fa69d  | #example tweet - #testing with @postgresql | {example,testing} | {postgresql}
(1 row)
</code></pre>

<p>It turns out that this is pretty easy to achieve with Postgres! First we need to define a function to parse tokens from content and return an array of text.</p>

<pre><code>CREATE FUNCTION parse_tokens(content text, prefix text)  
  RETURNS text[] AS $$
    DECLARE
      regex text;
      matches text;
      subquery text;
      captures text;
      tokens text[];
    BEGIN
      regex := prefix || '(\S+)';
      matches := 'regexp_matches($1, $2, $3) as captures';
      subquery := '(SELECT ' || matches || ' ORDER BY captures) as matches';
      captures := 'array_agg(matches.captures[1])';

      EXECUTE 'SELECT ' || captures || ' FROM ' || subquery
      INTO tokens
      USING LOWER(content), regex, 'g';

      IF tokens IS NULL THEN
        tokens = '{}';
      END IF;

      RETURN tokens;
    END;
  $$ LANGUAGE plpgsql STABLE;
</code></pre>

<p>Let's test it out by parsing hashtags from a tweet:</p>

<pre><code>SELECT parse_tokens('#example tweet - #testing with @postgresql', '#');

       tokens
-------------------
 {example,testing}
 (1 row)
</code></pre>

<p>Parsing mentions from a tweet is just as simple:</p>

<pre><code>SELECT parse_tokens('#example tweet - #testing with @postgresql', '@');

    tokens
--------------
 {postgresql}
 (1 row)
</code></pre>

<p>Now that our <code>parse_tokens</code> function is working, we need to define some triggers to parse hashtags and mentions when a tweet record is inserted or updated.</p>

<pre><code>CREATE TRIGGER parse_hashtags  
  BEFORE INSERT OR UPDATE ON tweets
  FOR EACH ROW EXECUTE PROCEDURE parse_hashtags_from_post();

CREATE FUNCTION parse_hashtags_from_post()  
  RETURNS trigger AS $$
    BEGIN
      NEW.hashtags = parse_tokens(NEW.post, '#');
      RETURN NEW;
    END;
  $$ LANGUAGE plpgsql;

CREATE TRIGGER parse_mentions  
  BEFORE INSERT OR UPDATE ON tweets
  FOR EACH ROW EXECUTE PROCEDURE parse_mentions_from_post();

CREATE FUNCTION parse_mentions_from_post()  
  RETURNS trigger AS $$
    BEGIN
      NEW.mentions = parse_tokens(NEW.post, '@');
      RETURN NEW;
    END;
  $$ LANGUAGE plpgsql;
</code></pre>

<p>Now when we create or update tweets the <code>hashtags</code> and <code>mentions</code> fields are automatically updated! This whole process was pretty fun and interesting to get working. I look forward to attempting to push even more logic down into Postgres!</p>]]></description><link>http://shuber.io/parsing-tags-from-text-content-in-postgres/</link><guid isPermaLink="false">a3e680b9-6fed-4597-8559-0782175f6d09</guid><category><![CDATA[postgres]]></category><category><![CDATA[ plpgsql]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Tue, 19 May 2015 05:59:00 GMT</pubDate></item><item><title><![CDATA[Silently drop everything in Postgres]]></title><description><![CDATA[<p>Sometimes when working in Postgres I like to reset my development database by deleting everything in it without dropping the actual database itself.</p>

<p>An easy way to achieve this is to just drop all database schema(s) with the <code>CASCADE</code> option. By default, everything lives in the <code>public</code> schema.</p>

<pre><code>DROP SCHEMA "public" CASCADE;  
</code></pre>

<p>Postgres will output notices as it drop things with <code>CASCADE</code>. These messages can be supressed by changing the log level temporarily.</p>

<pre><code>SET client_min_messages TO WARNING;  
DROP SCHEMA "public" CASCADE;  
SET client_min_messages TO NOTICE;  
</code></pre>]]></description><link>http://shuber.io/silently-drop-everything-in-postgres/</link><guid isPermaLink="false">abd871a8-1448-4a19-aa0d-23cfaf610c27</guid><category><![CDATA[postgres]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Sun, 17 May 2015 03:47:00 GMT</pubDate></item><item><title><![CDATA[Reading from the filesystem with Postgres]]></title><description><![CDATA[<p>Let's try to make the following SQL statement work:</p>

<pre><code>SELECT file.read('/tmp/test.txt');  
</code></pre>

<p>We can start by creating the file <code>/tmp/test.txt</code> with the following contents:</p>

<pre><code>Hello PostgreSQL!  
</code></pre>

<p>The next step is to create a simple <code>plpgsql</code> function named <code>file.read</code>!</p>

<pre><code>CREATE FUNCTION file.read(file text)  
  RETURNS text AS $$
    DECLARE
      content text;
    BEGIN
      content := 'Static content for now!';
      RETURN content;
    END;
  $$ LANGUAGE plpgsql VOLATILE;
</code></pre>

<p>This initial placeholder function just returns static content so that we can make sure things are working properly so far.</p>

<pre><code>SELECT file.read('/tmp/test.txt');

          read
------------------------
 Static content for now
(1 row)
</code></pre>

<p>Now we just need to fill in the function with logic to read from the filesystem!</p>

<pre><code>CREATE FUNCTION file.read(file text)  
  RETURNS text AS $$
    DECLARE
      content text;
      tmp text;
    BEGIN
      file := quote_literal(file);
      tmp := quote_ident(uuid_generate_v4()::text);

      EXECUTE 'CREATE TEMP TABLE ' || tmp || ' (content text)';
      EXECUTE 'COPY ' || tmp || ' FROM ' || file;
      EXECUTE 'SELECT content FROM ' || tmp INTO content;
      EXECUTE 'DROP TABLE ' || tmp;

      RETURN content;
    END;
  $$ LANGUAGE plpgsql VOLATILE;
</code></pre>

<p>Now we should see the contents of the file that we created!</p>

<pre><code>SELECT file.read('/tmp/test.txt');

          read
------------------------
 Hello PostgreSQL!
(1 row)
</code></pre>

<p>OK... so what's going on here? Let's break it down!</p>

<p>We begin by declaring a couple of variables using the <code>text</code> data type.</p>

<ul>
<li><code>content</code> - stores the contents of the file read from the filesystem</li>
<li><code>tmp</code> - a unique string used as the name of a temporary table</li>
</ul>

<p>Then we move into the <code>BEGIN</code> block and set a couple of variables.</p>

<ul>
<li><code>file</code> - the quoted file name that the function was called with</li>
<li><code>tmp</code> - the quoted unique name for a temporary table</li>
</ul>

<p>Once we have our variables all setup, we <code>EXECUTE</code> some SQL to read the file contents.</p>

<ul>
<li>First we create a temporary table named <code>tmp</code> with a single field named <code>content</code></li>
<li>Then we use PostgreSQL's <a href="http://www.postgresql.org/docs/9.2/static/sql-copy.html">COPY</a> command to read the contents of <code>file</code> into the <code>tmp</code> table</li>
<li>Once the data has been imported, we <code>SELECT</code> the contents from the <code>tmp</code> table and insert it <code>INTO</code> the local <code>content</code> variable</li>
<li>Finally we <code>DROP</code> the <code>tmp</code> table since we don't need it anymore</li>
</ul>

<p>This was pretty interesting to get working! PostgreSQL has some other ways to read files from the filesystem.</p>

<ul>
<li><a href="http://www.postgresql.org/docs/current/interactive/file-fdw.html">file_fdw</a> - a read-only <a href="http://www.postgresql.org/docs/current/interactive/ddl-foreign-data.html">foreign data wrapper</a> for filesystem access built on the <code>COPY</code> command</li>
<li><a href="http://www.postgresql.org/docs/current/interactive/functions-admin.html#FUNCTIONS-ADMIN-GENFILE">pg_read_file</a> - this function is restricted to superusers and only allows files within the database cluster directory and the log_directory to be accessed</li>
<li><a href="https://github.com/csimsek/pgsql-fio/">pgsql-fio</a> - an extension for basic file system functions</li>
</ul>

<p>Another interesting challenge could be to write a <code>file.write</code> function to save content to a file!</p>]]></description><link>http://shuber.io/reading-from-the-filesystem-with-postgres/</link><guid isPermaLink="false">8ea1f13a-a524-4399-aaef-049cd6be6a4c</guid><category><![CDATA[postgres]]></category><category><![CDATA[database]]></category><category><![CDATA[plpgsql]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Sun, 17 May 2015 03:41:00 GMT</pubDate></item><item><title><![CDATA[Using the uuid data type in Postgres]]></title><description><![CDATA[<p>It's incredibly simple to use the <a href="http://www.postgresql.org/docs/9.1/static/datatype-uuid.html">uuid data type</a> in PostgreSQL!</p>

<p>First we need to enable the <a href="http://www.postgresql.org/docs/9.1/static/uuid-ossp.html">uuid-ossp</a> extension by executing the following SQL:</p>

<pre><code>CREATE EXTENSION IF NOT EXISTS "uuid-ossp";  
</code></pre>

<p>Now the <code>uuid</code> data type is available for us to use! Let's try using it as our primary key in a table.</p>

<pre><code>CREATE TABLE users (  
  id   uuid PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
  name text NOT NULL
);
</code></pre>

<p>Notice that we're generating default ids by calling the <code>uuid_generate_v4()</code> function.</p>

<p>Let's test it out by inserting a record.</p>

<pre><code>INSERT INTO users (name) VALUES ("Sean Huber");  
</code></pre>

<p>We can verify that it worked with a simple <code>SELECT * FROM users</code>!</p>

<pre><code>                  id                  |       name        
--------------------------------------+-------------------
 cf5c79cd-8a8d-4afd-8091-ef93f662a44d | Sean Huber

(1 row)
</code></pre>]]></description><link>http://shuber.io/using-the-uuid-data-type-in-postgres/</link><guid isPermaLink="false">996311e8-12cf-4256-aca7-d8e5b4283885</guid><category><![CDATA[postgres]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Sun, 17 May 2015 00:24:00 GMT</pubDate></item><item><title><![CDATA[Enumerable#each_with_object]]></title><description><![CDATA[<p>The <a href="http://ruby-doc.org/core-2.2.2/Enumerable.html#method-i-each_with_object"><code>Enumerable#each_with_object</code></a> method behaves very similarly to <a href="http://ruby-doc.org/core-2.2.2/Enumerable.html#method-i-inject"><code>Enumerable#inject</code></a>! There are only a couple of differences!</p>

<h2 id="theblockargumentsarereversed">The block arguments are reversed</h2>

<p>The <code>inject</code> method passes the block arguments in the following order:</p>

<ul>
<li>The <code>accumulator</code> which is initially the object that <code>inject</code> was called with</li>
<li>The value/object for each member in the <code>Enumerable</code> that <code>inject</code> was called on</li>
</ul>

<p>For the example below, <code>subtotal</code> is the <code>accumulator</code> and <code>item</code> is the value/object.</p>

<pre><code>@order.line_items.inject(0) |subtotal, item|
  subtotal + (item.quantity * item.price)
end  
</code></pre>

<p>The arguments are the same with <code>each_with_object</code> but just in the reverse order!</p>

<h2 id="theinitialobjectisalwaysreturned">The initial object is always returned</h2>

<p>While <code>inject</code> allows you to perform some logic within a block and return a new <code>accumulator</code> object with each iteration, the <code>each_with_object</code> method <em>always</em> returns the initial object that it was called with.</p>

<p>This is useful in cases where the initial object is <em>mutated</em> each iteration.</p>

<pre><code>quantities = LineItem.for_orders_today.each_with_object({}) |item, hash|  
  hash[item.name] ||= 0
  hash[item.name] += item.quantity
end  
</code></pre>

<p>Compare that to the <code>inject</code> equivalent!</p>

<pre><code>quantities = LineItem.for_orders_today.inject({}) |hash, item|  
  hash[item.name] ||= 0
  hash[item.name] += item.quantity
  hash
end  
</code></pre>]]></description><link>http://shuber.io/enumerable-each_with_object/</link><guid isPermaLink="false">9a8d4a34-c8bf-4f9e-aa27-5e05f5950401</guid><category><![CDATA[ruby]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Sat, 16 May 2015 23:45:00 GMT</pubDate></item><item><title><![CDATA[Return random records in Postgres]]></title><description><![CDATA[<p>Lately I've been experimenting with building a simple "twitter" app in Postgres by pushing as much logic in the database layer as possible. This includes data validation/sanitization, triggers, and functions.</p>

<p>I needed a way to seed the database with sample data which sometimes required me to specify foreign keys to existing records. I ended up writing a couple <code>plpgsql</code> functions to make this easier.</p>

<pre><code>CREATE FUNCTION random.record(table_name text, exclude uuid DEFAULT uuid_generate_v4())  
  RETURNS record AS $$
    DECLARE
      record record;
    BEGIN
      EXECUTE 'SELECT * FROM ' || table_name || ' WHERE id != $1 ORDER BY random() LIMIT 1'
      INTO record
      USING exclude;

      RETURN record;
    END;
  $$ LANGUAGE plpgsql VOLATILE;
</code></pre>

<p>The function above returns a random record from any specied table. It can be called with something like <code>SELECT random.record('users')</code>.</p>

<p>It optionally accepts an <code>id</code> to exclude in case you're running a query like:</p>

<pre><code>INSERT INTO followers (follower_id, user_id)  
SELECT id as follower_id, random.id('users', id) as user_id  
FROM users;  
</code></pre>

<p>Use this other function if you only need the <code>id</code>: <code>SELECT random.id('users')</code>.</p>

<pre><code>CREATE FUNCTION random.id(table_name text, exclude uuid DEFAULT uuid_generate_v4())  
  RETURNS uuid AS $$
    DECLARE
      record record;
    BEGIN
      record := random.record(table_name, exclude);
      RETURN record.id;
    END;
  $$ LANGUAGE plpgsql VOLATILE;
</code></pre>

<p>These functions expect your table's primary key to be a <code>uuid</code> called <code>id</code>. You may need to tweak them to match your specific schema if you're using <code>integer</code> or some other primary key column name.</p>

<p>Check out how to use <a href="http://shuber.io/using-the-uuid-data-type-in-postgres/">uuids in PostgreSQL</a> if you're not already!</p>]]></description><link>http://shuber.io/return-random-records-in-postgres/</link><guid isPermaLink="false">d1dfd4e6-f119-40d9-9657-015165276d7b</guid><category><![CDATA[postgres]]></category><category><![CDATA[ plpgsql]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Sat, 16 May 2015 01:45:00 GMT</pubDate></item><item><title><![CDATA[I wish this was valid Ruby]]></title><description><![CDATA[<h5 id="validrubytheonlyvalidlineofcodeinthispost">Valid Ruby (the only valid line of code in this post)</h5>

<pre><code>before_validation(on: :create) { contact.email ||= email }  
</code></pre>

<h5 id="dropbracesanduseastabbyproc">Drop braces and use a stabby proc</h5>

<pre><code>before_validation(on: :create) -&gt; contact.email ||= email  
</code></pre>

<h5 id="dropparenthesesaroundthehasharguments">Drop parentheses around the hash arguments</h5>

<pre><code>before_validation on: :create -&gt; contact.email ||= email  
</code></pre>

<h5 id="shorthandforsymbolsymbolkeyvaluepairs">Shorthand for <code>{ :symbol =&gt; :symbol }</code> key/value pairs</h5>

<pre><code>before_validation on:create -&gt; contact.email ||= email  
</code></pre>

<h5 id="maybedropthegettersetternameduplicationsomehow">Maybe drop the getter/setter name duplication somehow</h5>

<pre><code>before_validation on:create -&gt; contact:||= email  
before_validation on:create -&gt; contact .= email  
</code></pre>

<p>That last one seems a little weird but would be an interesting syntax. I really like the condensed hash arguments syntax though. Maybe one day we'll see stuff like this in Ruby!</p>]]></description><link>http://shuber.io/i-wish-this-was-valid-ruby/</link><guid isPermaLink="false">64b2c7b5-fe53-4373-85e6-d3874744a203</guid><category><![CDATA[rails]]></category><category><![CDATA[ruby]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Fri, 06 Feb 2015 17:38:00 GMT</pubDate></item><item><title><![CDATA[Docker]]></title><description><![CDATA[<p><em>tldr; <a href="http://shuber.io/#letsgetstarted">Let's get started</a></em></p>

<p>I've heard a lot about <a href="https://www.docker.com/">Docker</a> over the past year but haven't really dived into it much until recently. So far the experience has been amazing! I've found the technology to be very easy and fun to work with. I believe Docker is going to be incredibly popular in the near future and I'd like to get you excited about it by showing you what I've learned so far.</p>

<p><a href="https://www.docker.com/"><img src="http://shuber.io/content/images/2014/11/docker-logo.png" alt="Docker" title=""></a></p>

<h2 id="whatisdocker">What is Docker?</h2>

<blockquote>
  <p>Docker is a platform for building, shipping, and running distributed applications.</p>
</blockquote>

<p>It uses lightweight, portable runtimes called <em>containers</em> to package up an application with all of its dependencies, including the operating system, native packages, and any other libraries or plugins required to run it.</p>

<p>Containers are pretty similar to virtual machines. The main difference is that Docker allows containers to share the same Linux kernel as the host system that they're running on. Containers only need to provide the packages and dependencies that are not already available on the host system. This greatly reduces the size of an application and provides a significant boost to performance allowing containers to be booted up in mere <em>milliseconds</em>.</p>

<p>Snapshots of containers called <em>images</em> allow applications to be distributed amongst developer laptops, production data centers, or any cloud service provider, running and behaving exactly the same in all environments.</p>

<h2 id="whyshouldiusedocker">Why should I use Docker?</h2>

<ul>
<li>It makes it incredibly easy for developers to create, manage, and deploy production ready application containers</li>
<li>It allows developers to work in an environment that perfectly mirrors production, reducing the introduction of bugs to live sites</li>
<li>It dramatically speeds up productivity by allowing new developers to quickly spin up a local development environment that behaves exactly the same as the rest of the teams'</li>
<li>It encourages the decoupling of application concerns by breaking apart monolithic code bases into smaller and more focused components or services</li>
<li>It provides the flexibility to allow containers that run completely different frameworks, programming languages, or operating systems to seamlessly work and communicate with each other on the same host system</li>
</ul>

<h2 id="howdoiusedocker">How do I use Docker?</h2>

<blockquote>
  <p>Let's learn by example and integrate Docker with a <a href="http://rubyonrails.org/">Rails</a> application!</p>
</blockquote>

<p>We'll use a pretty common stack consisting of:</p>

<ul>
<li>Ubuntu 14.04</li>
<li>Ruby 2.1.2</li>
<li>Rails 4.1.7</li>
<li>Redis 2.8.17</li>
<li>PostgreSQL 9.3.5</li>
</ul>

<h2 id="letsgetstarted">Let's get started</h2>

<p>Read on or feel free to jump around to the different sections using the links below.</p>

<ul>
<li><a href="http://shuber.io/#installdocker">Install Docker</a>
<ul><li><a href="http://shuber.io/#bootupubuntu1404withvagrant">Boot up Ubuntu 14.04 with <code>Vagrant</code></a></li>
<li><a href="http://shuber.io/#usethelightweightboot2dockerlinuxdistribution">Or use the lightweight <code>boot2docker</code> Linux distribution</a></li></ul></li>
<li><a href="http://shuber.io/#buildimageswithadockerfile">Build images with a <code>Dockerfile</code></a>
<ul><li><a href="http://shuber.io/#inheritfromabaseimagewithfrom">Inherit from a base image with <code>FROM</code></a></li>
<li><a href="http://shuber.io/#installrequiredpackageswithaptget">Install required packages with <code>apt-get</code> using <code>RUN</code></a></li>
<li><a href="http://shuber.io/#installrubywithenvrbenvandrubybuild">Install Ruby with <code>ENV</code>, <code>rbenv</code>, and <code>ruby-build</code></a></li>
<li><a href="http://shuber.io/#settheworkingdirectorywithworkdir">Set the working directory with <code>WORKDIR</code></a></li>
<li><a href="http://shuber.io/#tagimageswithdockertagordockerbuildt">Tag images with <code>docker build -t</code></a></li></ul></li>
<li><a href="http://shuber.io/#startacontainerfromanimagewithdockerrun">Start a container from an image with <code>docker run</code></a>
<ul><li><a href="http://shuber.io/#mountvolumesincontainerswithdockerrunv">Mount volumes in containers with <code>docker run -v</code></a></li>
<li><a href="http://shuber.io/#runcontainersinthebackgroundwithdockerrund">Run containers in the background with <code>docker run -d</code></a></li>
<li><a href="http://shuber.io/#linkcontainerswithdockerrunlink">Link containers with <code>docker run --link</code></a></li>
<li><a href="http://shuber.io/#setenvironmentvariableswithdockerrune">Set environment variables with <code>docker run -e</code></a></li>
<li><a href="http://shuber.io/#removecontainerswithdockerrmanddockerrunrm">Automatically remove containers with <code>docker run --rm</code></a></li>
<li><a href="http://shuber.io/#namecontainerswithdockerrunname">Name containers with <code>docker run --name</code></a></li></ul></li>
<li><a href="http://shuber.io/#fetchimagesfromthedockerhubwithdockerpull">Fetch images from the Docker Hub with <code>docker pull</code></a></li>
<li><a href="http://shuber.io/#tagimageswithdockertagordockerbuildt">Tag existing images with <code>docker tag</code></a></li>
<li><a href="http://shuber.io/#removeimageswithdockerrmi">Remove images with <code>docker rmi</code></a></li>
<li><a href="http://shuber.io/#listrunningcontainerswithdockerps">List running containers with <code>docker ps</code></a></li>
<li><a href="http://shuber.io/#stopcontainerswithdockerstop">Stop containers with <code>docker stop</code></a></li>
<li><a href="http://shuber.io/#listallcontainerswithdockerpsa">List all containers with <code>docker ps -a</code></a></li>
<li><a href="http://shuber.io/#removecontainerswithdockerrmanddockerrunrm">Remove containers with <code>docker rm</code> and <code>--rm</code></a></li>
<li><a href="http://shuber.io/#startupmultiplecontainerswithfig">Start up multiple containers with <code>Fig</code></a></li>
<li><a href="http://shuber.io/#rundockerwithindockerbymountingvarlibdocker">Run Docker within Docker by mounting <code>/var/lib/docker</code></a></li>
</ul>

<h3 id="installdocker">Install Docker</h3>

<blockquote>
  <p>We need a Linux host to run Docker since containers share the host's kernel.</p>
</blockquote>

<p>I'm not running a Linux distribution for development so let's spin up a host <abbr title="Virtual Machine">VM</abbr> by either:</p>

<ul>
<li>Booting one up with <a href="https://www.vagrantup.com/">Vagrant</a>.</li>
<li>Using the lightweight <a href="http://boot2docker.io/">boot2docker</a> Linux distribution</li>
</ul>

<h4 id="bootupubuntu1404withvagrant">Boot up Ubuntu 14.04 with <code>Vagrant</code></h4>

<p>First we'll need to define a <code>Vagrantfile</code> so let's add one to the root of our application. A box called <code>ubuntu/trusty64</code> running Ubuntu 14.04 already exists so we can just use that.</p>

<pre><code>VAGRANTFILE_API_VERSION = "2"

Vagrant.configure VAGRANTFILE_API_VERSION do |config|
  config.vm.box = "ubuntu/trusty64"
end
</code></pre>

<p>Then let's open our terminal and ssh to the new Ubuntu image by calling <code>vagrant up</code> then <code>vagrant ssh</code>.</p>

<p><strong>Install the <code>docker.io</code> package with <code>apt-get</code></strong></p>

<p>The <code>apt-get</code> and <code>docker</code> commands both require <code>sudo</code> so let's change to the root user since we'll be running the <code>docker</code> command frequently.</p>

<p>The root password is <code>vagrant</code>.</p>

<pre><code>vagrant@ubuntu-trusty-64:~$ su
Password:
</code></pre>

<p>Now let's update and install the <code>docker.io</code> package.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# apt-get update &amp;&amp; apt-get install docker.io
</code></pre>

<p>After Docker installs we can use <code>docker build</code> to create a new image.</p>

<h4 id="usethelightweightboot2dockerlinuxdistribution">Use the lightweight <code>boot2docker</code> Linux distribution</h4>

<p>The <a href="http://boot2docker.io/">boot2docker</a> distro was made specifically for running Docker containers. It currently supports both OSX and Windows hosts.</p>

<p>If you're using <a href="http://brew.sh/">homebrew</a> you can just <code>brew install boot2docker docker</code> to install both. Then call <code>boot2docker init &amp;&amp; boot2docker start</code>.</p>

<h3 id="buildimageswithadockerfile">Build images with a <code>Dockerfile</code></h3>

<p>New images are defined in a file called <a href="http://docs.docker.com/reference/builder/">Dockerfile</a>. This file is a simple list of statements that define the commands required to run a container. Let's add a <code>Dockerfile</code> to the root of our application next to our <code>Vagrantfile</code>.</p>

<h4 id="inheritfromabaseimagewithfrom">Inherit from a base image with <code>FROM</code></h4>

<p>Docker images remind me a lot of classes in object oriented programming.</p>

<blockquote>
  <p>Just like classes, Docker images are inheritable.</p>
</blockquote>

<p>All images start with a <em>base image</em>. Like Vagrant, there are existing official images for Ubuntu so let's use that as our base.</p>

<pre><code>FROM ubuntu:14.04
</code></pre>

<p>The <code>FROM</code> statement is the only thing required to build a Dockerfile image. Let's try building it from our terminal.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker build .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon
Step 0 : FROM ubuntu:14.04
5506de2b643b: Pulling dependent layers
511136ea3c5a: Download complete
d497ad3926c8: Download complete
ccb62158e970: Download complete
e791be0477f2: Download complete
3680052c0f5c: Download complete
22093c35d77b: Download complete
22093c35d77b: Download complete
 ---&gt; 5506de2b643b
Successfully built 5506de2b643b
</code></pre>

<p>Success! We just built our first Docker image called <code>5506de2b643b</code>!</p>

<p>Wait... what's all that noise about pulling and downloading dependent layers?</p>

<h4 id="fetchimagesfromthedockerhubwithdockerpull">Fetch images from the Docker Hub with <code>docker pull</code></h4>

<p>Like <a href="http://rubygems.org/">RubyGems</a> for Ruby, Docker has a registry for images called <a href="https://registry.hub.docker.com/">Docker Hub</a>.</p>

<p>This public Docker registry allows developers from all over the world to share open source images that run all kinds of different services and applications!</p>

<p>There are even <em>official images</em> for running popular projects like <a href="https://registry.hub.docker.com/_/ubuntu/">Ubuntu</a>, <a href="https://registry.hub.docker.com/_/redis/">Redis</a>, <a href="https://registry.hub.docker.com/_/postgres/">PostgreSQL</a>, <a href="https://registry.hub.docker.com/_/nginx/">Nginx</a>, <a href="https://registry.hub.docker.com/_/node/">Node.js</a>, and <a href="https://registry.hub.docker.com/_/jenkins/">Jenkins</a>.</p>

<blockquote>
  <p>When we called <code>docker build</code> just now, Docker noticed that the <code>ubuntu:14.04</code> image didn't exist on our local system, so it searched the Docker Hub and automatically downloaded the official one for us!</p>
</blockquote>

<p>Our application actually requires Redis and PostgreSQL as well so let's try pulling the official images for those from the Docker Hub registry!</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker pull redis:2.8.17
Pulling repository redis
3ce54e911389: Download complete
511136ea3c5a: Download complete
...snip...
6a8a6a35a96b: Download complete
28fdd31ac753: Download complete
</code></pre>

<p>Wow, that was easy! Now for PostgreSQL!</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker pull postgres:9.3.5
Pulling repository postgres
746b819f315e: Download complete
511136ea3c5a: Download complete
...snip...
ec77bb5a53d3: Download complete
165394769d57: Download complete
</code></pre>

<p>Let's use <code>docker images</code> to print out a list of all images on our system so far.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker images
REPOSITORY    TAG        IMAGE ID          CREATED        VIRTUAL SIZE
redis         2.8.17     3ce54e911389      3 days ago         110.7 MB
postgres      9.3.5      746b819f315e      4 days ago         212.9 MB
ubuntu        14.04      5506de2b643b      3 weeks ago        197.8 MB
</code></pre>

<p>Notice that the <code>ubuntu:14.04</code> image has the same image ID as the one that we built earlier! This is because our <code>Dockerfile</code> just inherits <code>FROM ubuntu:14.04</code> and doesn't add any additional behavior! Docker is smart enough to know that it doesn't need to create a whole new image in this case, it can just use <code>ubuntu</code>.</p>

<p>Let's try starting up a new container with this <code>5506de2b643b</code> Ubuntu image.</p>

<h4 id="startacontainerfromanimagewithdockerrun">Start a container from an image with <code>docker run</code></h4>

<p>Containers can be started by simply specifying an image id.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -i -t 5506de2b643b /bin/bash
root@b58db262db27:/#
</code></pre>

<p>Whoa, did you see how fast that started up!?</p>

<p>Now we're in our new container with its own prompt <code>root@b58db262db27:/#</code></p>

<blockquote>
  <p>Anything we do or change in the container will not effect the host system.</p>
</blockquote>

<p>All modifications made to the container's filesystem will be lost as soon as the container is shut down. It is an incredibly lightweight stateless runtime that can be stopped and thrown away whenever we're done with it.</p>

<p>When we started the container we specified a couple options:</p>

<ul>
<li><code>-i</code> keeps <code>STDIN</code> open even if we're not attached to the container</li>
<li><code>-t</code> allocates a <a href="http://en.wikipedia.org/wiki/Computer_terminal#Text_terminals">pseudo-tty</a></li>
</ul>

<p>For interactive processes (like a shell) we typically want a tty <em>and</em> persistent standard input (<code>STDIN</code>), so we'll use <code>-i -t</code> together in most interactive cases.</p>

<p>We also specified a couple of arguments:</p>

<ul>
<li><code>5506de2b643b</code> is the ID of the image that we want to run</li>
<li><code>/bin/bash</code> is the command that we want to execute on start up</li>
</ul>

<p>This container is not very useful since it doesn't actually provide any additional functionality. Let's <code>exit</code> back out to our Vagrant host and add some packages that are required by our application to our <code>Dockerfile</code>.</p>

<h4 id="installrequiredpackageswithaptget">Install required packages with <code>apt-get</code></h4>

<p>We need to install native dependencies for:</p>

<ul>
<li>Precompiling assets - <code>nodejs</code></li>
<li>Pulling packages and gems - <code>git</code></li>
<li>Generating image thumbnails - <code>imagemagick</code></li>
<li>Connecting to PostgreSQL - <code>postgresql-client</code> and <code>libpq-dev</code></li>
<li>Parsing XML documents with <a href="http://www.nokogiri.org/">Nokogiri</a> - <code>libxml2-dev</code> and <code>libxslt-dev</code></li>
<li>Building and installing Ruby with <a href="https://github.com/sstephenson/rbenv">Rbenv</a> - <code>build-essential</code>, <code>wget</code>, <code>libreadline-dev</code>, <code>libssl-dev</code>, <code>libyaml-dev</code></li>
</ul>

<p>We can use <code>apt-get</code> commands to install these packages in our <code>Dockerfile</code> by declaring <code>RUN</code> statements.</p>

<pre><code>FROM ubuntu:14.04

RUN apt-get update &amp;&amp; \
    apt-get -y install \
               build-essential \
               git \
               imagemagick \
               postgresql-client \
               nodejs \
               libpq-dev \
               libreadline-dev \
               libssl-dev \
               libyaml-dev \
               libxml2-dev \
               libxslt-dev \
               wget &amp;&amp; \
    apt-get clean &amp;&amp; \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
</code></pre>

<p>Notice that we run <code>apt-get clean</code> and <code>rm -rf</code> to clean up after ourselves once the packages are installed. </p>

<blockquote>
  <p>Docker <code>commits</code> changes as <em>layers</em> to an image every time it processes commands like <code>RUN</code> in Dockerfile build steps.</p>
</blockquote>

<p>Like a <a href="http://git-scm.com/">Git</a> repository, if we add files to an image and then delete them in future <code>RUN</code> commands, the image's history still contains the files in previous layers. If we're not careful, we could accidentally add bloat to  images with leftover files.</p>

<p>Let's try building our <code>Dockerfile</code> with these new changes!</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker build .
Sending build context to Docker daemon 10.75 kB
Sending build context to Docker daemon
Step 0 : FROM ubuntu:14.04
 ---&gt; 5506de2b643b
Step 1 : RUN apt-get update &amp;&amp; apt-get -y install build-essential git imagemagick postgresql-client nodejs libpq-dev libreadline-dev libssl-dev libyaml-dev libxml2-dev libxslt-dev wget &amp;&amp; apt-get clean &amp;&amp; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
 ---&gt; Running in d3ea35797f02
Ign http://archive.ubuntu.com trusty InRelease
Ign http://archive.ubuntu.com trusty-updates InRelease
Ign http://archive.ubuntu.com trusty-security InRelease
Ign http://archive.ubuntu.com trusty-proposed InRelease
Get:1 http://archive.ubuntu.com trusty Release.gpg [933 B]
Get:2 http://archive.ubuntu.com trusty-updates Release.gpg [933 B]
Get:3 http://archive.ubuntu.com trusty-security Release.gpg [933 B]
...snip...
Processing triggers for sgml-base (1.26+nmu4ubuntu1) ...
Processing triggers for libgdk-pixbuf2.0-0:amd64 (2.30.7-0ubuntu1) ...
 ---&gt; ea8c31ce96ce
Removing intermediate container d3ea35797f02
Successfully built ea8c31ce96ce
</code></pre>

<p>Sweet! We've got a new Docker image called <code>ea8c31ce96ce</code>. Let's try it out!</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -it ea8c31ce96ce /bin/bash
root@0d67a0fd8284:/# which git
/usr/bin/git
root@0d67a0fd8284:/# which psql
/usr/bin/psql
</code></pre>

<p>We've got Git and PostgreSQL! Just to make sure that everything is isolated to this container, let's <code>exit</code> back out to our host and check for those commands.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# which git
root@ubuntu-trusty-64:/vagrant# which psql
</code></pre>

<p>The <code>git</code> and <code>psql</code> commands don't exist on our host system, awesome!</p>

<p>Now that we've got our packages installed, let's try to get Ruby 2.1.2 working!</p>

<h4 id="installrubywithenvrbenvandrubybuild">Install Ruby with <code>ENV</code>, <code>rbenv</code>, and <code>ruby-build</code></h4>

<ul>
<li>First we'll install <a href="https://github.com/sstephenson/rbenv">rbenv</a> and <a href="https://github.com/sstephenson/ruby-build">ruby-build</a> by cloning them under <code>/.rbenv</code>.</li>
<li>Next we'll configure <code>rbenv</code> with <code>ENV</code> and run the <code>ruby-build</code> installation script.</li>
<li>Then we'll install Ruby version 2.1.2.</li>
<li>Finally we'll install <code>bundler</code> since we'll need it to install gem depedencies.</li>
</ul>

<p>Let's update our <code>Dockerfile</code> to perform these actions.</p>

<pre><code>RUN github="https://github.com/sstephenson" &amp;&amp; \
    git clone --depth=1 $github/rbenv.git /.rbenv &amp;&amp; \
    git clone --depth=1 $github/ruby-build.git /.rbenv/plugins/ruby-build

ENV PATH /.rbenv/bin:/.rbenv/shims:$PATH
ENV RBENV_ROOT /.rbenv

RUN /.rbenv/plugins/ruby-build/install.sh &amp;&amp; \
    echo 'eval "$(rbenv init -)"' &gt;&gt; /.bashrc &amp;&amp; \
    echo "gem: --no-rdoc --no-ri" &gt;&gt; /.gemrc

RUN version="2.1.2" &amp;&amp; \
    rbenv install $version &amp;&amp; \
    rbenv global $version

RUN gem install bundler &amp;&amp; \
    rbenv rehash
</code></pre>

<p>Notice that we used a new statement called <code>ENV</code>. This simply sets an environment variable. Existing environment  variables can be referenced in <code>ENV</code> declarations just like we did with <code>PATH</code>.</p>

<p>Let's build our new image and try it out!</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker build .
Sending build context to Docker daemon 11.26 kB
Sending build context to Docker daemon
Step 0 : FROM ubuntu:14.04
 ---&gt; 5506de2b643b
Step 1 : RUN apt-get update &amp;&amp; apt-get -y install build-essential git imagemagick postgresql-client nodejs libpq-dev libreadline-dev libssl-dev libyaml-dev libxml2-dev libxslt-dev wget &amp;&amp; apt-get clean &amp;&amp; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
 ---&gt; Using cache
 ---&gt; ea8c31ce96ce
 ...snip...
 Successfully built 8a8f8ad165b7
</code></pre>

<p>Whoa, check it out, it skipped the <code>apt-get</code> update step this time!</p>

<blockquote>
  <p>Docker is smart enough to know that it doesn't need to re-execute commands like <code>RUN</code> unless the command has changed since the last time it was evaluated.</p>
</blockquote>

<p>In this case, our list of packages to install didn't change so Docker just used its cached copy.</p>

<p>Let's try out the updated <code>8a8f8ad165b7</code> image by starting up an <code>irb</code> console!</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -it 8a8f8ad165b7 irb
irb(main):001:0&gt; RUBY_VERSION
=&gt; "2.1.2"
</code></pre>

<p>Awesome! Now we've got Ruby 2.1.2 and all of the other system level dependencies that are required to run our application!</p>

<p>Now, let's figure out how we can add our Rails code into the container so we can actually run our application.</p>

<h4 id="mountvolumesincontainerswithdockerrunv">Mount volumes in containers with <code>docker run -v</code></h4>

<p>Docker allows containers to <em>mount</em> directories on the host system so that we can share files with it. This allows us to share our Rails application in the current directory with a container!</p>

<p>First we'll need to update our <code>Dockerfile</code> to support a <code>VOLUME</code> for our Rails app.</p>

<pre><code>FROM ubuntu:14.04

...snip...

RUN version="2.1.2" &amp;&amp; \
    rbenv install $version &amp;&amp; \
    rbenv global $version

VOLUME /app
</code></pre>

<p>This simple <code>VOLUME</code> command let's Docker know that our image expects <code>/app</code> to be a shared directory that lives somewhere on the host system. Let's try it out by building a new image from these changes.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker build .
...snip...
Step 6 : RUN version="2.1.2" &amp;&amp; rbenv install 2.1.2 &amp;&amp; rbenv global 2.1.2
 ---&gt; Using cache
 ---&gt; 8a8f8ad165b7
Step 7 : VOLUME /app
 ---&gt; Running in a999838c4841
 ---&gt; e4d5a879c353
Removing intermediate container a999838c4841
Successfully built 59778b8a0ce2
</code></pre>

<p>Now let's try it mounting <code>/app</code> to our Rails app in the current directory.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -it -v $PWD:/app 59778b8a0ce2 /bin/bash
root@64c5e7b2ba49:/# ls -la /app
drwxr-xr-x  15 1000  1000    510 Nov 14 13:33 .git
-rw-r--r--   1 1000  1000    706 Nov 11 11:19 .gitignore
-rw-r--r--   1 1000  1000      6 Nov  5 15:56 .ruby-version
-rw-r--r--   1 1000  1000   1015 Nov 12 01:31 Dockerfile
-rw-r--r--   1 1000  1000   1338 Nov 11 11:18 Gemfile
-rw-r--r--   1 1000  1000   8556 Nov 11 11:30 Gemfile.lock
-rw-r--r--   1 1000  1000    249 Nov  5 15:56 Rakefile
drwxr-xr-x  20 1000  1000    680 Nov  5 15:56 app
drwxr-xr-x  76 1000  1000   2584 Nov 12 01:01 bin
drwxr-xr-x  25 1000  1000    850 Nov 10 22:33 config
-rw-r--r--   1 1000  1000    154 Nov  5 15:56 config.ru
drwxr-xr-x   5 1000  1000    170 Nov 10 13:24 db
drwxr-xr-x  26 1000  1000    884 Nov 10 13:46 lib
drwxr-xr-x   3 1000  1000    102 Nov 11 11:59 log
drwxr-xr-x  10 1000  1000    340 Nov 10 23:49 public
drwxr-xr-x  18 1000  1000    612 Nov  7 14:25 spec
drwxr-xr-x   3 1000  1000    102 Nov 11 11:59 vendor
</code></pre>

<p>Sweet, now we've got our Rails code mounted under the <code>/app</code> directory!</p>

<blockquote>
  <p>Any changes that a container makes to mounted volumes will be shared and reflected on the host system as well.</p>
</blockquote>

<p>Now let's try install gem dependencies with <code>bundle install</code> and write them to the <code>vendor/bundle</code> directory.</p>

<p>We'll need to configure Nokogiri to use the system libraries for <code>libxml2</code> first.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -it 59778b8a0ce2 /bin/bash
root@f44fde88a15d:/# cd /app
root@f44fde88a15d:/app# bundle config build.nokogiri --use-system-libraries --with-xml2-include=/usr/include/libxml2
root@f44fde88a15d:/app# bundle install --path vendor/bundle
Don't run Bundler as root. Bundler can ask for sudo if it is needed, and installing your bundle as root will break this application for all non-root users on this machine.
Fetching gem metadata from https://rubygems.org/...........
Resolving dependencies...
Installing rake 10.3.2
Installing i18n 0.6.11
...snip...
Installing turbolinks 2.5.2
Installing uglifier 2.5.3
Your bundle is complete!
It was installed into ./vendor/bundle
</code></pre>

<p>Great, all of the gem dependencies installed successfully! Let's check our host system to make sure that <code>vendor/bundle</code> was created and actually has contents.</p>

<pre><code>root@f44fde88a15d:/app# exit
root@ubuntu-trusty-64:/vagrant# ls -la vendor/bundle
total 0
drwxr-xr-x 1 vagrant vagrant 102 Nov 16 06:23 .
drwxr-xr-x 1 vagrant vagrant 102 Nov 16 06:23 ..
drwxr-xr-x 1 vagrant vagrant 102 Nov 16 06:23 ruby
</code></pre>

<p>Looks like <code>bundle</code> installed the gems to <code>vendor/bundle</code> as expected!</p>

<p>To verify, let's start up a new container and try to <code>bundle install</code> again.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -it -v $PWD:/app 59778b8a0ce2 /bin/bash
root@f44fde88a15d:/# cd /app
root@837a7a749b19:/app# bundle install
Don't run Bundler as root. Bundler can ask for sudo if it is needed, and installing your bundle as root will break this application for all non-root users on this machine.
Using rake 10.3.2
Using i18n 0.6.11
...snip...
Using turbolinks 2.5.2
Using uglifier 2.5.3
Your bundle is complete!
It was installed into ./vendor/bundle
</code></pre>

<p>Success! Bundler skips <code>Installing</code> all of our gems and imforms us that it's <code>Using</code> the existing versions from <code>vendor/bundle</code> instead!</p>

<p>Notice that we didn't have to configure Nokogiri again! Since the <code>bundle config</code> command saves settings to <code>.bundle/config</code> (which is mounted on our host system) this configuration can persist and be shared between containers.</p>

<p>Since we keep calling <code>cd /app</code> when we first run the container, let's make that the default working directory.</p>

<h4 id="settheworkingdirectorywithworkdir">Set the working directory with <code>WORKDIR</code></h4>

<p>The Dockerfile <code>WORKDIR</code> directive simply sets the working directory to the specified value for all commands that run after it. Let's try adding it to our <code>Dockerfile</code>.</p>

<pre><code>WORKDIR /app
</code></pre>

<p>Now we can rebuild it and try it out!</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker build .
...snip...
Successfully built 9075d0fd41f5
root@ubuntu-trusty-64:/vagrant# docker run -it -v $PWD:/app 9075d0fd41f5 /bin/bash
root@130321bd404c:/app# pwd
/app
</code></pre>

<p>Sweet, now we don't have to <code>cd /app</code> all the time!</p>

<p>It's a little annoying having to copy paste the image ids like <code>9075d0fd41f5</code> when we want to run a container. There's got to be an easier way!</p>

<h4 id="tagimageswithdockertagordockerbuildt">Tag images with <code>docker tag</code> or <code>docker build -t</code></h4>

<p>Since we've already built the <code>9075d0fd41f5</code> image for our Rails application, let's try tagging it as <code>example-app</code> so we can refer to it by that instead.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker tag 9075d0fd41f5 example-app
root@ubuntu-trusty-64:/vagrant# docker images
REPOSITORY      TAG         IMAGE ID         CREATED      VIRTUAL SIZE
example-app     latest      9075d0fd41f5     26 minutes ago   554.7 MB
&lt;none&gt;          &lt;none&gt;      e4d5a879c353     2 hours ago      550.7 MB
&lt;none&gt;          &lt;none&gt;      4ecd2ce76f10     46 hours ago     550.7 MB
...snip...
&lt;none&gt;          &lt;none&gt;      73ab02dbc5df     46 hours ago     437.1 MB
&lt;none&gt;          &lt;none&gt;      047c19d8acb0     2 days ago       397.9 MB
redis           2.8.17      3ce54e911389     5 days ago       110.7 MB
</code></pre>

<p>Sweet, Docker will now allow us to refer to our image as <code>example-app</code>. Let's give it a shot!</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -it example-app /bin/bash
root@fa627a840e57:/app#
</code></pre>

<p>Great, it worked as expected! We can also tag an image when it's built by specifying the <code>-t</code> flag.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker build -t example-app .
</code></pre>

<p>That's pretty convenient! We can run that command whenever we update our <code>Dockerfile</code> and the <code>example-app</code> image will always stay up to date!</p>

<p>Did you notice all of those <code>&lt;none&gt;</code> images from the <code>docker images</code> output earlier? Those are all of the images we made from our previous calls to <code>docker build .</code>. Since we don't really need those anymore, let's try removing them.</p>

<h4 id="removeimageswithdockerrmi">Remove images with <code>docker rmi</code></h4>

<p>If your <code>docker images</code> list starts to fill up, you can remove them by their name or <code>IMAGE ID</code>.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker rmi 4ecd2ce76f10
Deleted: 4ecd2ce76f10611d6f0f6a31653f9245414d198c92bbc265886bb1c79152a06c
</code></pre>

<p>We've got a bunch of images to delete but it's pretty tedious and annoying to have to list out all of those image ids. Here's a couple of commands to make removing multiple images easier.</p>

<blockquote>
  <p>To delete all <code>untagged</code> images</p>
</blockquote>

<pre><code>docker rmi $(docker images | grep "^&lt;none&gt;" | awk '{print $3}')
</code></pre>

<blockquote>
  <p>To delete <code>all</code> images</p>
</blockquote>

<pre><code>docker rmi $(docker images -q)
</code></pre>

<p>Now that we've got our Docker images ready, let's figure out how to allow running containers to communicate with each other.</p>

<h4 id="runcontainersinthebackgroundwithdockerrund">Run containers in the background with <code>docker run -d</code></h4>

<p>Let's try booting up our Redis image to see if it works.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -t redis:2.8.17
[1] 17 Nov 08:32:30.476 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 2.8.17 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in stand alone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 1
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

[1] 17 Nov 08:32:30.485 # Server started, Redis version 2.8.17
[1] 17 Nov 08:32:30.487 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
[1] 17 Nov 08:32:30.487 * The server is now ready to accept connections on port 6379
</code></pre>

<p>Uh oh, this process never ends so our shell is stuck! We'll have to run this container in the background using the <code>-d</code> flag. Let's hit <code>ctrl+c</code> to stop the process and exit back out to our host system.</p>

<pre><code>root@vagrant-ubuntu-trusty-64:/vagrant# docker run -d redis:2.8.17
9e3b945adf4e1e7fc18c8429a2f8696a7bec0b387d088279b2fda8fff306182a
</code></pre>

<blockquote>
  <p>Docker allows us to daemonize a container process with <code>-d</code> so it runs in the background</p>
</blockquote>

<p>The <code>docker run</code> command printed out the id of the container that it created. Let's try starting a background container running PostgreSQL as well.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -d postgres:9.3.5
8170b29887b793dce20fa63a1b0424e1edbf4eafea9ec294192c194915c6a213
</code></pre>

<p>That was pretty easy! Let's figure out a way to list out the names and ids of the currently running containers just to make sure.</p>

<h4 id="listrunningcontainerswithdockerps">List running containers with <code>docker ps</code></h4>

<p>Simply calling <code>docker ps</code> will list out all currently running containers.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED              STATUS              PORTS               NAMES
8170b29887b7        postgres:9.3.5      /docker-entrypoint.s   About a minute ago   Up About a minute   5432/tcp            dreamy_lalande
9e3b945adf4e        redis:2.8.17        /entrypoint.sh redis   6 minutes ago        Up 5 minutes        6379/tcp            distracted_leakey
e83564543aed        redis:2.8.17        /entrypoint.sh redis   8 minutes ago        Up 8 minutes        6379/tcp            naughty_wozniak
</code></pre>

<p>Wait... why do we have two Redis containers running? One of them was from earlier when we didn't start the container in the background with <code>-d</code>! We detached from the process but we didn't actually stop the container.</p>

<h4 id="stopcontainerswithdockerstop">Stop containers with <code>docker stop</code></h4>

<p>The <code>docker stop</code> command accepts the id of a container and stops it. Pretty straightforward!</p>

<p>Let's try stopping the old Redis container.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker stop e83564543aed
e83564543aed
</code></pre>

<p>Looks like it worked! Let's run <code>docker ps</code> again just to make sure.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
8170b29887b7        postgres:9.3.5      /docker-entrypoint.s   11 minutes ago      Up 11 minutes       5432/tcp            dreamy_lalande
9e3b945adf4e        redis:2.8.17        /entrypoint.sh redis   16 minutes ago      Up 16 minutes       6379/tcp            distracted_leakey
</code></pre>

<p>The old Redis container is gone! Now let's try connecting our running background services to our Rails application.</p>

<h4 id="linkcontainerswithdockerrunlink">Link containers with <code>docker run --link</code></h4>

<p>TODO: Demonstrate naming and linking containers for Redis and PostgreSQL.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -v $PWD:/app --link 8170b29887b7:db --link 9e3b945adf4e:redis example-app bundle exec rake db:create:all
</code></pre>

<h4 id="namecontainerswithdockerrunname">Name containers with <code>docker run --name</code></h4>

<p>TODO: Demonstrate naming the Redis and PostgreSQL containers.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -d --name redis redis:2.8.17
root@ubuntu-trusty-64:/vagrant# docker run -d --name db postgres:9.3.5
</code></pre>

<h4 id="setenvironmentvariableswithdockerrune">Set environment variables with <code>docker run -e</code></h4>

<p>TODO: Demonstrate setting <code>DB_ADAPTER</code>, <code>DB_USER</code>, <code>DB_PASS</code>, and <code>REDIS_URL</code>.</p>

<pre><code>root@ubuntu-trusty-64:/vagrant# docker run -v $PWD:/app --link db:db --link redis:redis -e "DB_ADAPTER=postgis" -e "DB_USER=docker" -e "DB_PASS=docker" -e "REDIS_URL=redis://redis" example-app bundle exec rake db:create:all
</code></pre>

<h4 id="listallcontainerswithdockerpsa">List all containers with <code>docker ps -a</code></h4>

<p>TODO: Demonstrate listing all containers, including stopped, with <code>docker ps -a</code>.</p>

<h4 id="removecontainerswithdockerrmanddockerrunrm">Remove containers with <code>docker rm</code> and <code>docker run --rm</code></h4>

<p>TODO: Demonstrate removing stopped containers with <code>docker rm</code>. Demonstrate shortcut for removing multiple containers at once. Auto remove containers after its process ends with <code>docker run --rm</code>.</p>

<h4 id="startupmultiplecontainerswithfig">Start up multiple containers with <code>Fig</code></h4>

<p>TODO: Demonstrate spinning up a full stack with Rails, Redis, and PostgreSQL.</p>

<h4 id="rundockerwithindockerbymountingvarlibdocker">Run Docker within Docker by mounting <code>/var/lib/docker</code></h4>

<p>TODO: Demonstrate managing Docker images and containers from within a running container.</p>

<h3 id="todo">TODO</h3>

<ul>
<li>compare <code>Dockerfile</code> definitions to classes in programming
<ul><li>they're inheritable</li>
<li>they're only supposed to "do" one thing, in this case, perform a single task</li>
<li>dependencies are passed into containers when initializing</li>
<li><a href="http://www.fig.sh/">fig</a> is like a dependecy injection framework for provisioning docker containers</li></ul></li>
<li>explain how Docker containers are super light weight
<ul><li>they only run one process</li>
<li>they only contain the dependencies required to run that single process</li>
<li>they are supposed to be "stateless", services and data volumes run in their own containers</li></ul></li>
<li>explain how to run containers
<ul><li>naming containers with <code>--name</code></li>
<li>creating volumes with <code>-v example</code></li>
<li>mounting volumes with <code>--volumes-from</code></li></ul></li>
<li>explain data only volumes and how to mount them</li>
<li>explain how to commit running containers</li>
<li>explain how to push images to the Docker Hub</li>
<li>explain how private Docker image registries work</li>
<li>explain how the <code>ADD</code>, <code>COPY</code>, and <code>RUN</code> commands cache works</li>
<li>explain how we can create a <code>package</code> of our application</li>
<li>explain how to <code>import</code> and <code>export</code> images
<ul><li>compressing <code>tar</code> archives with <code>gzip</code></li>
<li>exporting to and from <code>S3</code></li></ul></li>
</ul>]]></description><link>http://shuber.io/docker/</link><guid isPermaLink="false">ae3ecb89-69f5-4dd5-b8ad-f2ddd0aa2519</guid><category><![CDATA[docker]]></category><category><![CDATA[devops]]></category><category><![CDATA[rails]]></category><category><![CDATA[ruby]]></category><dc:creator><![CDATA[Sean Huber]]></dc:creator><pubDate>Fri, 14 Nov 2014 09:43:00 GMT</pubDate></item></channel></rss>