Rendering User attributes in XML

Neil Cauldwell wrote:

Let's say an app has a User, and a User has many friends. Also, let's
say the app authentication was built on the restful_authentication
plugin, and we have email and password in the Users table. The friends
controller index might look like this;

# GET /users/1/friends
# GET /users/1/friends.xml
def index
  @users = @user.friends

  respond_to do |format|
    format.html
    format.xml { render :xml => @friends }
  end
end

If the app needs to show all of a users friends in the XML output, what
is the best practice for handling the User model attributes that are
formatted in XML whilst not rendering sensitive attributes like email
and password? Does the app need a custom XML template for this? Or is
there a convenient way to not show the account credentials of the User
model when we're shoving them in to the XML output?

No thoughts on this one? It sounds like something that any app with RA
based authentication & user record XML outputs would encounter. Someone
I've been working with suggested I take a look at this;

http://code.google.com/p/custom-xml-serialization/wiki/Overview

But seeings as there's been no updates since last year, I was thinking
that maybe there's something in Rails which I just don't know about.

the to_xml method takes a bunch of options, including :only
and :except which allow you to exclude attributes.

Fred

Frederick Cheung wrote:

> there a convenient way to not show the account credentials of the User
> model when we're shoving them in to the XML output?

No thoughts on this one? It sounds like something that any app with RA
based authentication & user record XML outputs would encounter. Someone
I've been working with suggested I take a look at this;

the to_xml method takes a bunch of options, including :only
and :except which allow you to exclude attributes.

Fred

Thanks Fred. I've come across the to_xml before, I just can't work out
how to use it in conjunction with the format.xml helper;

    respond_to do |format|
      format.html # index.html.erb
      format.xml { @users.to_xml :except => [:email] }
    end

(That tells me I need a template)

    respond_to do |format|
      format.html # index.html.erb
      format.xml { render :xml => @users.to_xml, :except => :email }
    end

(And so does that)

