spacer
Ruby developer for Heroku. Climbs rocks in Austin & teaches Rails classes at the University of Texas
  • Follow on Tumblr
  • Ask me anything
  • Rails Classes
  • About Schneems
  • Screencasts
  • Twitter
  • Gem: Wicked
  • Gem: Likeable

Likes

  • Link via thechangelog
    Make your Ruby objects Likeable with Redis

    The Gowalla development team has released Likeable, a Ruby library to make it simple to add social ‘likes’ to your Ruby classes.

    With just a few lines...

    Link via thechangelog
  • Photoset via staff

    Yesterday we did a historic thing. We generated 87,834 phone calls to U.S. Representatives in a concerted effort to protect the Internet. Extraordinary. There’s no doubt that we’ve been heard.

    Photoset via staff
  • Link via thechangelog
    SMTPRoutes - Python-powered SMTP server with Sinatra-style routes

    A cool project from Benjamin E. Coe for SMTP using an elegant DSL in Python:

    class ExampleRoute(Route):...
    Link via thechangelog
  • Link via thechangelog
    A few tools to craft JSON output in a Ruby web app API

    It seems a solid API that returns JSON is almost a prerequisite for any new web app these days. Often these JSON data structures return nested...

    Link via thechangelog
  • Post via hourschool
    The proof is in the numbers

    Check out this great article from Good on “Why Stanford’s Free Online Education Experiment is Booming”

    Numbers like this seem to expose the beginning of a shift in...

    Post via hourschool
Loading latest tweet

You got NoSQL in my Postgres! Using Hstore in Rails

Heroku just announced their support of hstore in their dedicated Postgres 9.1 instances. Hstore is a schema less key value store inside of PostgreSQL that allows us to store data like hashes directly inside of a column. It’s great for when you don’t know exactly what types of attributes you need to store on a model, or if you need to support many different attributes for the same model.

A good example is storing attributes for a Product model. We might start out only selling books, which have an author, number of pages, but then transition over to selling laptops which have cpu speed and display resolution. Using Hstore allows us to easily store all these values without having to make a bunch mostly blank columns.

To get started with Rails and hstore you can watch the screencast below or visit the hstore example app running on Heroku.

More on Hstore

Hstore in Rails functions much like serializing hashes, except that we can query our data much faster since hstore is a native data type. It is supported natively in Rails 4, but until then we’ll need to use the activerecord-postgres-hstore gem.

Getting Started

You will need a version of PostgreSQL locally that supports the hstore extension. I recommend installing postgres using homebrew on OS X. Once you’ve done that you can enable hstore usage by running this in Postgres

CREATE EXTENSION hstore;

You can put this in a migration if you prefer

class SetupHstore < ActiveRecord::Migration
  def self.up
    execute "CREATE EXTENSION hstore"
  end

  def self.down
    execute "DROP EXTENSION hstore"
  end
end

Once that is done you will need to create a column with a type of hstore, here we are giving our Product model a column called data with hstore type.

class CreateProducts < ActiveRecord::Migration
  def change
    create_table :products do |t|
      t.string  :name
      t.hstore  :data
      t.timestamps
    end
  end
end

Once we’ve done that we can now store any type of attributes in the data column.

Product.create(:name => "Geek Love: A Novel", :data => {'author' => 'Katherine Dunn', 'pages' => 368, 'category' => 'fiction'})
Product.last.data['category']  # => 'fiction'

Querying

Not only does hstore allow us to store arbitrary keys and values it allows us to quickly query them.

  # Find all products that have a key of 'author' in data
  Product.where("data ? :key", :key => 'author')

  # Find all products that have a 'pages' and '368' key value pair in data
  Product.where("data @> (:key => :value)", :key => 'pages', :value => '368')

  # Find all products that don't have a key value pair 'pages' and '999' in data
  Product.where("not data @> (:key => :value)", :key => 'pages', :value => '999')

  # Find all products having key 'author' and value like 'ba' in data
  Product.where("data -> :key LIKE :value",     :key => 'author, :value => "%Kat%")

More information available in the Postgres hstore docs. Though like a normal column if you query it frequently, you can get even more speed by adding an index. You can do this using one of two indexes that also speed up full text searches. They’re GiST (Generalized Search Tree) or GIN (Generalized Inverted iNdex). Which sill speed up queries using the @> and ? postgres operators.

class Index < ActiveRecord::Migration
  def up
    execute "CREATE INDEX products_gin_data ON products USING GIN(data)"
  end

  def down
    execute "DROP INDEX products_gin_data"
  end
end

Use It

Try out the hstore example app, clone the Github repo, and let me know what cool things you build on twitter @schneems.

Thanks

Special thanks to Aaron Patterson and Joel Hoffman for their work with hstore & Rails4, to the team at Softa for writing this gem, & and the team at Heroku for their contributions to Postgres, and supporting this feature.

spacer

Get Down with Heroku at SXSW this year register now. It’s gonna be awesome.

I love doing screencasts, but hate the way my MBP mic sounds, so I got a Rode Podcaster mic. You can see the difference in this quick video. All sound is raw and un-edited. I’m pretty happy with the purchase :)

