mirror of
https://github.com/github/rails.git
synced 2026-02-10 06:04:55 -05:00
Added association inclusion in to_xml [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3831 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
@@ -36,6 +36,33 @@
|
||||
<parent-id></parent-id>
|
||||
<last-read type="date">2004-04-15</last-read>
|
||||
</topic>
|
||||
|
||||
You can even do load first-level associations as part of the document:
|
||||
|
||||
firm.to_xml :include => [ :account, :clients ]
|
||||
|
||||
...that'll return something like:
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<firm>
|
||||
<id type="integer">1</id>
|
||||
<rating type="integer">1</rating>
|
||||
<name>37signals</name>
|
||||
<clients>
|
||||
<client>
|
||||
<rating type="integer">1</rating>
|
||||
<name>Summit</name>
|
||||
</client>
|
||||
<client>
|
||||
<rating type="integer">1</rating>
|
||||
<name>Microsoft</name>
|
||||
</client>
|
||||
</clients>
|
||||
<account>
|
||||
<id type="integer">1</id>
|
||||
<credit-limit type="integer">50</credit-limit>
|
||||
</account>
|
||||
</firm>
|
||||
|
||||
* Allow :counter_cache to take a column name for custom counter cache columns [Jamis Buck]
|
||||
|
||||
|
||||
@@ -1418,8 +1418,24 @@ module ActiveRecord #:nodoc:
|
||||
|
||||
|
||||
# Returns a hash of all the attributes with their names as keys and clones of their objects as values.
|
||||
def attributes
|
||||
clone_attributes :read_attribute
|
||||
def attributes(options = nil)
|
||||
attributes = clone_attributes :read_attribute
|
||||
|
||||
if options.nil?
|
||||
attributes
|
||||
else
|
||||
if except = options[:except]
|
||||
except = Array(except).collect { |attribute| attribute.to_s }
|
||||
except.each { |attribute_name| attributes.delete(attribute_name) }
|
||||
attributes
|
||||
elsif only = options[:only]
|
||||
only = Array(only).collect { |attribute| attribute.to_s }
|
||||
attributes.delete_if { |key, value| !only.include?(key) }
|
||||
attributes
|
||||
else
|
||||
raise ArgumentError, "Options does not specify :except or :only (#{options.keys.inspect})"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a hash of cloned attributes before typecasting and deserialization.
|
||||
@@ -1506,16 +1522,31 @@ module ActiveRecord #:nodoc:
|
||||
|
||||
# Turns this record into XML
|
||||
def to_xml(options = {})
|
||||
options[:skip_attributes] = Array(options[:skip_attributes])
|
||||
options[:skip_attributes] << :type
|
||||
options[:skip_attributes].collect! { |attribute| attribute.to_s }
|
||||
|
||||
attributes_to_be_xmled = attributes
|
||||
options[:skip_attributes].each { |attribute_name| attributes_to_be_xmled.delete(attribute_name) }
|
||||
|
||||
options[:root] ||= self.class.to_s.underscore
|
||||
options[:except] = Array(options[:except]) << self.class.inheritance_column unless options[:only]
|
||||
only_or_except = { :only => options[:only], :except => options[:except] }
|
||||
|
||||
attributes_to_be_xmled.to_xml(options)
|
||||
attributes_for_xml = attributes(only_or_except)
|
||||
|
||||
if include_associations = options.delete(:include)
|
||||
for association in Array(include_associations)
|
||||
case self.class.reflect_on_association(association).macro
|
||||
when :has_many, :has_and_belongs_to_many
|
||||
records = send(association).to_a
|
||||
unless records.empty?
|
||||
attributes_for_xml[association] = records.collect do |record|
|
||||
record.attributes(only_or_except)
|
||||
end
|
||||
end
|
||||
when :has_one, :belongs_to
|
||||
if record = send(association)
|
||||
attributes_for_xml[association] = record.attributes(only_or_except)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attributes_for_xml.to_xml(options)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -1155,12 +1155,12 @@ class BasicsTest < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def test_to_xml
|
||||
xml = Topic.find(:first).to_xml(:indent => 0, :skip_instruct => true)
|
||||
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true)
|
||||
assert_equal "<topic>", xml.first(7)
|
||||
assert xml.include?(%(<title>The First Topic</title>))
|
||||
assert xml.include?(%(<author-name>David</author-name>))
|
||||
assert xml.include?(%(<id type="integer">1</id>))
|
||||
assert xml.include?(%(<approved type="boolean">false</approved>))
|
||||
assert xml.include?(%(<approved type="boolean">false</approved>)), "Approved should be a boolean"
|
||||
assert xml.include?(%(<replies-count type="integer">0</replies-count>))
|
||||
assert xml.include?(%(<bonus-time type="datetime">2000-01-01 08:28:00</bonus-time>))
|
||||
assert xml.include?(%(<written-on type="datetime">2003-07-16 09:28:00</written-on>))
|
||||
@@ -1171,16 +1171,54 @@ class BasicsTest < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def test_to_xml_skipping_attributes
|
||||
xml = Topic.find(:first).to_xml(:indent => 0, :skip_instruct => true, :skip_attributes => :title)
|
||||
breakpoint
|
||||
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => :title)
|
||||
assert_equal "<topic>", xml.first(7)
|
||||
assert !xml.include?(%(<title>The First Topic</title>))
|
||||
assert xml.include?(%(<author-name>David</author-name>))
|
||||
|
||||
xml = Topic.find(:first).to_xml(:indent => 0, :skip_instruct => true, :skip_attributes => [ :title, :author_name ])
|
||||
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [ :title, :author_name ])
|
||||
assert !xml.include?(%(<title>The First Topic</title>))
|
||||
assert !xml.include?(%(<author-name>David</author-name>))
|
||||
end
|
||||
|
||||
def test_to_xml_including_has_many_association
|
||||
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :include => :replies)
|
||||
assert_equal "<topic>", xml.first(7)
|
||||
assert xml.include?(%(<replies><reply>))
|
||||
assert xml.include?(%(<title>The Second Topic's of the day</title>))
|
||||
end
|
||||
|
||||
def test_to_xml_including_belongs_to_association
|
||||
xml = companies(:first_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
||||
assert !xml.include?("<firm>")
|
||||
|
||||
xml = companies(:second_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
||||
assert xml.include?("<firm>")
|
||||
end
|
||||
|
||||
def test_to_xml_including_multiple_associations
|
||||
xml = companies(:first_firm).to_xml(:indent => 0, :skip_instruct => true, :include => [ :clients, :account ])
|
||||
assert_equal "<firm>", xml.first(6)
|
||||
assert xml.include?(%(<account>))
|
||||
assert xml.include?(%(<clients><client>))
|
||||
end
|
||||
|
||||
def test_except_attributes
|
||||
assert_equal(
|
||||
%w( author_name type id approved replies_count bonus_time written_on content author_email_address parent_id last_read),
|
||||
topics(:first).attributes(:except => :title).keys
|
||||
)
|
||||
|
||||
assert_equal(
|
||||
%w( replies_count bonus_time written_on content author_email_address parent_id last_read),
|
||||
topics(:first).attributes(:except => [ :title, :id, :type, :approved, :author_name ]).keys
|
||||
)
|
||||
end
|
||||
|
||||
def test_include_attributes
|
||||
assert_equal(%w( title ), topics(:first).attributes(:only => :title).keys)
|
||||
assert_equal(%w( title author_name type id approved ), topics(:first).attributes(:only => [ :title, :id, :type, :approved, :author_name ]).keys)
|
||||
end
|
||||
|
||||
# FIXME: this test ought to run, but it needs to run sandboxed so that it
|
||||
# doesn't b0rk the current test environment by undefing everything.
|
||||
|
||||
Reference in New Issue
Block a user