<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 21/09/12 12:25 PM, Tomas Sedovic
      wrote:<br>
    </div>
    <blockquote cite="mid:505C4EC2.4060909@redhat.com" type="cite">On
      09/20/2012 02:20 PM, Martyn Taylor wrote:
      <br>
      <blockquote type="cite">Gents.
        <br>
        <br>
        I'm having some trouble with getting nested resources working
        properly
        <br>
        from bespoke XML/JSON in RESTful API.&nbsp; There seems to be some
        <br>
        fundamental problems with the way rails works, which means we
        have to
        <br>
        write a lot of bespoke code to get it working, possibly even
        having to
        <br>
        monkey patch Rails itself.
        <br>
        <br>
        I've written an example rails app that highlights the problem
        and put a
        <br>
        detailed description in the README you can find it here:
        <br>
        <br>
        <a class="moz-txt-link-freetext" href="https://github.com/mtaylor/Rails-Nested-Resource-Issues">https://github.com/mtaylor/Rails-Nested-Resource-Issues</a>
        <br>
        <br>
        I've ran into this issue on IME.&nbsp; But it's going to affect us
        across all
        <br>
        rails projects with REST APIs, so we could do with discussing
        this issue
        <br>
        and coming up with the best possible solution that results in as
        little
        <br>
        replication as possible.
        <br>
        <br>
        Please read through the problem and let me know if you have any
        better
        <br>
        ideas that the solutions I have proposed.
        <br>
        <br>
        Regards
        <br>
        <br>
        Martyn
        <br>
      </blockquote>
      <br>
      <br>
      I'm beginning to lean towards the custom serialization and
      deserialization. We'll have explicit control over the input/output
      formats which is a good thing for API stability.
      <br>
      <br>
      However, there may be another issue that's reasonably close to
      what we expected the default behaviour would be.
      <br>
      <br>
      If I understand this correctly, the issue isn't really behaviour
      of the `attribute=` setters but of `Model.new`[1] and
      `@model.update_attributes`[2] methods.
      <br>
      <br>
      We could insert a base class into the model inheritance chain and
      either "fix" the methods there or add new ones that do bulk
      attribute operations correctly.
      <br>
      <br>
      Pseudocode:
      <br>
      <br>
      class NestedModels &lt; ActiveRecord::Base
      <br>
      &nbsp; def initialize(attributes = nil, options = {})
      <br>
      &nbsp;&nbsp;&nbsp; if attributes
      <br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; attributes = attributes.clone
      <br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get_nested_attribute_names.each do |name|
      <br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; attributes[name + '_attributes'] = attributes[name]
      <br>
      &nbsp;&nbsp;&nbsp;&nbsp;attributes.delete name
      <br>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end
      <br>
      &nbsp;&nbsp;&nbsp; end
      <br>
      &nbsp;&nbsp;&nbsp; super.initialize(attributes, options)
      <br>
      &nbsp; end
      <br>
      <br>
      &nbsp; def update_attributes(attributes, options = {})
      <br>
      &nbsp;&nbsp;&nbsp; # TODO, similar to initialize
      <br>
      &nbsp; end
      <br>
      <br>
      &nbsp; def update_attributes!(attributes, options = {})
      <br>
      &nbsp;&nbsp;&nbsp; # TODO, similar to update_attributes
      <br>
      &nbsp; end
      <br>
      <br>
      &nbsp; def get_nested_attributes
      <br>
      &nbsp;&nbsp;&nbsp; # TODO: use introspection to figure out attribute names passed
      to accepts_nested_attributes_for in the model declaration
      <br>
      &nbsp; end
      <br>
      end
      <br>
      <br>
      class User &lt; NestedModels
      <br>
      &nbsp; has_many :addresses
      <br>
      <br>
      &nbsp; accepts_nested_attributes_for :addresses
      <br>
      &nbsp; attr_accessible :name, :addresses, :addresses_attributes
      <br>
      end
      <br>
      <br>
      <br>
      now calling:
      <br>
      <br>
      &nbsp;&nbsp;&nbsp; User.new({"name"=&gt;"Joe Bloggs",
      "addresses"=&gt;[{"street"=&gt;"Church Street"}]})
      <br>
      <br>
      would work because ActiveRecord::Base would receive:
      <br>
      <br>
      &nbsp;&nbsp;&nbsp; {"name"=&gt;"Joe Bloggs",
      "addresses_attributes"=&gt;[{"street"=&gt;"Church Street"}]}
      <br>
      <br>
      <br>
      This is similar to the monkeypatching proposal but it's safer. We
      would not be modifying any of the Rails' internals. Rather, we'd
      explicitly specify which models should have this modified
      behaviour.
      <br>
      <br>
      We could probably also do this by including a module with the
      overrides instead of using inheritance.
      <br>
    </blockquote>
    <br>
    Keep in mind that ActiveRecord provides builder methods for
    associations [3]. In the example you used:<br>
    <br>
    &nbsp;&nbsp; User.address.build(:street =&gt; "Church street")<br>
    <br>
    or if you already have an instance of User:<br>
    <br>
    &nbsp;&nbsp; @user.address.build(:street =&gt; "Church street")<br>
    <br>
    <br>
    There are similar methods for one-to-many associations, which have
    the benefit of elements of collection not being persisted
    immediately (as opposed to adding an element to a collection
    directly).<br>
    <br>
    <br>
    If you are inclined to solve the problem on the model level, you
    could add a factory method that accepts a hash, and returns a
    fully-assembled instance, nested resources and all, with no monkey
    patching involved.<br>
    <br>
    <br>
    -d<br>
    <br>
    <br>
    <br>
    <blockquote cite="mid:505C4EC2.4060909@redhat.com" type="cite">
      <br>
      [1]:
<a class="moz-txt-link-freetext" href="https://github.com/rails/rails/blob/9b5309fb6819d8f2a1b31e44ba61e682272c7aa3/activerecord/lib/active_record/base.rb#L481">https://github.com/rails/rails/blob/9b5309fb6819d8f2a1b31e44ba61e682272c7aa3/activerecord/lib/active_record/base.rb#L481</a><br>
      [2]:
<a class="moz-txt-link-freetext" href="https://github.com/rails/rails/blob/81542f95d25825a7d3eff87d6f706661bf553b18/activerecord/lib/active_record/persistence.rb#L211">https://github.com/rails/rails/blob/81542f95d25825a7d3eff87d6f706661bf553b18/activerecord/lib/active_record/persistence.rb#L211</a><br>
    </blockquote>
    [3]:
    <meta http-equiv="content-type" content="text/html;
      charset=ISO-8859-1">
    <a
href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html">http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html</a>
  </body>
</html>