Test Drive: Induction - The Everything Database Client for Mac

Join me for a quick demo of Induction, the latest project by @Mattt from Heroku. Induction will let you view your data-stores including: PostgreSQL, MySQL, SQLite, Redis, MongoDB, and so much more. The alpha product also lets you run queries, and visualize data.

Induction is completely free and open source, for more info visit the website or clone the repo.

Give Tumblr Some Code <3 with Prettify.js

Lets admit it, code and Tumblr don’t exactly get along right now. Sure you can write your posts in markdown, but there isn’t really an out of the box experience for syntax highlighting in code blocks.

In the past I’ve resorted to using Gists to store code in my blog, but this can be a hassle to manage, especially if you need to modify your code later. One day I noticed that one of my favorite blogs The Changelog has great code highlighting on their Tumblr blog. With a little view source-ing and a little googling I eventually found out that the best way to add code highlighting to your blog is through a javascript library called prettify.js. I followed these directions by blairvanderhoof, and came up with something not too bad. While his instructions are good, I made a few modifications. Lets take a look.

  1. Link to the prettify.js CDN in your html, by customizing and putting this in right before the<body> tag:

    <script type="text/javascript" src="/img/spacer.gif"> 
  2. Add an the ‘prettyprint’ class to all <pre> tags that contain a <code> tag. Then initialize the prettyPrint() javascript method by adding this in your HTML:

    $(document).ready( function(){
      $('code').parent('pre').addClass('prettyprint');
      prettyPrint();
    });
    
  3. Pick a prettify theme. I chose the Desert theme. Add that style to the Add Custom CSS under the advanced section, or directly to your HTML.

     /* desert scheme ported from vim to google prettify */
    pre { display: block; background-color: #333; overflow:scroll; px;  }
    pre .nocode { background-color: none; color: #000 }
    pre .str { color: #ffa0a0 } /* string  - pink */
    pre .kwd { color: #f0e68c; font-weight: bold }
    pre .com { color: #87ceeb } /* comment - skyblue */
    pre .typ { color: #98fb98 } /* type    - lightgreen */
    pre .lit { color: #cd5c5c } /* literal - darkred */
    pre .pun { color: #fff }    /* punctuation */
    pre .pln { color: #fff }    /* plaintext */
    pre .tag { color: #f0e68c; font-weight: bold } /* html/xml tag    - lightyellow */
    pre .atn { color: #bdb76b; font-weight: bold } /* attribute name  - khaki */
    pre .atv { color: #ffa0a0 } /* attribute value - pink */
    pre .dec { color: #98fb98 } /* decimal         - lightgreen */
    
    /* Specify class=linenums on a pre to get line numbering */
    ol.linenums { margin-top: 0; margin-bottom: 0; color: #AEAEAE } /* IE indents via margin-left */
    li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8 { list-style-type: none }
    /* Alternate shading for lines */
    li.L1,li.L3,li.L5,li.L7,li.L9 { }
    
    @media print {
      pre { background-color: none }
      pre .str, code .str { color: #060 }
      pre .kwd, code .kwd { color: #006; font-weight: bold }
      pre .com, code .com { color: #600; font-style: italic }
      pre .typ, code .typ { color: #404; font-weight: bold }
      pre .lit, code .lit { color: #044 }
      pre .pun, code .pun { color: #440 }
      pre .pln, code .pln { color: #000 }
      pre .tag, code .tag { color: #006; font-weight: bold }
      pre .atn, code .