By the looks of it, it would be cleaner to specify which attributes (the
ones we don't want to show) in the User.rb. Does Rails have this built
in?

Frederick Cheung wrote:

>> > there a convenient way to not show the account credentials of the User
>> > model when we're shoving them in to the XML output?

>> No thoughts on this one? It sounds like something that any app with RA
>> based authentication & user record XML outputs would encounter. Someone
>> I've been working with suggested I take a look at this;

> the to_xml method takes a bunch of options, including :only
> and :except which allow you to exclude attributes.

> Fred

Thanks Fred. I've come across the to_xml before, I just can't work out
how to use it in conjunction with the format.xml helper;

respond\_to do |format|
  format\.html \# index\.html\.erb
  format\.xml  \{ @users\.to\_xml :except => \[:email\] \}
end

(That tells me I need a template)

respond\_to do |format|
  format\.html \# index\.html\.erb
  format\.xml  \{ render :xml => @users\.to\_xml, :except => :email \}
end

nearly - render :xml => @users.to_xml(:except => :email) should do it.

(And so does that)

By the looks of it, it would be cleaner to specify which attributes (the
ones we don't want to show) in the User.rb. Does Rails have this built
in?

I imagine you could change the defaults by overriding to_xml in your
model. It probably wouldn't be too hard to write this so that you
could do

class User < ActiveRecord::Base
  exclude_from_xml :email, :password
end

Fred

Frederick Cheung wrote:

� � � format.xml �{ @users.to_xml :except => [:email] }
� � end

(That tells me I need a template)

� � respond_to do |format|
� � � format.html # index.html.erb
� � � format.xml �{ render :xml => @users.to_xml, :except => :email }
� � end

nearly - render :xml => @users.to_xml(:except => :email) should do it.

(And so does that)

By the looks of it, it would be cleaner to specify which attributes (the
ones we don't want to show) in the User.rb. Does Rails have this built
in?

I imagine you could change the defaults by overriding to_xml in your
model. It probably wouldn't be too hard to write this so that you
could do

class User < ActiveRecord::Base
  exclude_from_xml :email, :password
end

Fred

Thanks Fred, the first method works a treat but, I just realised I have
15 attributes I need to hide away. My format.xml helper looks like
Pinocchios nose.

The model would be the way to go, and the API suggests it is easy to do;
http://docs.huihoo.com/api/ruby-on-rails/classes/ActiveRecord/XmlSerialization.html

...I just can't work out how to simply exclude certain attributes; I
haven't touched AR internals before so nothing within the def to_xml
makes any sense. Not that that is stopping me from allowing myself 10
minutes of trial & error though!

You could make an array

exclusions = [:email, :some_attr, :other_attr, …]

and use it instead of specifying all the exclusions inline

format.xml { render :xml => @users.to_xml, :except => exclusions }

since the docs indicate that you can use an array as the value for :except.

Regards,
Craig

Craig Demyanovich wrote:

You could make an array

exclusions = [:email, :some_attr, :other_attr, ...]

and use it instead of specifying all the exclusions inline

format.xml { render :xml => @users.to_xml, :except => exclusions }

since the docs indicate that you can use an array as the value for
:except.

Regards,
Craig

Thanks Craig. Are you saying (?);

def to_xml(options = {})
exclusions = [:email, :some_attr, :other_attr, ...]
end

And in my controller;

format.xml { render :xml => @users.to_xml, :except => exclusions }

Or is it simpler than that?

Thanks Craig. Are you saying (?);

def to_xml(options = {})
exclusions = [:email, :some_attr, :other_attr, …]

end

And in my controller;

format.xml { render :xml => @users.to_xml, :except => exclusions }

Or is it simpler than that?

I’m suggesting

respond_to do |format|

format.xml do
exclusions = [ … ]
render :xml => @users.to_xml, :except => exclusions

end
end

simply as another way to accomplish what you want while striving for something that may be more readable than specifying all of the exclusions inline.

Regards,
Craig

Craig Demyanovich wrote:

Or is it simpler than that?

I'm suggesting

respond_to do |format|
  ...
  format.xml do
    exclusions = [ ... ]
    render :xml => @users.to_xml, :except => exclusions
  end
end

simply as another way to accomplish what you want while striving for
something that may be more readable than specifying all of the
exclusions
inline.

Regards,
Craig

Thanks again, I was hoping I could specify the exclusions in the
User.rb. Is there any reason I couldn't do that? There's 5 or 6
controllers in which I'll need the exclusions.

You could override to_xml like this if you’ll need the custom XML everywhere:

class User < ActiveRecord::Base

you can choose a better name than ar_to_xml, of course

alias_method :ar_to_xml, :to_xml
def to_xml(options = {}, &blk)
# update this list with the attrs that you want to exclude or create the array elsewhere in the class and use it here
default_except = [:created_at, :updated_at]

options[:except] = (options[:except] ? options[:except] + default_except : default_except)
ar_to_xml(options, &blk)

end
end

If you won’t need the custom XML everywhere, you can remember to call User.ar_to_xml (or whatever you name it), or you could create a class that composes a User and does the custom formatting.

Regards,
Craig

By the way, this page was the inspiration for my last reply:

http://ryandaigle.com/articles/2007/4/13/what-s-new-in-edge-rails-a-more-flexible-to_xml

Craig Demyanovich wrote:

By the way, this page was the inspiration for my last reply:

http://ryandaigle.com/articles/2007/4/13/what-s-new-in-edge-rails-a-more-flexible-to_xml

On Sat, Aug 30, 2008 at 11:42 AM, Craig Demyanovich

Cool. I'm doing this;

  alias_method :ar_to_xml, :to_xml
  def to_xml(options = {})
    default_except = [:activated_at, :activation_code ....]
    options[:except] = (options[:except] ? options[:except] +
default_except : default_except)
    ar_to_xml(options)
  end

It works like a charm.