<?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>kueda.net &#187; ruby</title>
	<atom:link href="http://kueda.net/blog/tag/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://kueda.net</link>
	<description>I'm Back</description>
	<lastBuildDate>Thu, 02 Feb 2012 19:42:04 +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>Active Record Model Adapters</title>
		<link>http://kueda.net/blog/2008/09/09/active-record-model-adapters/</link>
		<comments>http://kueda.net/blog/2008/09/09/active-record-model-adapters/#comments</comments>
		<pubDate>Tue, 09 Sep 2008 22:32:25 +0000</pubDate>
		<dc:creator>Ken-ichi</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[designpatterns]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://kueda.net/?p=208</guid>
		<description><![CDATA[I recently refactored some code in iNaturalist that fetches taxon names from external name providers like uBio and the Catalogue of Life. They return names and classification data that are similar but (of course) not identical to ActiveRecord models we use in iNat, so I figured I&#8217;d write adapters for them, and I thought a [...]]]></description>
			<content:encoded><![CDATA[<p>I recently refactored some code in <a href="http://inaturalist.org">iNaturalist</a> that fetches taxon names from external name providers like <a href="http://ubio.org">uBio</a> and the <a href="http://catalogueoflife.org">Catalogue of Life</a>.  They return names and classification data that are similar but (of course) not identical to ActiveRecord models we use in iNat, so I figured I&#8217;d write adapters for them, and I thought a really smart solution would be to subclass the models themselves, simply overriding the attributes with getters that mined a private instance variable holding an XML response from one of the web services.  Big mistake.  ActiveRecord mixes in all kinds of magic into the models that doesn&#8217;t necessarily get passed on to child classes.  I ran into all sorts of fun errors and problems until I remembered the Adapter implementation described <a href="http://www.scribd.com/doc/396559/gof-patterns-in-ruby">here</a>, which takes a much more sensible approach: don&#8217;t sublcass, and instead hold an internal copy of the adaptee, passing calls to anything you don&#8217;t want to override to the adaptee.</p>
<p><span id="more-208"></span>The only real &#8220;gotcha&#8221; is that <code>ActiveRecord::Base</code> overrides some of <code>Object</code>&#8216;s methods, so you need to delegate those to the adaptee as well.  I just delegated them all, though there may be some unforeseen consequences in this, I don&#8217;t know.</p>
<p>Anyway, here&#8217;s my solution: a model adapter module:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#008000; font-style:italic;">#</span>
<span style="color:#008000; font-style:italic;"># Module for ActiveRecord model adapters.</span>
<span style="color:#008000; font-style:italic;">#</span>
<span style="color:#008000; font-style:italic;"># Usage:</span>
<span style="color:#008000; font-style:italic;">#   class YourModelAdapter</span>
<span style="color:#008000; font-style:italic;">#     include ModelAdapter</span>
<span style="color:#008000; font-style:italic;">#     alias :your_model :adaptee # optional</span>
<span style="color:#008000; font-style:italic;">#     </span>
<span style="color:#008000; font-style:italic;">#     def initialize</span>
<span style="color:#008000; font-style:italic;">#       @adaptee = YourModel.new # required!</span>
<span style="color:#008000; font-style:italic;">#     end</span>
<span style="color:#008000; font-style:italic;">#     </span>
<span style="color:#008000; font-style:italic;">#     def some_attribute</span>
<span style="color:#008000; font-style:italic;">#       do_something_different</span>
<span style="color:#008000; font-style:italic;">#     end</span>
<span style="color:#008000; font-style:italic;">#   end</span>
<span style="color:#008000; font-style:italic;">#</span>
<span style="color:#9966CC; font-weight:bold;">module</span> ModelAdapter
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:adaptee</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> method_missing<span style="color:#006600; font-weight:bold;">&#40;</span>method, <span style="color:#006600; font-weight:bold;">*</span>args<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#0066ff; font-weight:bold;">@adaptee</span>.<span style="color:#9900CC;">respond_to</span>? method
      <span style="color:#0066ff; font-weight:bold;">@adaptee</span>.<span style="color:#9900CC;">send</span><span style="color:#006600; font-weight:bold;">&#40;</span>method, <span style="color:#006600; font-weight:bold;">*</span>args<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">else</span>
      <span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#CC00FF; font-weight:bold;">NoMethodError</span>, <span style="color:#996600;">&quot;#{self.class} hasn't implemented #{method}&quot;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># Redirect calls to public methods in Object to the adaptee</span>
  <span style="color:#CC00FF; font-weight:bold;">Object</span>.<span style="color:#9900CC;">methods</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>method_name<span style="color:#006600; font-weight:bold;">|</span>
    define_method<span style="color:#006600; font-weight:bold;">&#40;</span>method_name.<span style="color:#9900CC;">to_sym</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|*</span>args<span style="color:#006600; font-weight:bold;">|</span>
      <span style="color:#0066ff; font-weight:bold;">@adaptee</span>.<span style="color:#9900CC;">send</span><span style="color:#006600; font-weight:bold;">&#40;</span>method_name.<span style="color:#9900CC;">to_sym</span>, <span style="color:#006600; font-weight:bold;">*</span>args<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://kueda.net/blog/2008/09/09/active-record-model-adapters/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

