diff --git a/lib/her/model/associations/association.rb b/lib/her/model/associations/association.rb index 6a4ae110..c6bd2fe8 100644 --- a/lib/her/model/associations/association.rb +++ b/lib/her/model/associations/association.rb @@ -65,6 +65,21 @@ def build_association_path(code) end end + # @private + def build_with_inverse(attributes = {}) + @klass.build(attributes.merge(:"#{@parent.singularized_resource_name}_id" => @parent.id)).tap do |resource| + begin + resource.request_path + rescue Her::Errors::PathError => e + e.missing_parameters.each do |m| + if id = @parent.get_attribute(m) || @parent.get_attribute("_#{m}") + resource.send("_#{m}=", id) + end + end + end + end + end + # Add query parameters to the HTTP request performed to fetch the data # # @example diff --git a/lib/her/model/associations/has_many_association.rb b/lib/her/model/associations/has_many_association.rb index 63cef796..901f8d03 100644 --- a/lib/her/model/associations/has_many_association.rb +++ b/lib/her/model/associations/has_many_association.rb @@ -49,10 +49,8 @@ def self.parse(association, klass, data) # user = User.find(1) # new_comment = user.comments.build(:body => "Hello!") # new_comment # => # - # TODO: This only merges the id of the parents, handle the case - # where this is more deeply nested def build(attributes = {}) - @klass.build(attributes.merge(:"#{@parent.singularized_resource_name}_id" => @parent.id)) + build_with_inverse(attributes) end # Create a new object, save it and add it to the associated collection diff --git a/lib/her/model/associations/has_one_association.rb b/lib/her/model/associations/has_one_association.rb index 80cb3cd3..b3f8cb46 100644 --- a/lib/her/model/associations/has_one_association.rb +++ b/lib/her/model/associations/has_one_association.rb @@ -45,7 +45,7 @@ def self.parse(*args) # new_role = user.role.build(:title => "moderator") # new_role # => # def build(attributes = {}) - @klass.build(attributes.merge(:"#{@parent.singularized_resource_name}_id" => @parent.id)) + build_with_inverse(attributes) end # Create a new object, save it and associate it to the parent diff --git a/spec/model/associations_spec.rb b/spec/model/associations_spec.rb index 5dc9af57..2cb99216 100644 --- a/spec/model/associations_spec.rb +++ b/spec/model/associations_spec.rb @@ -490,7 +490,13 @@ def present? context "building and creating association data" do before do - spawn_model "Foo::Comment" + spawn_model "Foo::Like" do + collection_path "/users/:user_id/comments/:comment_id/likes" + end + spawn_model "Foo::Comment" do + collection_path "/users/:user_id/comments" + has_many :likes + end spawn_model "Foo::User" do has_many :comments end @@ -502,6 +508,11 @@ def present? expect(@comment.body).to eq("Hello!") expect(@comment.user_id).to eq(10) end + + it "uses nested path parameters from the parent" do + @like = Foo::User.new(:id => 10).comments.build(:id => 20).likes.build + @like.request_path.should == "/users/10/comments/20/likes" + end end context "with #create" do @@ -511,7 +522,7 @@ def present? builder.use Faraday::Request::UrlEncoded builder.adapter :test do |stub| stub.get("/users/10") { [200, {}, { id: 10 }.to_json] } - stub.post("/comments") { |env| [200, {}, { id: 1, body: Faraday::Utils.parse_query(env[:body])["body"], user_id: Faraday::Utils.parse_query(env[:body])["user_id"].to_i }.to_json] } + stub.post("/users/10/comments") { |env| [200, {}, { id: 1, body: Faraday::Utils.parse_query(env[:body])["body"], user_id: Faraday::Utils.parse_query(env[:body])["user_id"].to_i }.to_json] } end end