<?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>Coffee Powered &#187; Rails</title>
	<atom:link href="http://www.coffeepowered.net/tag/rails/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.coffeepowered.net</link>
	<description>code and content</description>
	<lastBuildDate>Mon, 09 Jan 2012 18:32:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Rails, Varnish, Cookie Sessions, and CSRF tokens</title>
		<link>http://www.coffeepowered.net/2011/01/29/rails-varnish-cookie-sessions-and-csrf-tokens/</link>
		<comments>http://www.coffeepowered.net/2011/01/29/rails-varnish-cookie-sessions-and-csrf-tokens/#comments</comments>
		<pubDate>Sat, 29 Jan 2011 08:33:29 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[cookies]]></category>
		<category><![CDATA[csr]]></category>
		<category><![CDATA[varnish]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=352</guid>
		<description><![CDATA[I&#8217;ve recently been trying to figure out how to get Rails to place nicely with Varnish. It doesn&#8217;t do that very well. In a nutshell: Varnish is easy to use, if your app isn&#8217;t setting session cookies until you actually need them. The presence of a session cookie usually means that content shouldn&#8217;t be cacheable. [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.coffeepowered.net/wp-content/uploads/2011/01/126070445_82ca5f6f4c_m.jpg" align="right" style="margin: 0 0 15px 15px;" alt="Cookies! Delicious and performance-shattering." />I&#8217;ve recently been trying to figure out how to get Rails to place nicely with <a href="http://varnish-cache.org/">Varnish</a>. It doesn&#8217;t do that very well. In a nutshell:</p>
<ul>
<li>Varnish is easy to use, if your app isn&#8217;t setting session cookies until you actually need them. The presence of a session cookie usually means that content shouldn&#8217;t be cacheable.</li>
<li>Hitting any page with a form results in Rails generating a CSRF token and sticking it in the session, generating a session cookie and effectively locking the rest of the session out of being cacheable (even if it should be).</li>
<li>Just *breathing* the method <code>session</code> in your app initializes your session.</li>
<li>The Rails cookie session middleware assumes you always want to write a session cookie.</li>
</ul>
<p>Fortunately, since so much of this is in Rack middleware, we can fix its mistakes with a middleware of our own. In a nutshell, I&#8217;m going to:</p>
<ul>
<li>Avoid writing CSRF tokens until we actually need them</li>
<li>Check and see if we have an &#8220;empty&#8221; session (ie, no interesting data, just the session ID)</li>
<li>Prevent session cookies from being sent to the browser unless there&#8217;s actually useful data in them.</li>
</ul>
<p><span id="more-352"></span><br />
Let&#8217;s get started. There&#8217;s a lot to this, and it&#8217;s a delicate collection of hacks, but it works nicely.</p>
<h2>The care and feeding of CSRF tokens</h2>
<p>To get started, I disabled CSRF functionality based on user state. In your application_controller.rb:</p>
<pre class="brush: ruby; title: ; notranslate">
  protect_from_forgery :if =&gt; :user?
  skip_before_filter :verify_authenticity_token, :unless =&gt; :user?

protected

  def form_authenticity_token
    if user?
      session[:_csrf_token] ||= ActiveSupport::SecureRandom.base64(32)
    end
  end
</pre>
<p>In this case, <code>user?</code> is a method from my authentication framework that lets me check if I have an active session. The astute reader will note that this check performs the aforementioned breathing-on (and thereby initializing) the session, so it&#8217;s unfortunately not quite as simple as this. However, this will prevent authenticity checks for unauthenticated sessions. There&#8217;s no real point to them if you aren&#8217;t performing privileged operations anyhow, so we&#8217;ll just save the overhead.</p>
<h2>Stuffing your cookies back into the jar</h2>
<p>Next, we need to deal with the session cookie itself. We have two options when invalidating cookies &#8211; either strip them from the already-written headers, or just add another Set-Cookie line to instantly invalidate them. Since we&#8217;re dealing with Varnish, we want option 1 &#8211; ideally, we won&#8217;t be passing the Set-Cookie header, since Varnish (by default) won&#8217;t cache any response that attempts to set a cookie.</p>
<p>Session cookie management happens in <code>ActionController::Session::CookieStore</code>, and it&#8217;s really high up in the middleware stack. <code>rake middleware</code> will dump your stack &#8211; you&#8217;ll find it&#8217;s usually in position 2 or 3. So, in order to tweak it, we&#8217;ll need to inject a new middleware into your stack to mess with your cookie headers after the cookie handler itself blindly writes them out.</p>
<p>Scroll down if you want the code, but the gist of it is this:</p>
<ul>
<li>Check for a special &#8220;cookie.logout&#8221; environment parameter. If this is present, we&#8217;re going to just flat-out nuke the session cookie. More on this later.</li>
<li>Otherwise, check to see if the session has any interesting keys. If it doesn&#8217;t, remove it from the Set-Cookie header</li>
</ul>
<p>The code itself. Drop this in <code>lib/strip_empty_sessions.rb</code>.</p>
<pre class="brush: ruby; title: ; notranslate">
class StripEmptySessions
  ENV_SESSION_KEY = &quot;rack.session&quot;.freeze
  HTTP_SET_COOKIE = &quot;Set-Cookie&quot;.freeze
  BOGUS_KEYS = [:session_id, :_csrf_token]

  def initialize(app, options = {})
    @app = app
    @options = options
  end

  def call(env)
    status, headers, body = @app.call(env)

    session_data = env[ENV_SESSION_KEY]
    sc = headers[HTTP_SET_COOKIE]
    if env[&quot;cookie.logout&quot;]
      value = Hash.new
      value[:value] = &quot;x&quot;
      value[:expires] = Time.now - 1.year
      cookie = build_cookie(@options[:key], value.merge(@options))

      if sc.nil?
        headers[HTTP_SET_COOKIE] = cookie if env[&quot;cookie.logout&quot;]
      elsif sc.is_a? Array
        sc &lt;&lt; cookie if env[&quot;cookie.logout&quot;]
      elsif sc.is_a? String
        headers[HTTP_SET_COOKIE] &lt;&lt; &quot;\n#{cookie}&quot; if env[&quot;cookie.logout&quot;]
      end
    elsif (session_data.keys - BOGUS_KEYS).empty?
      if sc.is_a? Array
        sc.reject! {|c| c.match(/^\n?#{@options[:key]}=/)}
      elsif sc.is_a? String
        headers[HTTP_SET_COOKIE].gsub!( /(^|\n)#{@options[:key]}=.*?(\n|$)/, &quot;&quot; )
      end
    end

    [status, headers, body]
  end

  private

  # Copied from the cookie session middleware.
  def build_cookie(key, value)
    case value
    when Hash
      domain  = &quot;; domain=&quot;  + value[:domain] if value[:domain]
      path    = &quot;; path=&quot;    + value[:path]   if value[:path]
      # According to RFC 2109, we need dashes here.
      # N.B.: cgi.rb uses spaces...
      expires = &quot;; expires=&quot; + value[:expires].clone.gmtime.
        strftime(&quot;%a, %d-%b-%Y %H:%M:%S GMT&quot;) if value[:expires]
      secure = &quot;; secure&quot; if value[:secure]
      httponly = &quot;; HttpOnly&quot; if value[:httponly]
      value = value[:value]
    end
    value = [value] unless Array === value
    Rack::Utils.escape(key) + &quot;=&quot; +
      value.map { |v| Rack::Utils.escape(v) }.join(&quot;&amp;&quot;) +
      &quot;#{domain}#{path}#{expires}#{secure}#{httponly}&quot;
  end
end
</pre>
<p>Next, you&#8217;ll need to add this to your middleware stack. In your <code>environment.rb</code>:</p>
<pre class="brush: ruby; title: ; notranslate">
config.middleware.insert_before &quot;ActionController::Session::CookieStore&quot;, &quot;StripEmptySessions&quot;, :key =&gt; &quot;your_session_key&quot;, :path =&gt; &quot;/&quot;, :httponly =&gt; true
</pre>
<p>The <code>:key</code> and <code>:path</code> parameters should match your session cookie settings.</p>
<p>What this will do is let this middleware run on the way back up the stack, right after the session handler gets a crack at things. If there is nothing interesting in the session, it&#8217;ll remove that line from the Set-Cookie header, so if you aren&#8217;t setting any other cookies, the header should end up being empty and should get thrown away. If you triggered a logout, will invalidate the client cookies (rather than just writing a cookie with no data in it back to them).</p>
<p>To do that, you&#8217;ll need to modify your logout method:</p>
<pre class="brush: ruby; title: ; notranslate">
def logout
  request.env[&quot;cookie.logout&quot;] = true
end
</pre>
<p>That should be it. You should now:</p>
<ol>
<li>Not be setting session cookies for empty sessions</li>
<li>Not be setting CSRF tokens for anonymous sessions</li>
<li>Not be leaving &#8220;empty&#8221; session cookies laying around on client machines after a logout.</li>
</ol>
<p>The net result is that you should be cookieless for anonymous sessions, resulting in trivial caching with Varnish. This can vastly improve the performance of your site &#8211; especially if you&#8217;re catching high-traffic pages from web crawlers and the like with Varnish, so they never touch your Rails stack.</p>
<hr />
<p><i>Cookie image (C) <a href="http://www.flickr.com/photos/71217725@N00/126070445/sizes/z/">scubadive67</a>, used under Creative Commons license</i></p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/01/29/rails-varnish-cookie-sessions-and-csrf-tokens/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Quick tip: Strip URLs before parsing!</title>
		<link>http://www.coffeepowered.net/2009/03/28/quick-tip-strip-urls-before-parsing/</link>
		<comments>http://www.coffeepowered.net/2009/03/28/quick-tip-strip-urls-before-parsing/#comments</comments>
		<pubDate>Sat, 28 Mar 2009 08:09:32 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[error]]></category>
		<category><![CDATA[parse]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[uri]]></category>
		<category><![CDATA[usability]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=170</guid>
		<description><![CDATA[Rather than roll my own URL regexes, I prefer to let the existing libraries do the heavy lifting. Ruby has a uri library which is fantastic for parsing (and validating) URLs. For example, something like this might be used in a model validation: I noticed a bit ago that I started getting invalid URL errors [...]]]></description>
			<content:encoded><![CDATA[<p>Rather than roll my own URL regexes, I prefer to let the existing libraries do the heavy lifting. Ruby has a <code>uri</code> library which is fantastic for parsing (and validating) URLs.</p>
<p>For example, something like this might be used in a model validation:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'uri'

def validate_url(url)
	parsed_uri = URI::parse(url)
rescue URI::InvalidURIError
	errors.add :url, &quot;Sorry, that doesn't look like a valid URL&quot;
end
</pre>
<p>I noticed a bit ago that I started getting invalid URL errors where there shouldn&#8217;t be any. After far too long spent in the library&#8217;s code, I realized my error: the URLs were being pasted with a trailing space. Stripping the string before attempting to parse it fixed it right up.</p>
<p>I&#8217;d argue that URI::parse should likely strip any incoming strings, but in the meantime, remember to strip your user input before trying to determine whether it&#8217;s valid or not, or you may end up with frustrated users.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2009/03/28/quick-tip-strip-urls-before-parsing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mass inserting data in Rails without killing your performance</title>
		<link>http://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/</link>
		<comments>http://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/#comments</comments>
		<pubDate>Sat, 24 Jan 2009 03:55:59 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=82</guid>
		<description><![CDATA[Mass inserting is one of those operations that isn&#8217;t really well-supported by ActiveRecord, but which has to be done nonethless. You might say, &#8220;Well hey, I&#8217;ll just run a loop and create a bunch of AR objects, no sweat&#8221;. That&#8217;ll work, but if speed is a factor, it might not be your best option. ActiveRecord [...]]]></description>
			<content:encoded><![CDATA[<p>Mass inserting is one of those operations that isn&#8217;t really well-supported by ActiveRecord, but which has to be done nonethless. You might say, &#8220;Well hey, I&#8217;ll just run a loop and create a bunch of AR objects, no sweat&#8221;.</p>
<p>That&#8217;ll work, but if speed is a factor, it might not be your best option.</p>
<p>ActiveRecord makes interface to the DB very easy, but it doesn&#8217;t necessarily make it fast. Instantiating an ActiveRecord object is costly, and if you do a lot of &#8216;em, that&#8217;s going to cause you to bump up against the garbage collector, which will significantly hinder performance. There are several options, though, depending on how much speed you need.</p>
<p>There are benchmarks at the bottom of the post, so if you&#8217;re just interested in those, scroll down.<br />
<span id="more-82"></span></p>
<h2>Option 1: Use transactions</h2>
<p>This is definitely the easiest method, and while you&#8217;ll realize gains from it, you aren&#8217;t going to be breaking any speed records using only this method. However, it&#8217;s well worth it if you are doing mass inserts via ActiveRecord.</p>
<p>Instead of</p>
<pre class="brush: ruby; title: ; notranslate">
1000.times { Model.create(options) }
</pre>
<p>You want:</p>
<pre class="brush: ruby; title: ; notranslate">
ActiveRecord::Base.transaction do
  1000.times { Model.create(options) }
end
</pre>
<p>The net effect is that the database performs all of your inserts in a single transaction, rather than starting and committing a new transaction for every request.</p>
<h2>Options 2: Get down and dirty with the raw SQL</h2>
<p>If you know that your data is valid and can afford to skip validations, you can save a <b>lot</b> of time by just jumping directly to raw SQL.</p>
<p>Imagine, for example, that you&#8217;re running the following:</p>
<pre class="brush: ruby; title: ; notranslate">
1000.times {|i| Foo.create(:counter =&gt; i) }
</pre>
<p>That&#8217;s going to create 1000 ActiveRecord objects, run validations, generate the insert SQL, and dump it into the database. You can realize large performance gains by just jumping directly to the generated SQL.</p>
<pre class="brush: ruby; title: ; notranslate">
1000.times do |i|
  Foo.connection.execute &quot;INSERT INTO foos (counter) values (#{i})&quot;
end
</pre>
<p>You should use <code>sanitize_sql</code> and such as necessary to sanitize input values if they are not already sanitized, but with this technique you can realize extremely large performance gains. Of course, wrapping all those inserts in a single transaction, as in Option 1 gets you even more performance.</p>
<pre class="brush: ruby; title: ; notranslate">
Foo.transaction do
  1000.times do |i|
    Foo.connection.execute &quot;INSERT INTO foos (counter) values (#{i})&quot;
  end
end
</pre>
<h2>Option 3: A single mass insert</h2>
<p>Many databases support mass inserts of data in a single insert statement. They are able to significantly optimize this operation under the hood, and if you&#8217;re comfortable using it, will be your fastest option by far.</p>
<pre class="brush: ruby; title: ; notranslate">
inserts = []
TIMES.times do
  inserts.push &quot;(3.0, '2009-01-23 20:21:13', 2, 1)&quot;
end
sql = &quot;INSERT INTO user_node_scores (`score`, `updated_at`, `node_id`, `user_id`) VALUES #{inserts.join(&quot;, &quot;)}&quot;
</pre>
<p>No transaction block is necessary here, since it&#8217;s just a single statement, and the DB will wrap it in a transaction. We build an array of value sets to include, then just join them into the <code>INSERT</code> statement. We don&#8217;t use string concatenation, since it will result in significantly more string garbage generated, which could potentially get us into the GC, which we&#8217;re trying to avoid (and hey, memory savings are always good).</p>
<h2>Option 4: ActiveRecord::Extensions</h2>
<p>njero in <code>#rubyonrails</code> pointed me at <a href="http://www.continuousthinking.com/tags/arext/rdoc/index.html">this nifty little gem</a> and I decided to include it. It seems to try to intelligently do mass inserts of data. I wasn&#8217;t able to get it to emulate the single mass insert for a MySQL database, but it does provide a significant speed increase without much additional work, and can preserve your validations and such.</p>
<p>There&#8217;s the obvious added benefit that you stay in pure Ruby, and don&#8217;t have to get into the raw SQL.</p>
<pre class="brush: ruby; title: ; notranslate">
columns = [:score, :node_id, :user_id]
values = []
TIMES.times do
	values.push [3, 2, 1]
end

UserNodeScore.import columns, values
</pre>
<h2>Benchmarks</h2>
<p>I used a simple script to test each of the methods described here.</p>
<pre class="brush: ruby; title: ; notranslate">
require &quot;ar-extensions&quot;

CONN = ActiveRecord::Base.connection
TIMES = 10000

def do_inserts
	TIMES.times { UserNodeScore.create(:user_id =&gt; 1, :node_id =&gt; 2, :score =&gt; 3) }
end

def raw_sql
	TIMES.times { CONN.execute &quot;INSERT INTO `user_node_scores` (`score`, `updated_at`, `node_id`, `user_id`) VALUES(3.0, '2009-01-23 20:21:13', 2, 1)&quot; }
end

def mass_insert
	inserts = []
	TIMES.times do
		inserts.push &quot;(3.0, '2009-01-23 20:21:13', 2, 1)&quot;
	end
	sql = &quot;INSERT INTO user_node_scores (`score`, `updated_at`, `node_id`, `user_id`) VALUES #{inserts.join(&quot;, &quot;)}&quot;
	CONN.execute sql
end

def activerecord_extensions_mass_insert(validate = true)
	columns = [:score, :node_id, :user_id]
	values = []
	TIMES.times do
		values.push [3, 2, 1]
	end

	UserNodeScore.import columns, values, {:validate =&gt; validate}
end

puts &quot;Testing various insert methods for #{TIMES} inserts\n&quot;
puts &quot;ActiveRecord without transaction:&quot;
puts base = Benchmark.measure { do_inserts }

puts &quot;ActiveRecord with transaction:&quot;
puts bench = Benchmark.measure { ActiveRecord::Base.transaction { do_inserts } }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)

puts &quot;Raw SQL without transaction:&quot;
puts bench = Benchmark.measure { raw_sql }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)

puts &quot;Raw SQL with transaction:&quot;
puts bench = Benchmark.measure { ActiveRecord::Base.transaction { raw_sql } }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)

puts &quot;Single mass insert:&quot;
puts bench = Benchmark.measure { mass_insert }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)

puts &quot;ActiveRecord::Extensions mass insert:&quot;
puts bench = Benchmark.measure { activerecord_extensions_mass_insert }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)

puts &quot;ActiveRecord::Extensions mass insert without validations:&quot;
puts bench = Benchmark.measure { activerecord_extensions_mass_insert(true)  }
puts sprintf(&quot;  %2.2fx faster than base&quot;, base.real / bench.real)
</pre>
<p>And the results:</p>
<pre class="brush: ruby; title: ; notranslate">
Testing various insert methods for 10000 inserts
ActiveRecord without transaction:
 14.930000   0.640000  15.570000 ( 18.898352)
ActiveRecord with transaction:
 13.420000   0.310000  13.730000 ( 14.619136)
  1.29x faster than base
Raw SQL without transaction:
  0.920000   0.170000   1.090000 (  3.731032)
  5.07x faster than base
Raw SQL with transaction:
  0.870000   0.150000   1.020000 (  1.648834)
  11.46x faster than base
Single mass insert:
  0.000000   0.000000   0.000000 (  0.268634)
  70.35x faster than base
ActiveRecord::Extensions mass insert:
  6.580000   0.280000   6.860000 (  9.409169)
  2.01x faster than base
ActiveRecord::Extensions mass insert without validations:
  6.550000   0.240000   6.790000 (  9.446273)
  2.00x faster than base
</pre>
<p>The results are fairly self-explainatory, but of particular note is the specific single INSERT statement. At 70x faster than the non-transactional ActiveRecord insert, if you need speed, it&#8217;s hard to beat.</p>
<h2>Conclusions</h2>
<p>ActiveRecord is great, but sometimes it&#8217;ll hold you back. Finding the balance between ease of use (full ActiveRecord) and performance (bare metal mass inserts) can have a profound effect on the performance of your app.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Quick tip &#8211; use anonymous blocks!</title>
		<link>http://www.coffeepowered.net/2008/10/09/quick-tip-use-anonymous-blocks/</link>
		<comments>http://www.coffeepowered.net/2008/10/09/quick-tip-use-anonymous-blocks/#comments</comments>
		<pubDate>Fri, 10 Oct 2008 05:30:21 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[blocks]]></category>
		<category><![CDATA[memory]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=75</guid>
		<description><![CDATA[In tracking down a memory leak in one of our Rails apps today, I ran across an interesting post detailing the difference between anonymous and named blocks in Ruby, and the performance differences therein. It&#8217;s definitely worth a look, especially if you&#8217;re running in a complex environment, where new closures will be large and unwieldy. [...]]]></description>
			<content:encoded><![CDATA[<p>In tracking down a memory leak in one of our Rails apps today, I ran across an <a href="http://blog.pluron.com/2008/02/rails-faster-as.html">interesting post</a> detailing the difference between anonymous and named blocks in Ruby, and the performance differences therein.</p>
<p>It&#8217;s definitely worth a look, especially if you&#8217;re running in a complex environment, where new closures will be large and unwieldy. It&#8217;s very easy, too. Any time you use:</p>
<pre class="brush: ruby; title: ; notranslate">
def note(text, options = {}, &amp;block)
  options[:class] = ((options[:class] || &quot;&quot;) + &quot; form-note&quot;).strip
  content_tag(:div, text, options, &amp;block)
end
</pre>
<p>Instead, don&#8217;t explicitly name the block parameter; just yield to it, and you prevent all the messiness of creating a new Proc object.</p>
<pre class="brush: ruby; title: ; notranslate">
def note(text, options = {})
  options[:class] = ((options[:class] || &quot;&quot;) + &quot; form-note&quot;).strip
  content_tag(:div, text, options) {|*block_args| yield(*block_args) if block_given? }
end
</pre>
<p>I don&#8217;t have benchmarks just yet, but anecdotally it has definitely slowed instance memory consumption in my apps. It&#8217;s worth taking a look at!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2008/10/09/quick-tip-use-anonymous-blocks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Re: Simple RoR+MySQL optimization</title>
		<link>http://www.coffeepowered.net/2008/09/30/re-simple-rormysql-optimization/</link>
		<comments>http://www.coffeepowered.net/2008/09/30/re-simple-rormysql-optimization/#comments</comments>
		<pubDate>Tue, 30 Sep 2008 21:42:44 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[garabge collector]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[orm]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=58</guid>
		<description><![CDATA[I recently ran across a rather bare post espousing some generic &#8220;optimization&#8221; techniques for Rails apps. It offered no education, no explanation, no benchmarks. So, I thought, why not put those claims to the test? find_by_sql versus find_by_x First, Konstantin claims that Model#find_by_field is slower than Model#find_by_sql. This one is hard to dispute; the first [...]]]></description>
			<content:encoded><![CDATA[<p>I recently ran across a <a href="http://guruonrails.com/blog/simple-ror-mysql-optimization">rather bare post</a> espousing some generic &#8220;optimization&#8221; techniques for Rails apps. It offered no education, no explanation, no benchmarks. So, I thought, why not put those claims to the test?<br />
<span id="more-58"></span></p>
<h2>find_by_sql versus find_by_x</h2>
<p>First, Konstantin claims that <code>Model#find_by_field</code> is slower than <code>Model#find_by_sql</code>. This one is hard to dispute; the first will invoke method_missing and spend time generating SQL, while the latter simply executes a statement. Is cutting the knees out from under your ORM worth the time saved? Let&#8217;s see!</p>
<pre class="brush: ruby; title: ; notranslate">
require 'benchmark'

def measure_find_by_sql_vs_orm(num = 1000)
  puts &quot;find_by_sql (#{num}x)&quot;
  puts Benchmark.measure {
    num.times { User.find_by_sql &quot;select * from users where id = 123&quot; }
  }

  puts &quot;find_by_id (#{num}x)&quot;
  puts Benchmark.measure {
    num.times { User.find_by_id 123 }
  }
end

measure_find_by_sql_vs_orm(10000)
</pre>
<p>Let&#8217;s run this a few times.</p>
<pre><code>
[chris@polaris benchmarks]$ script/runner benchmark.rb
find_by_sql (10000x)
  2.290000   0.540000   2.830000 (  4.452150)
find_by_id (10000x)
  4.660000   0.400000   5.060000 (  6.766629)

[chris@polaris benchmarks]$ script/runner benchmark.rb
find_by_sql (10000x)
  2.300000   0.480000   2.780000 (  4.473950)
find_by_id (10000x)
  4.520000   0.560000   5.080000 (  6.837272)

[chris@polaris benchmarks]$ script/runner benchmark.rb
find_by_sql (10000x)
  2.170000   0.540000   2.710000 (  4.419207)
find_by_id (10000x)
  4.580000   0.540000   5.120000 (  6.881676)

find_by_sql: Averages 4.44 sec for 10,000 queries
find_by_id: Averages 6.83 sec for 10,000 queries
</code></pre>
<p>Conclusion the first: Using the ORM to build SQL adds some overhead; in my tests, 2.47 sec/10,000 queries, or 0.000247 seconds per query. Is this worth optimizing out? Yeah, probably not. In fact, the productivity lost by using <code>find_by_sql</code> is likely going to end up costing the project more.</p>
<h2>IDs and numbers in quotes</h2>
<p>Second, they claim that quoting values in your SQL statements slows down your queries. This one struck me as just a <em>little</em> out there. Let&#8217;s see what the benchmarks say.</p>
<pre class="brush: ruby; title: ; notranslate">
require 'benchmark'

def measure_select_with_quotes(num = 1000)
  puts &quot;Without quotes (#{num}x):&quot;
  db = ActiveRecord::Base.connection.instance_variable_get :@connection
  puts Benchmark.measure {
    num.times { db.query(&quot;select * from users where id = 123&quot;) {} }
  }

  puts &quot;With quotes (#{num}x):&quot;
  puts Benchmark.measure {
    num.times { db.query(&quot;select * from users where id = \&quot;123\&quot;&quot;) {} }
  }
end

measure_select_with_quotes(10000)
</pre>
<p>And the results:</p>
<pre><code>
[chris@polaris benchmarks]$ script/runner benchmark.rb
Without quotes (10000x):
  0.690000   0.340000   1.030000 (  2.639554)
With quotes (10000x):
  0.670000   0.290000   0.960000 (  2.655049)

[chris@polaris benchmarks]$ script/runner benchmark.rb
Without quotes (10000x):
  0.570000   0.320000   0.890000 (  2.654003)
With quotes (10000x):
  0.550000   0.400000   0.950000 (  2.617369)
</code></pre>
<p>Well, that&#8217;s certainly interesting. In 10,000 queries, an average difference of about 3/100ths of a second. Certainly not worth combing through your codebase as an optimization point.</p>
<p>Conclusion the second: The performance gain from quoted versus non-quoted field values is so small to be inconsequential.</p>
<p>On a side note, there is a <b>very</b> interesting subtlety here. Observe the difference between</p>
<pre class="brush: ruby; title: ; notranslate">
num.times { db.query(&quot;select * from users where id = 123&quot;) {} }
</pre>
<p>and </p>
<pre class="brush: ruby; title: ; notranslate">
num.times { db.query(&quot;select * from users where id = 123&quot;) }
</pre>
<p>The former passes the <code>Mysql::Result</code> object to a block, and frees it after the block terminates. The latter does not, and the returned <code>Mysql::Result</code> object remains in scope for the entire pass of the benchmark. This subtlety makes a massive difference.</p>
<pre class="brush: ruby; title: ; notranslate">
def measure_select_with_free(num = 1000)
  db = ActiveRecord::Base.connection.instance_variable_get :@connection

  puts &quot;Query with block, result immediately freed&quot;
  puts Benchmark.measure {
    num.times { db.query(&quot;select * from users where id = 123&quot;) {} }
  }

  puts &quot;Query without block, result remains in scope&quot;
  puts Benchmark.measure {
    num.times { db.query(&quot;select * from users where id = 123&quot;) }
  }
end
</pre>
<pre><code>
[chris@polaris benchmarks]$ script/runner benchmark.rb
Query with block, result immediately freed
  0.060000   0.040000   0.100000 (  0.267983)
Query without block, result remains in scope
  5.040000   0.050000   5.090000 (  5.266476)
</code></pre>
<p>Whoa damn. Ruby&#8217;s GC is <i>slaughtering</i> performance there. Just adding a pair of curly braces makes the benchmark run <i>20 times faster</i>.</p>
<h2>It&#8217;s better to request only specific column</h2>
<p>Finally, Konstantin mentions that selecting only specific fields from a table is faster. This is a truth in both MySQL and in the ActiveRecord ORM, for a number of reasons. However, he says that</p>
<blockquote><p>Person.find_by_name(&#8220;Name&#8221;).phone_number. It would be much faster if you use: Person.find_by_sql(&#8220;SELECT persons.phone_number WHERE persons.name = &#8216;Name&#8217;&#8221;) </p></blockquote>
<p>Why not just use the :select option that ActiveRecord provides?</p>
<pre class="brush: ruby; title: ; notranslate">
Person.find_by_name(&quot;Name&quot;, :select =&gt; &quot;phone_number&quot;)
</pre>
<p>Let&#8217;s test those assumptions.</p>
<pre class="brush: ruby; title: ; notranslate">
def measure_single_field_select(num = 1000)
  puts &quot;Find with all fields&quot;
  puts Benchmark.measure {
    num.times { User.find_by_id(123)}
  }

  puts &quot;Find with one field, with :select&quot;
  puts Benchmark.measure {
    num.times { User.find_by_id(123, :select =&gt; &quot;email&quot;)}
  }
end
</pre>
<pre><code>
[chris@polaris benchmarks]$ script/runner benchmark.rb
Find with all fields
  0.720000   0.060000   0.780000 (  0.963273)
Find with one field, with :select
  0.310000   0.010000   0.320000 (  0.364554)

[chris@polaris benchmarks]$ script/runner benchmark.rb
Find with all fields
  0.710000   0.110000   0.820000 (  1.014548)
Find with one field, with :select
  0.260000   0.020000   0.280000 (  0.351761)
</code></pre>
<p>Very significant difference there&#8230;and we didn&#8217;t have to bypass the ORM to get it, either.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2008/09/30/re-simple-rormysql-optimization/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Powerful, easy, DRY, multi-format REST APIs</title>
		<link>http://www.coffeepowered.net/2008/09/27/powerful-easy-dry-multi-format-rest-apis/</link>
		<comments>http://www.coffeepowered.net/2008/09/27/powerful-easy-dry-multi-format-rest-apis/#comments</comments>
		<pubDate>Sun, 28 Sep 2008 03:53:48 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[jsonp]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[yaml]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=38</guid>
		<description><![CDATA[Rails&#8217; baked-in REST support is great. Build your app right, and you can expose a programmatic interface to your users for free. That said, many times providing views in non-HTML formats tends to be bulky and unwieldy. You end up with either very brittle representations of your data, or extremely bulky respond_to blocks in your [...]]]></description>
			<content:encoded><![CDATA[<p>Rails&#8217; baked-in REST support is great. Build your app right, and you can expose a programmatic interface to your users for free.</p>
<p>That said, many times providing views in non-HTML formats tends to be bulky and unwieldy. You end up with either very brittle representations of your data, or extremely bulky respond_to blocks in your controllers.</p>
<p>Fortunately, there&#8217;s a better way! We&#8217;re going to provide two new render targets, <code>:to_yaml</code> and <code>:to_json</code> which will let us write a single XML builder view, and then provide that view in XML, YAML, and JSON formats according to the consuming developer&#8217;s preferences.</p>
<p>In <code>application.rb</code> you&#8217;ll want to override the render method.</p>
<pre class="brush: ruby; title: ; notranslate">
def render(opts = {}, &amp;block)
  if opts[:to_yaml] then
    headers[&quot;Content-Type&quot;] = &quot;text/plain;&quot;
    render :text =&gt; Hash.from_xml(render_to_string(:template =&gt; opts[:to_yaml], :layout =&gt; false)).to_yaml, :layout =&gt; false
  elsif opts[:to_json] then
    content = Hash.from_xml(render_to_string(:template =&gt; opts[:to_json], :layout =&gt; false)).to_json
    cbparam = params[:callback] || params[:jsonp]
    content = &quot;#{cbparam}(#{content})&quot; unless cbparam.blank?
    render :json =&gt; content, :layout =&gt; false
  else
    super opts, &amp;block
  end
end
</pre>
<p>As you can see, we render a single XML view, and then load it to a hash from XML, and use Rails&#8217; built-in <code>Hash#to_json</code> and <code>Hash#to_yaml</code> methods to provide the data in the desired format. There is a single glaring problem with this approach, though &#8211; <code>Hash#from_xml</code> is <em>dog slow</em> because it uses REXML. There&#8217;s a fantastic solution, though!</p>
<p>Courtesy of a blog post over at <a href="http://www.visnup.com/entries/423-cobravsmongoose-not-slow-vs-hashfrom_xml-slow-vs-faster_xml_simple-fast">cobravsmongoose</a>, we have a libxml drop-in for <code>Hash#from_xml</code></p>
<p>First, install <a href="http://libxml.rubyforge.org/">libxml</a> and then <a href="http://code.google.com/p/faster-xml-simple/">faster_xml_simple</a>.</p>
<p>Second, include a monkeypatch to <code>Hash#from_xml</code> with the following:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'faster_xml_simple'
class Hash
  def self.from_xml(xml)
    undasherize_keys(typecast_xml_value(FasterXmlSimple.xml_in(xml,
      'forcearray'   =&gt; false,
      'forcecontent' =&gt; true,
      'keeproot'     =&gt; true,
      'contentkey'   =&gt; '__content__')
    ))
  end
end
</pre>
<p>You can run the benchmarks if you&#8217;d like, but it&#8217;s orders of magnitude faster than REXML. Seriously. Don&#8217;t use REXML. It&#8217;s like trying to run a Ferrari off of a 9-volt battery.</p>
<p>Now, let&#8217;s say you have an action you want to provide HTML, XML, JSON, and YAML views for.</p>
<pre class="brush: ruby; title: ; notranslate">
def index
  ...
  respond_to do |wants|
    wants.html
    wants.xml  { render :layout =&gt; false }
    wants.json { render :to_json =&gt; &quot;posts/index.xml.builder&quot; }
    wants.yaml { render :to_yaml =&gt; &quot;posts/index.xml.builder&quot; }
  end
end
</pre>
<p>Finally, throw together your <code>index.xml.builder</code> file as you best see fit.</p>
<pre class="brush: ruby; title: ; notranslate">
xml.instruct! :xml, :version=&gt;&quot;1.0&quot;, :encoding=&gt;&quot;UTF-8&quot;
xml.posts do
  @posts.each do |post|
    xml.post(:id =&gt; post.id) do
      xml.user(:id =&gt; post.user.id) +
      xml.content do
        post.post_body
      end
    end
  end
end
</pre>
<p>And all of a sudden, bam! You&#8217;ve got your posts available in HTML&#8230;</p>
<pre><code>/posts/index</code></pre>
<p>&#8230;and in XML, YAML, and JSON, along with the associated User. By using an XML builder, you can make the serialized data as complex and customized as you&#8217;d like. No more funky respond_to blocks, no more exposing data you don&#8217;t want to. Expose what you want, and just what you want, in several formats.</p>
<pre><code>
/posts/index.xml
/posts/index.yml
/posts/index.json
</code></pre>
<p>One final trick is that the JSON views accept an optional <code>callback</code> or <code>jsonp</code> parameter, which will cause the content to be passed to a Javascript function matching the passed parameter, as per the <a href="http://ajaxian.com/archives/jsonp-json-with-padding">JSONP</a> spec.</p>
<p>For example, if you have a <code>/foo/bar.json</code> view that would render the following JSON:</p>
<pre><code>"{\"foo\":\"bar\"}"</code></pre>
<p>Calling <code>/foo/bar.json?jsonp=returnFunc</code> would return the following:</p>
<pre><code>returnFunc("{\"foo\":\"bar\"}")</code></pre>
<p>Check out the <a href="http://ajaxian.com/archives/jsonp-json-with-padding">JSONP</a> spec for more.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2008/09/27/powerful-easy-dry-multi-format-rest-apis/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Stupid attachment_fu tricks, part 1</title>
		<link>http://www.coffeepowered.net/2008/09/25/stupid-attachment_fu-tricks-part-1/</link>
		<comments>http://www.coffeepowered.net/2008/09/25/stupid-attachment_fu-tricks-part-1/#comments</comments>
		<pubDate>Thu, 25 Sep 2008 23:16:23 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[attachment_fu]]></category>
		<category><![CDATA[imagemagick]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=27</guid>
		<description><![CDATA[attachment_fu is fantastic, but it&#8217;s a bit limited for some purposes. Ever wanted to upload data from a URL instead of making people upload files? It&#8217;s a common problem! Presume that we have a model named Image, which is our target for attachment_fu. Adding URL upload capability is surprisingly simple: There you go. All you [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://svn.techno-weenie.net/projects/plugins/attachment_fu/">attachment_fu</a> is fantastic, but it&#8217;s a bit limited for some purposes. Ever wanted to upload data from a URL instead of making people upload files? It&#8217;s a common problem!</p>
<p>Presume that we have a model named Image, which is our target for attachment_fu. Adding URL upload capability is surprisingly simple:</p>
<pre class="brush: ruby; title: ; notranslate">
class Image &lt; ActiveRecord::Base

	# Standard attachment_fu inclusion here
	has_attachment :storage =&gt; :file_system,
		:content_type =&gt; :image,
		:resize_to =&gt; &quot;1024x1024&gt;&quot;,
		:path_prefix =&gt; &quot;public/images/cache/attached&quot;,
		:format =&gt; &quot;jpg&quot;

	# Allows the direct assignment of a URL to this image, which is the source image to save from
	def url=(v)
		self.uploaded_data = UrlUpload.new(v)
	end

	# Or, we can just pass a URL to Image#uploaded_data
	def uploaded_data=(filedata_or_url)
		if filedata_or_url.is_a? String and filedata_or_url.match /^http(s)?:\/\// then
			file = open(filedata_or_url)
			file.extend(UrlUpload)
			super(file)
		else
			super(filedata_or_url)
		end
	end
end

module UrlUpload
	def filename
		base_uri.to_s.split(&quot;/&quot;).last
	end

	def original_filename
		base_uri.to_s.split(&quot;/&quot;).last
	end
end
</pre>
<p>There you go. All you need now is <code>Image.create(:url => "http://some.url/to/an/image.png")</code> and when the model is saved, the image will be sucked down and saved. Easy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2008/09/25/stupid-attachment_fu-tricks-part-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Jabberish: making Rails talk back</title>
		<link>http://www.coffeepowered.net/2008/09/25/jabberish-making-rails-talk-back/</link>
		<comments>http://www.coffeepowered.net/2008/09/25/jabberish-making-rails-talk-back/#comments</comments>
		<pubDate>Thu, 25 Sep 2008 11:45:49 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[drb]]></category>
		<category><![CDATA[google talk]]></category>
		<category><![CDATA[jabber]]></category>
		<category><![CDATA[xmpp]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=19</guid>
		<description><![CDATA[Ever wanted to do IM from Rails? xmpp4r-simple makes it really easy to talk to Jabber clients (such as Google Talk users) from Ruby, but it&#8217;s not quite a cut-and-dried solution for your Rails apps. Fortunately, there&#8217;s Jabberish. Jabberish is a DRb-backed Jabber client designed for use in multi-server Rails apps. Just drop in the [...]]]></description>
			<content:encoded><![CDATA[<p>Ever wanted to do IM from Rails? <a href="http://code.google.com/p/xmpp4r-simple/">xmpp4r-simple</a> makes it really easy to talk to Jabber clients (such as <a href="http://www.google.com/talk/">Google Talk</a> users) from Ruby, but it&#8217;s not quite a cut-and-dried solution for your Rails apps. Fortunately, there&#8217;s <a href="http://github.com/cheald/jabberish/tree/master">Jabberish</a>.</p>
<p>Jabberish is a DRb-backed Jabber client designed for use in multi-server Rails apps. Just drop in the plugin, configure, start the daemon, and off you go.</p>
<p>Installation is painless, as you&#8217;d expect.</p>
<pre><code> script/plugin install git://github.com/cheald/jabberish.git</code></pre>
<p>Jabberish calls in your code will fail silently if the Jabberish DRb process isn&#8217;t running, so if the daemon goes missing, it won&#8217;t bring your app crashing down around your shoulders &#8211; you just won&#8217;t get IMs.</p>
<p>Once it&#8217;s installed, it&#8217;s very easy to get it up and running.</p>
<ol>
<li>Pop open <code>config/jabberish.yml</code> and set your preferences as you best see fit.</li>
<li>run <code>rake jabberish:start</code> &#8211; this will start up your DRb daemon, and connect to your configured account to your Jabber network</li>
<li>Call Jabberish from your code!</li>
</ol>
<pre class="brush: ruby; title: ; notranslate">
JabberishAgent.deliver(&quot;your-email@gmail.com&quot;, &quot;Hi there!&quot;)
</pre>
<p>There are many potential applications. For example, to send yourself IMs when your app has an error, in application.rb:</p>
<pre class="brush: ruby; title: ; notranslate">
def rescue_action(e)
  # The third parameter is &quot;throttle&quot;, which will cause Jabberish to refuse
  # to send the same message to a given recipient twice in a row
  msg = sprintf(&quot;[#%s] %s (%s)&quot;, Time.now.to_i, e, e.backtrace.first)
  JabberishAgent.deliver(&quot;your-email@gmail.com&quot;, msg, true)
end
</pre>
<p>And lickety split, you&#8217;re IMing error reports to yourself in realtime. I&#8217;m sure others will find much more interesting things to do with it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2008/09/25/jabberish-making-rails-talk-back/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>site_config &#8211; painless custom configuration for your Rails project</title>
		<link>http://www.coffeepowered.net/2008/09/25/site_config-painless-config-variables-for-rails-projects/</link>
		<comments>http://www.coffeepowered.net/2008/09/25/site_config-painless-config-variables-for-rails-projects/#comments</comments>
		<pubDate>Thu, 25 Sep 2008 11:31:59 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=14</guid>
		<description><![CDATA[site_config is a little plugin that addresses a problem lots of people seem to need to solve in their Rails apps: per-environment configuration variables. It&#8217;s very simple, but makes configuration dead-easy. To install it: script/plugin install git://github.com/cheald/site_config.git Once you have it installed, check out config/site_config.yml &#8211; there&#8217;s your config file. You&#8217;ll notice that it has [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://github.com/cheald/site_config/tree/master">site_config</a> is a little plugin that addresses a problem lots of people seem to need to solve in their Rails apps: per-environment configuration variables.</p>
<p>It&#8217;s very simple, but makes configuration dead-easy. To install it:</p>
<pre><code>script/plugin install git://github.com/cheald/site_config.git</code></pre>
<p>Once you have it installed, check out <code>config/site_config.yml</code> &#8211; there&#8217;s your config file.</p>
<p>You&#8217;ll notice that it has some dummy data in there to begin with. It&#8217;s much like your <code>database.yml</code> file; just specify the environment, and under that, specify the key:value pairs you want to have available in your app. site_config has one little trick up its sleeve, though &#8211; the key &#8220;inherit&#8221; is special, and tells it to pull values from another environment. This helps you DRY up your configs, and makes it quite easy to maintain.</p>
<p>For example, if you had the following <code>site_config.yml</code>:</p>
<pre class="brush: ruby; title: ; notranslate">
development:
  page_title: &quot;my development site&quot;
  admin_user: chris

production:
  inherit: development
  page_title: &quot;my production site&quot;
</pre>
<p>You can then use those configured values in your site like so:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;title&gt;&lt;%=config_option :page_title %&gt;&lt;/title&gt;
Your friendly admin is &lt;%=config_option :admin_user %&gt;
</pre>
<p>site_config will pull values defined for your current environment. If you don&#8217;t have a value defined for a given environment, but do have an <code>inherit</code> defined, site_config will then look to the inherited config to pull values from.</p>
<p>Additionally, if you want a value from a specific environment, <code>config_option</code> accepts a second parameter, which specifies the environment to pull from.</p>
<pre class="brush: ruby; title: ; notranslate">
config_option :page_title, :development
</pre>
<p>There&#8217;s more at the github page. Check it out.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2008/09/25/site_config-painless-config-variables-for-rails-projects/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

