Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering deep associations in Rails' to_xml

I've got a Person object that has_many roles. Roles, in turn, belong_to application. I'm using the following piece of code to render this deep relationship into XML:

format.xml { render :text => @person.to_xml( :include => { :roles => { :include => :application } } ) }

Rendering out something like this:

<person>
  <email>****@****.edu</email>
  <first>Christopher</first>
  <last>****</last>
  <loginid>****</loginid>
  <roles type="array">
    <role>
      <application-id type="integer">3</application-id>
      <name>Access</name>
      <application>
        <name>****</name>
      </application>
    </role>
    <role>
      <application-id type="integer">2</application-id>
      <name>Create Ballots</name>
      <application>
        <name>****</name>
      </application>
    </role>
  </roles>
</person>

This works, however, I'd like to filter which applications and roles it shows. I'd like to only show roles (and thus, nested within them, applications) where the application_id is a certain integer. E.g., the following output if I was looking for only application_id == 3:

<person>
  <email>****@****.edu</email>
  <first>Christopher</first>
  <last>****</last>
  <loginid>****</loginid>
  <roles type="array">
    <role>
      <application-id type="integer">3</application-id>
      <name>Access</name>
      <application>
        <name>****</name>
      </application>
    </role>
  </roles>
</person>

Thanks in advance for any help you can offer.

like image 429
Christopher Avatar asked Aug 04 '11 22:08

Christopher


1 Answers

Maybe one way to do it would be to override your role to_xml method. It would look like the following (approximatively):

in your Role model:

def to_xml(options={})
    if application.id != 3
      options[:indent] ||= 2
      xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
      xml.instruct! unless options[:skip_instruct]
      xml.role do
        # role_application is the application linked to you role..
        role_application = applications.select {|a| a.id == 3}
        xml.application_id role_applications.id
        xml.name role_application.name
        xml.application do
          xml.name role_application.name
        end
      end
  else
   # return nothing
   return ""
  end
end

end

and you would call it like this:

format.xml { render :text => @person.to_xml( :include => { :roles => {} } )

(look at the documentation at the end of this page)

like image 161
alex Avatar answered Oct 07 '22 06:10

alex