<?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; yaml</title>
	<atom:link href="http://www.coffeepowered.net/tag/yaml/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 Cookie Sessions and PHP</title>
		<link>http://www.coffeepowered.net/2011/08/24/rails-cookie-sessions-and-php/</link>
		<comments>http://www.coffeepowered.net/2011/08/24/rails-cookie-sessions-and-php/#comments</comments>
		<pubDate>Wed, 24 Aug 2011 23:56:25 +0000</pubDate>
		<dc:creator>Chris Heald</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[yaml]]></category>

		<guid isPermaLink="false">http://www.coffeepowered.net/?p=470</guid>
		<description><![CDATA[I recently found myself needing to share session data from my Rails app with a PHP app on the same domain. We use cookie sessions for a number of reasons, and while they work great, the data stored in them is stored in Ruby&#8217;s native Marshal format, which is not trivial to reimplement in PHP. [...]]]></description>
			<content:encoded><![CDATA[<p>I recently found myself needing to share session data from my Rails app with a PHP app on the same domain. We use cookie sessions for a number of reasons, and while they work great, the data stored in them is stored in Ruby&#8217;s native Marshal format, which is not trivial to reimplement in PHP. After trying to get the data unmarshaled for a bit, I had another idea &#8211; why not just change the storage format?</p>
<p>Fortunately, Ruby is deeply entangled with another more portable serialization format: YAML.</p>
<p>Rails manages its session cookies through the <a href="https://github.com/rails/rails/blob/2-3-stable/activesupport/lib/active_support/message_verifier.rb">MessageVerifier</a>. Easy enough &#8211; we can just write our own MessageVerifier that uses YAML rather than Marshal.</p>
<pre class="brush: ruby; title: ; notranslate">

module ActiveSupport
  class YamlMessageVerifier &lt; MessageVerifier
    def verify(signed_message)
      raise InvalidSignature if signed_message.blank?

      data, digest = signed_message.split(&quot;--&quot;)
      if data.present? &amp;&amp; digest.present? &amp;&amp; secure_compare(digest, generate_digest(data))
        str = ActiveSupport::Base64.decode64(data)
        if str[0..2] == '---'
          YAML::load str
        else # Handle old Marshal.dump'd session
          Marshal.load(str)
        end
      else
        raise InvalidSignature
      end
    end

    def generate(value)
      data = ActiveSupport::Base64.encode64s(YAML::dump value)
      &quot;#{data}--#{generate_digest(data)}&quot;
    end
  end
end
</pre>
<p>You&#8217;ll notice that verify() can accept a Marshaled session as well; this lets you transparently transition existing cookies to the new format without any kind of session breakage. Nice.</p>
<p>Now, to use the verifier, we monkeypatch CookieStore:</p>
<pre class="brush: ruby; title: ; notranslate">
module ActionController
  module Session
    class CookieStore
      def verifier_for(secret, digest)
        key = secret.respond_to?(:call) ? secret.call : secret
        ActiveSupport::YamlMessageVerifier.new(key, digest)
      end
    end
  end
end
</pre>
<p>Now, this will work&#8230;at least at first glance, until you try to use the flash. This is a particularly nasty little problem, and it stems from the fact that Ruby&#8217;s YAML implementation serializes Hash objects without their instance variables, and <a href="https://github.com/rails/rails/blob/2-3-stable/actionpack/lib/action_controller/flash.rb">FlashHash</a> inherits from Hash, and thus inherits its serialization/deserialization strategy. I worked for a while to monkeypatch those strategies, but I didn&#8217;t like the result, and it felt a little hacky. Instead, I just took advantage of the YAML load lifecycle to make sure the FlashHash initializes properly:</p>
<pre class="brush: ruby; title: ; notranslate">
module ActionController
  module Flash
    class FlashHash
      def update_with_initializer(h)
        @used ||= {}
        update_without_initializer(h)
      end
      alias_method_chain :update, :initializer
    end
  end
end
</pre>
<p>The core problem is that <code>YAML::load</code> calls <code>Hash#update</code>, and <code>FlashHash</code> presumes that the <code>@used</code> instance variable is present and initialized to an empty hash. To fix that, I just aliased in an initializer to make sure that variable is set.</p>
<p>Note that if you are storing other Hash subclasses with instance variables that rely on those variables being persisted across sessions, they will break. However, you should only be storing primitive/array/hash data in the session if possible. FlashHash is sort of a nasty violation of this principle.</p>
<p>At this point, your session should be serializing to and from YAML. We&#8217;ll want to read it from PHP, naturally. I&#8217;m using <a href="http://code.google.com/p/spyc/">SPYC</a> in the PHP project, which gets us Close Enough(TM). It doesn&#8217;t handle symbol keys, but we&#8217;ll handle those in the PHP itself.</p>
<h2>Reading from PHP</h2>
<p>Reading the data back out is surprisingly simple. We have to verify the authenticity of the data, of course, by checking the hash, but then you just base64 decode the data, load it with spyc, and perform some simple transformation to turn symbols into strings. If you wanted to make it even easier, you could monkeypatch the cookie store to call <code>#stringify_keys!</code> on your session hash before serializing it (and then call <code>#with_indifferent_access</code> on the hash when you deserialize it. Be aware of the speed impact of such a decision before you do it.)</p>
<pre class="brush: php; title: ; notranslate">
function explode_symbols($arr) {
  $result = array();
  foreach($arr as $key =&gt; $val) {
    if(is_numeric($key) &amp;&amp; $val[0] == &quot;:&quot;) {
      $bits = explode(&quot;:&quot;, $val, 3);
      $result[trim($bits[1])] = trim($bits[2]);
    } elseif (is_array($val)) {
      $result[$key] = explode_symbols($val);
    } else {
      $result[$key] = $val;
    }
  }
  return $result;
}

function deserialize_session($session_key, $secret) {
  list($session64, $hash) = explode(&quot;--&quot;, $_COOKIE[$session_key], 2);
  if(hash_hmac(&quot;SHA1&quot;, $session64, $secret) == $hash) {
    $session = base64_decode($session64);
    return explode_symbols(spyc_load($session));
  } else {
    throw new Exception(&quot;Invalid session signature&quot;);
  }
}

$rails_session = deserialize_session(&quot;your_session_cookie_name&quot;, $your_session_cookie_secret);
</pre>
<h2>Caveats</h2>
<ul>
<li>Be aware that YAML is slower than Marshal</li>
<li>Be aware that storing Hash subclasses in the session is likely going to Not Work.</li>
</ul>
<p>And that&#8217;s all there is to it. You can now share data between the two apps via the session cookie.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.coffeepowered.net/2011/08/24/rails-cookie-sessions-and-php/feed/</wfw:commentRss>
		<slash:comments>0</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>
	</channel>
</rss>

