<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Joe&#039;s Notes</title>
	<atom:link href="http://simple10.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://simple10.com</link>
	<description>web development, startup, and life musings</description>
	<lastBuildDate>Wed, 11 Apr 2012 18:38:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Chaining Bundle Gemfiles</title>
		<link>http://simple10.com/chaining-bundle-gemfiles/</link>
		<comments>http://simple10.com/chaining-bundle-gemfiles/#comments</comments>
		<pubDate>Wed, 11 Apr 2012 18:38:47 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[rails3]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://simple10.com/?p=307</guid>
		<description><![CDATA[Useful little snippet to include gem files inside of each other.]]></description>
			<content:encoded><![CDATA[<p>Useful little snippet to include gem files inside of each other.</p>
<pre class="brush: ruby; title: ; notranslate">
eval(IO.read(File.expand_path('../somedir/Gemfile', __FILE__)), binding)
</pre>
]]></content:encoded>
			<wfw:commentRss>http://simple10.com/chaining-bundle-gemfiles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Save Only Changed Attributes in Backbone.js</title>
		<link>http://simple10.com/save-only-changed-attributes-in-backbone-js/</link>
		<comments>http://simple10.com/save-only-changed-attributes-in-backbone-js/#comments</comments>
		<pubDate>Sat, 24 Mar 2012 21:23:02 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[backbone.js]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://simple10.com/?p=301</guid>
		<description><![CDATA[Backbone.js syncs all model data to the server by default regardless of what actually changed. This makes a lot of frontend tasks and debugging much easier, but for some models, sending all the data every time is overkill. Here&#8217;s a quick extension to backbone models and collections to only sync changes. Just call model.saveChanges instead [...]]]></description>
			<content:encoded><![CDATA[<p>Backbone.js syncs all model data to the server by default regardless of what actually changed. This makes a lot of frontend tasks and debugging much easier, but for some models, sending all the data every time is overkill.</p>
<p>Here&#8217;s a quick extension to backbone models and collections to only sync changes. Just call model.saveChanges instead of model.save and only your changes will be synced.</p>
<pre class="brush: jscript; title: ; notranslate">
# CoffeeScript
cx_backbone_common =
  sync: (method, model, options) -&gt;
    # Changed attributes will be available here if model.saveChanges was called instead of model.save
    if method == 'update' &amp;&amp; model.changedAttributes()
      options.data = JSON.stringify(model.changedAttributes())
      options.contentType = 'application/json';
    Backbone.sync.call(this, method, model, options)

cx_backbone_model =
  # Calling this method instead of set will force sync to only send changed attributes
  # Changed event will not be triggered until after the model is synced
  saveChanges: (attrs) -&gt;
    @save(attrs, {wait: true})

_.extend(Backbone.Model.prototype, cx_backbone_common, cx_backbone_model)
_.extend(Backbone.Collection.prototype, cx_backbone_common)
</pre>
]]></content:encoded>
			<wfw:commentRss>http://simple10.com/save-only-changed-attributes-in-backbone-js/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RSpec + Capybara + Devise Login Tests</title>
		<link>http://simple10.com/rspec-capybara-devise-login-tests/</link>
		<comments>http://simple10.com/rspec-capybara-devise-login-tests/#comments</comments>
		<pubDate>Fri, 16 Mar 2012 03:00:42 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://simple10.com/?p=290</guid>
		<description><![CDATA[For the new version of Connect.Me (in development), the interface is mostly driven through AJAX interactions. In the past, I&#8217;ve used Cucumber + Capybara to test JavaScript, but I really don&#8217;t like the Cucumber syntax and slow tests. I recently switched to RSpec request specs with Capybara. The only problem is testing testing JS on [...]]]></description>
			<content:encoded><![CDATA[<p>For the new version of <a href="http://connect.me">Connect.Me</a> (in development), the interface is mostly driven through AJAX interactions. In the past, I&#8217;ve used Cucumber + Capybara to test JavaScript, but I really don&#8217;t like the Cucumber syntax and slow tests. I recently switched to RSpec request specs with Capybara. The only problem is testing testing JS on pages that require a login.</p>
<p>Since Capybara runs in a different thread from the tests, session data is not available. So the Devise sign_in method does nothing for Capybara.</p>
<p>There are basically two solutions to get Capybara to authenticate:</p>
<ol>
<li>Use Capybara to login through a Devise login form by posting the user&#8217;s email and password</li>
<li>Set session data in Capybara to simulate a login (basically do the same thing that Devise&#8217;s sign_in does)</li>
</ol>
<p>For speed of tests reasons, I&#8217;d prefer to just set session data. After Googling around, I found <a href="http://stackoverflow.com/questions/9144865/rspec-capybara-request-specs-cant-get-devise-to-post-new-user-session">this solution</a> and modified it a bit.</p>
<pre class="brush: ruby; title: ; notranslate">
# spec/support/request_helpers.rb
require 'spec_helper'
include Warden::Test::Helpers

module RequestHelpers
  def create_logged_in_user
    user = Factory(:user)
    login(user)
    user
  end

  def login(user)
    login_as user, scope: :user
  end
end
</pre>
<p>Now you just need to call create_logged_in_user and you&#8217;re good to go.</p>
<pre class="brush: ruby; title: ; notranslate">
describe &quot;user settings&quot; do
  let(:authed_user) { create_logged_in_user }

  it &quot;should allow access&quot; do
    visit user_settings_path(authed_user)
    # should be good!
  end
end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://simple10.com/rspec-capybara-devise-login-tests/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Resque Admin in Rails 3 Routes with CanCan</title>
		<link>http://simple10.com/resque-admin-in-rails-3-routes-with-cancan/</link>
		<comments>http://simple10.com/resque-admin-in-rails-3-routes-with-cancan/#comments</comments>
		<pubDate>Fri, 08 Jul 2011 19:01:49 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[rails3]]></category>

		<guid isPermaLink="false">http://www.simple10.com/?p=284</guid>
		<description><![CDATA[Resque is a background jobs queue that&#8217;s highly recommended over Delayed::Job if you are processing a lot of jobs. It uses Redis as the backend which doesn&#8217;t suffer from db related bottlenecks under high load. Resque comes with a built-in admin interface that&#8217;s Rack compatible. In Rails 3, you can mount the Resque server admin [...]]]></description>
			<content:encoded><![CDATA[<p><a href="https://github.com/defunkt/resque">Resque</a> is a background jobs queue that&#8217;s highly recommended over Delayed::Job if you are processing a lot of jobs. It uses <a href="http://redis.io/">Redis</a> as the backend which doesn&#8217;t suffer from db related bottlenecks under high load.</p>
<p>Resque comes with a built-in admin interface that&#8217;s Rack compatible. In Rails 3, you can mount the Resque server admin directly in your routes.rb file.</p>
<pre class="brush: ruby; title: ; notranslate">
mount Resque::Server, at: '/resque'
</pre>
<p>But you&#8217;ll definitely want to add password protection. Ryan Bates in his <a href="http://railscasts.com/episodes/271-resque">Resque RailsCast</a> covers the basics of using Devise and HTTP auth. However, you&#8217;ll probably want to hook into your existing ACL system. In my case, I&#8217;m using <a href="https://github.com/ryanb/cancan">CanCan</a>.</p>
<p>CanCan is not available in the routes.rb by default, but it&#8217;s pretty easy to manually load the user and check permissions.</p>
<pre class="brush: ruby; title: ; notranslate">
# routes.rb
namespace :admin do
  constraints CanAccessResque do
    mount Resque::Server, at: 'resque'
  end
end
</pre>
<pre class="brush: ruby; title: ; notranslate">
# config/initializers/admin.rb
class CanAccessResque
  def self.matches?(request)
    current_user = request.env['warden'].user
    return false if current_user.blank?
    Ability.new(current_user).can? :manage, Resque
  end
end
</pre>
<pre class="brush: ruby; title: ; notranslate">
# ability.rb
class Ability
  include CanCan::Ability
  def initialize(user)
    user ||= User.new
    if user.is_admin?
      can :manage, Resque
    end
  end
end
</pre>
<p>You&#8217;ll need User.is_admin? method or change the logic in Ability to suit your project.</p>
<p>Now an authenticated user with is_admin? == true will be able to access Resque admin. Other users will get a 404 since no route matches.</p>
<p>Thanks to <a href="http://www.arcath.net/posts/38">Arcath&#8217;s blog post</a> for initially pointing me in the right direction.</p>
]]></content:encoded>
			<wfw:commentRss>http://simple10.com/resque-admin-in-rails-3-routes-with-cancan/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Rescuing from Rack::Timeout to Close MongoDB Connection</title>
		<link>http://simple10.com/rescuing-from-racktimeout-to-close-mongodb-connection/</link>
		<comments>http://simple10.com/rescuing-from-racktimeout-to-close-mongodb-connection/#comments</comments>
		<pubDate>Thu, 07 Jul 2011 22:56:09 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[rails3]]></category>

		<guid isPermaLink="false">http://www.simple10.com/?p=278</guid>
		<description><![CDATA[I&#8217;m using Rack::Timeout on Heroku to kill requests before Heroku&#8217;s 30 second limit is reached. This helps applications play nice with cloud infrastructure but can cause some unexpected bugs with MongoDB connections being reused by the next request. The errors showed up as&#8230; Mongo::ConnectionFailure: Expected response 372 but got 371 Mongo ruby driver >=1.3 catches [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m using Rack::Timeout on Heroku to kill requests before Heroku&#8217;s 30 second limit is reached. This helps applications play nice with cloud infrastructure but can cause some unexpected bugs with <a href="https://jira.mongodb.org/browse/RUBY-231?focusedCommentId=26045&#038;page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_26045">MongoDB connections being reused</a> by the next request.</p>
<p>The errors showed up as&#8230;</p>
<blockquote><p>Mongo::ConnectionFailure: Expected response 372 but got 371</p></blockquote>
<p>Mongo ruby driver >=1.3 catches the reused request and raises an error, but this still means the first and next requests both returned errors. It&#8217;s much better to catch the initial timeout and close the connection.</p>
<p>It seems like rescue_from Timeout::Error in ApplicationController should work, but for some reason the exception passed in is a Class and not Timeout::Error – most likely due to Rack::Timeout wrapping the entire app.</p>
<p>I <a href="http://www.google.com/search?sourceid=chrome&#038;ie=UTF-8&#038;q=rescue_from+timeout+error">googled around</a> and couldn&#8217;t find a more elegant solution, but the below snippet in ApplicationController does the trick.</p>
<pre class="brush: ruby; title: ; notranslate">
  # note: can not rescue from Timeout::Error directly because a timeout from Rack::Timeout ends up passing in Class as the exception
  rescue_from Exception do |exception|
    # catch Timeout::Error or message from Rack::Timeout
    if exception.is_a?(Timeout::Error) || /execution expired/ =~ exception.message
      # prevent subsequent requests from reusing this mongo connection
      Mongoid.database.connection.close
    end
    raise
  end
</pre>
<p>As a side note, Heroku&#8217;s new cedar stack does not have the 30 second limit if you&#8217;re streaming data – Rails 3.1 supports streaming.</p>
]]></content:encoded>
			<wfw:commentRss>http://simple10.com/rescuing-from-racktimeout-to-close-mongodb-connection/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Validating a Single Attribute in Rails ActiveRecord</title>
		<link>http://simple10.com/validating-a-single-attribute-in-rails-activerecord/</link>
		<comments>http://simple10.com/validating-a-single-attribute-in-rails-activerecord/#comments</comments>
		<pubDate>Fri, 18 Feb 2011 06:14:42 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[rails3]]></category>

		<guid isPermaLink="false">http://www.simple10.com/?p=274</guid>
		<description><![CDATA[Checking a single attribute on a model for validity doesn&#8217;t seem to be possible in Rails. Or at least I couldn&#8217;t find a quick answer googling around or looking through the ActiveRecord code. What I really want to do is pass a hash into valid? with the attributes I want to validate or have an [...]]]></description>
			<content:encoded><![CDATA[<p>Checking a single attribute on a model for validity doesn&#8217;t seem to be possible in Rails.  Or at least I couldn&#8217;t find a quick answer googling around or looking through the ActiveRecord code.</p>
<p>What I really want to do is pass a hash into valid? with the attributes I want to validate or have an attribute_valid? method. This level of granularity is often useful in AJAX heavy apps. For instance, checking for username availability and validity as the user types during username selection.</p>
<p>Here&#8217;s a quick solution for a User model.</p>
<pre class="brush: ruby; title: ; notranslate">
def attribute_valid?(attr, value)
  u = User.new(attr =&gt; value))
  u.valid?
  !u.errors.has_key?(:username)
end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://simple10.com/validating-a-single-attribute-in-rails-activerecord/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fundraising Advice from Buddy Press Founder</title>
		<link>http://simple10.com/fundraising-advice-from-buddy-press-founder/</link>
		<comments>http://simple10.com/fundraising-advice-from-buddy-press-founder/#comments</comments>
		<pubDate>Fri, 11 Feb 2011 17:05:41 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[fundraising]]></category>
		<category><![CDATA[startup]]></category>

		<guid isPermaLink="false">http://www.simple10.com/?p=271</guid>
		<description><![CDATA[Great startup fundraising article from Michael Lazerow on how to raise money from VC&#8217;s without selling your soul. Take-aways: pick your deep pockets carefully and be wary of sharing too many of your secrets with VCs who might use your market education to fund your competitors.]]></description>
			<content:encoded><![CDATA[<p><a href="http://finance.fortune.cnn.com/2010/12/05/how-to-raise-venture-capital-without-losing-your-soul/">Great startup fundraising article</a> from Michael Lazerow on how to raise money from VC&#8217;s without selling your soul.</p>
<p>Take-aways: pick your deep pockets carefully and be wary of sharing too many of your secrets with VCs who might use your market education to fund your competitors. </p>
]]></content:encoded>
			<wfw:commentRss>http://simple10.com/fundraising-advice-from-buddy-press-founder/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails 3&#8242;s unobtrusive javascript support&#8230;</title>
		<link>http://simple10.com/256/</link>
		<comments>http://simple10.com/256/#comments</comments>
		<pubDate>Wed, 09 Feb 2011 19:57:18 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[jquery]]></category>
		<category><![CDATA[rails3]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[autocomplete]]></category>

		<guid isPermaLink="false">http://www.simple10.com/?p=256</guid>
		<description><![CDATA[Rails 3&#8242;s unobtrusive javascript support makes it easy to integrate jQuery UI Autocomplete and any backend or custom query you want. There&#8217;s a Rails3 jQuery Autocomplete gem already available on github, but it&#8217;s not very RESTful and makes a lot of assumptions that might not fit your application.  So why not roll your own? It&#8217;s easy. [...]]]></description>
			<content:encoded><![CDATA[<p>Rails 3&#8242;s unobtrusive javascript support makes it easy to integrate <a href="http://jqueryui.com/demos/autocomplete/">jQuery UI Autocomplete</a> and any backend or custom query you want. There&#8217;s a <a href="https://github.com/crowdint/rails3-jquery-autocomplete">Rails3 jQuery Autocomplete</a> gem already available on github, but it&#8217;s not very RESTful and makes a lot of assumptions that might not fit your application.  So why not roll your own?</p>
<p>It&#8217;s easy.</p>
<p>First, make sure your rails app is setup with jQuery support.</p>
<p>Next, download <a href="http://jqueryui.com/download">jQuery UI Autocomplete</a>, copy the appropriate files into your javascripts and stylesheets directories, and make sure the JS and CSS files are loading properly in your app.</p>
<p>Here&#8217;s the general process I use to setup autocomplete for Rails 3:</p>
<p><strong>In the controller</strong></p>
<ol>
<li>create a method to handle the autocomplete search request</li>
</ol>
<p><strong>In routes</strong></p>
<ol>
<li>add a route for the method you created in the controller – this is your autocomplete search endpoint</li>
</ol>
<p><strong>In the view</strong></p>
<ol>
<li>add a text field with a unique class name like &#8216;autocomplete&#8217;</li>
<li>add a unique data attribute like &#8216;data-endpoint&#8217; to the text field and set it to the path of your autocomplete endpoint</li>
</ol>
<p><strong>In application.js</strong></p>
<ol>
<li>enable jQuery Autocomplete on any DOM element with the class &#8216;autocomplete&#8217; (or whatever you used in the view)</li>
<li>use the value of data-endpoint as the source URL for the jQuery Autocomplete widget</li>
</ol>
<p>In the following example, I&#8217;m tagging a user and using autocomplete to help suggest tags.</p>
<p><strong>controllers/users/tags_controller.rb</strong></p>
<pre class="brush: ruby; title: ; notranslate">
class Users::TagsController &lt; ApplicationController
  respond_to :json
  skip_before_filter :authenticate_user!, :only =&gt; [:index]

  def index
    @user = User.find(params[:user_id])
    @tags = Tag.where([&quot;LOWER(name) LIKE ?&quot;, &quot;#{params[:term].downcase}%&quot;]).select('name').limit(15).map {|tag| tag.name}
    respond_with(@tags)
  end

  def create
    @user = User.find(params[:user_id])
    tag = @user.tags.create!(params[:tag])
    flash[:success] = 'Tag added'
    redirect_to user_path(@user)
  end
end
</pre>
<p>The tags controller has two methods. One for creating a tag, and one (index) for handling tag autocomplete searches.</p>
<p>The index method expects user_id and term params. In this example, the user_id is being handled in the path /users/:user_id/tags and jQuery Autocomplete sends in the term param.</p>
<p><strong>routes.rb</strong></p>
<pre class="brush: ruby; title: ; notranslate">
resources :users do
  resources :tags, :only =&gt; [:index, :create], :controller =&gt; 'users/tags'
end
</pre>
<p>This creates a /users/:user_id/tags route and a users_tags_path helper to use in your views.</p>
<p><strong>views/users/show.html.haml</strong></p>
<pre class="brush: ruby; title: ; notranslate">
= form_for [@user, @user.tags.build] do |f|
  .field
    = f.label :name, 'Tag'
    = f.text_field :name, :class =&gt; 'autocomplete', :'data-endpoint' =&gt; user_tags_path(@user)
  = f.submit 'Add Tag'
</pre>
<p><strong>javascripts/application.js</strong></p>
<pre class="brush: ruby; title: ; notranslate">
jQuery(function($){
  $('.autocomplete').each(function(){
    var self = $(this);
    self.autocomplete({source: self.attr('data-endpoint')});
  });
});
</pre>
<p>That&#8217;s all there is to it.  You can easily modify your controller and model code to use MongoDB, Solr, Redis, or whatever you want.</p>
<p>Happy coding.</p>
]]></content:encoded>
			<wfw:commentRss>http://simple10.com/256/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Git Hacks for OSX</title>
		<link>http://simple10.com/git-hacks-for-osx/</link>
		<comments>http://simple10.com/git-hacks-for-osx/#comments</comments>
		<pubDate>Mon, 07 Feb 2011 03:20:33 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[misc]]></category>

		<guid isPermaLink="false">http://www.simple10.com/?p=246</guid>
		<description><![CDATA[Use these git config settings and tools to make your life easier. Git tab autocomplete for OSX &#8211; enables tab autocomplete for most git commands Git autocomplete is super helpful if you have long branch names. Add the below code to your ~/.gitconfig file to enable color and popular short codes. GitX &#8211; git graphical [...]]]></description>
			<content:encoded><![CDATA[<p>Use these git config settings and tools to make your life easier.</p>
<p><a href="http://www.codethatmatters.com/2010/01/git-autocomplete-in-mac-os-x/">Git tab autocomplete for OSX</a> &#8211; enables tab autocomplete for most git commands</p>
<p>Git autocomplete is super helpful if you have long branch names.</p>
<p>Add the below code to your ~/.gitconfig file to enable color and popular short codes.</p>
<pre class="brush: bash; title: ; notranslate">
[color]
	ui = auto
[alias]
	co = checkout
	br = branch
	st = status
</pre>
<p><a href="http://gitx.frim.nl/">GitX</a> &#8211; git graphical viewer &#8211; better than gitk</p>
<p>The <a href="https://github.com/brotherbard/gitx">brotherbard</a> fork of gitx has some recommended improvements.</p>
<p>Thanks to <a href="https://github.com/empact">Ben Woolsey</a> for all these tips.  Ben is working with us on a new startup.</p>
]]></content:encoded>
			<wfw:commentRss>http://simple10.com/git-hacks-for-osx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails 3 + STI: Making Associations Work Properly</title>
		<link>http://simple10.com/rails-3-sti/</link>
		<comments>http://simple10.com/rails-3-sti/#comments</comments>
		<pubDate>Tue, 18 Jan 2011 07:13:30 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[rails3]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.simple10.com/?p=196</guid>
		<description><![CDATA[I really like the idea of Single Table Inheritance (STI) for all sorts of applications to keep code DRY and make it easier to organize object behavior. The only problem is that Rails 3.0.3 doesn&#8217;t fully support STI with association collections. Let&#8217;s say you have a User model that has many badges. The badges will [...]]]></description>
			<content:encoded><![CDATA[<p>I really like the idea of Single Table Inheritance (STI) for all sorts of applications to keep code DRY and make it easier to organize object behavior. The only problem is that Rails 3.0.3 doesn&#8217;t fully support STI with association collections.</p>
<p>Let&#8217;s say you have a User model that has many badges. The badges will be stored in the badges table but you want to implement each badge in a subclass. All you have to do is make sure there&#8217;s a <strong>:type</strong> field of type string in your badges table and Rails STI support should take care of the rest (well, in theory).</p>
<pre class="brush: ruby; title: ; notranslate">
class User &lt; ActiveRecord::Base
  has_many :badges
end

class Badge &lt; ActiveRecord::Base
  belongs_to :user
  def award
    raise &quot;Must implement in subclass&quot;
  end
end

class Badges::Superhero &lt; Badge
  def award
    user.status = 'superhero'
  end
end
</pre>
<p>Now you can do cool things like create a new Superhero badge and add it to a user&#8217;s badge collection.</p>
<pre class="brush: ruby; title: ; notranslate">
user = User.first
badge = Badges::Superhero.new
user.badges &lt;&lt; badge
</pre>
<p>But for some weird reason, you can&#8217;t use the best practice of building a badge directly from the user&#8217;s badges collection.</p>
<pre class="brush: ruby; title: ; notranslate">
user = User.first
badge = user.badges.build(:type =&gt; Badges::Superhero)
# badge.class == Badge
</pre>
<p>This is particularly annoying if you&#8217;re trying to create new badges from a form where :type is a drop down menu.</p>
<p>The reason the collection build method doesn&#8217;t work as expected is because :type is a protected field and ActiveRecord::AssociationReflection doesn&#8217;t fully support STI (at least in Rails 3.0.3).</p>
<p>Not to fret, hacks to the rescue!</p>
<p>You have two options to make STI work as expected.</p>
<p><strong>Option 1: Override the Badge.new method to handle :type<br />
</strong></p>
<pre class="brush: ruby; title: ; notranslate">
class Badge &lt; ActiveRecord::Base
  belongs_to :user
  self.abstract_class = true

  class &lt;&lt; self
    def new_with_cast(*a, &amp;b)
      if (h = a.first).is_a? Hash and (type = h.symbolize_keys[self.class.inheritance_column.to_sym]) and (klass = type.to_s.constantize) != self
        raise &quot;Must be a subclass of Badge&quot; unless klass &lt; self  # klass should be a descendant of self
        return klass.new_without_cast(*a, &amp;b)
      end
      raise &quot;Badge must be created through a subclass.&quot;
      new_without_cast(*a, &amp;b)
    end
    alias_method_chain :new, :cast
  end
end
</pre>
<p><strong>Option 2: Patch AssociationReflection to behave more intelligently<br />
</strong></p>
<pre class="brush: ruby; title: ; notranslate">
class ActiveRecord::Reflection::AssociationReflection
  def build_association(*opts)
    col = klass.inheritance_column.to_sym
    if (h = opts.first).is_a? Hash and (type = h.symbolize_keys<div class='shortcode col'></div>) and type.class == Class
      opts.first<div class='shortcode col'></div>.to_s.constantize.new(*opts)
    elsif klass.abstract_class?
      raise &quot;#{klass.to_s} is an abstract class and can not be directly instantiated&quot;
    else
      klass.new(*opts)
    end
  end
end
</pre>
<p>My preference is Option 2 even though it might break in future releases of Rails. I&#8217;d rather have Rails behaving as expected than pepper my models code with repetitive hacks.</p>
<p>The above solutions were inspired from a couple of different <a href="http://coderrr.wordpress.com/2008/04/22/building-the-right-class-with-sti-in-rails/">posts</a> and <a href="http://stackoverflow.com/questions/2553931/can-nested-attributes-be-used-in-combination-with-inheritance">sources</a>.</p>
<p>I submitted Option 2 as a <a href="https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/6306-collection-associations-build-method-not-supported-for-sti">patch for Rails</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://simple10.com/rails-3-sti/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Served from: simple10.com @ 2012-05-20 21:57:04 -->
