STI, acts_as_tree, and xml_response_from

More Land Brokr/NCRE integration means more xml_response_fromhackery. This one involves the message center.

NCRE messages are STI trees. That is:

class Message < ActiveRecord::Base
  acts_as_tree :order => 'created_at DESC'
end

class PurchaseMessage < Message
  def summary
    "blah blah"
  end
end

class OpenHouseMessage < Message
  def summary
    "blah blah"
  end
end

So the code to send a message thread over XML is:

class MessagesController < ActionController::Base
  def show_thread
    @thread = Message.find(params[:id]).root
    respond_to do |wants|
      wants.html
      wants.xml { render :xml => @thread.to_xml(:include => [:children]) }
    end
  end
end

Which sends, for example, this XML:

<?xml version="1.0" encoding="UTF-8"?>
<purchase-message>
  <children>
    <child>
      <replied-to></replied-to>
      <body></body>
      <folder>messages</folder>
      <type>PurchaseMessage</type>
      <read type="datetime">2006-06-01T15:47:35-04:00</read>
      <subject></subject>
      <recipient-id type="integer">1</recipient-id>
      <id type="integer">108</id>
      <sender-id type="integer">6</sender-id>
      <parent-id type="integer">107</parent-id>
      <created-at type="datetime">2006-06-01T15:46:44-04:00</created-at>
    </child>
  </children>
  <replied-to type="datetime">2006-06-01T15:46:47-04:00</replied-to>
  <body></body>
  <folder>messages</folder>
  <type>PurchaseMessage</type>
  <read type="datetime">2006-06-01T15:45:45-04:00</read>
  <subject></subject>
  <recipient-id type="integer">6</recipient-id>
  <id type="integer">107</id>
  <sender-id type="integer">1</sender-id>
  <parent-id></parent-id>
  <created-at type="datetime">2006-06-01T15:45:08-04:00</created-at>
</purchase-message>

The ‘children’ and ‘child’ elements are the interesting part. Okay, cool, so it sent the whole thread, including any children. But now on Land Brokr I need to turn the children into the correct object, based on their type.

Here’s what I ended up writing on the Land Brokr side:

class MessageFactory
  def self.new(h)
    if h[:type]
      h[:type].constantize.new(h)
    else
      Message.new(h)
    end
  end
end

class Message
  attr :body, true
  # and so on, for the other attributes
  attr :children, true

def initialize(h)
    @children = []
    h.each { |k,v| send("#{k}=", v) }
  end

def purchase_message=(m)
    @children << m[0]
  end

def open_house_message=(m)
    @children << m[0]
  end

def find(id)
    xml_response_from("http://myncre.com/messages/show_thread/#{id}",
        { :child => MessageFactory })
  end
end

Which means now I can do Message.find(165) and get back the whole thread.

Advertisements

2 Comments

  1. Posted June 27, 2006 at 9:05 pm | Permalink

    Yeah, thanks for removing my indentation, WordPress. Jerks.

    Update: Yeah, it works now. Okay. Next time WordPress should stop being so dang “smart”.

  2. Posted October 29, 2010 at 10:31 am | Permalink

    Сызнова действительно побочная вопрос) Врят ли она кому то мешает, мне например ровно то пофиг


%d bloggers like this: