Browse files

Merge pull request #13 from sfaxon/has_many_requests_child

has_many association requests child url if not present in first request
  • Loading branch information...
2 parents a45d577 + 405fd21 commit c0c6b338ca3bc45b7e72ca9ab37573645e7b2190 @jeremy jeremy committed Apr 14, 2012
View
19 lib/active_resource/associations.rb
@@ -30,6 +30,11 @@ module Builder
#
# <tt>has_many :comments, :class_name => 'myblog/comment'</tt>
# Would resolve those comments into the <tt>Myblog::Comment</tt> class.
+ #
+ # If the response body does not contain an attribute matching the association name
+ # a request sent to the index action under the current resource.
+ # For the example above, if the comments are not present the requested path would be:
+ # GET /posts/123/comments.xml
def has_many(name, options = {})
Builder::HasMany.build(self, name, options)
end
@@ -115,4 +120,18 @@ def defines_belongs_to_finder_method(method_name, association_model, finder_key)
end
end
+ def defines_has_many_finder_method(method_name, association_model)
+ ivar_name = :"@#{method_name}"
+
+ define_method(method_name) do
+ if instance_variable_defined?(ivar_name)
+ instance_variable_get(ivar_name)
+ elsif attributes.include?(method_name)
+ attributes[method_name]
+ else
+ instance_variable_set(ivar_name, association_model.find(:all, :params => {:"#{self.class.element_name}_id" => self.id}))
+ end
+ end
+ end
+
end
View
9 lib/active_resource/associations/builder/has_many.rb
@@ -1,5 +1,12 @@
module ActiveResource::Associations::Builder
class HasMany < Association
- self.macro = :has_many
+ self.macro = :has_many
+
+ def build
+ validate_options
+ model.create_reflection(self.class.macro, name, options).tap do |reflection|
+ model.defines_has_many_finder_method(reflection.name, reflection.klass)
+ end
+ end
end
end
View
7 test/abstract_unit.rb
@@ -26,6 +26,9 @@ def setup_response
@people = { :people => [ { :person => { :id => 1, :name => 'Matz' } }, { :person => { :id => 2, :name => 'David' } }] }.to_json
@people_david = { :people => [ { :person => { :id => 2, :name => 'David' } }] }.to_json
@addresses = { :addresses => [{ :address => { :id => 1, :street => '12345 Street', :country => 'Australia' } }] }.to_json
+ @post = {:id => 1, :title => 'Hello World', :body => 'Lorem Ipsum'}.to_json
+ @posts = [{:id => 1, :title => 'Hello World', :body => 'Lorem Ipsum'},{:id => 2, :title => 'Second Post', :body => 'Lorem Ipsum'}].to_json
+ @comments = [{:id => 1, :post_id => 1, :content => 'Interesting post'},{:id => 2, :post_id => 1, :content => 'I agree'}].to_json
# - deep nested resource -
# - Luis (Customer)
@@ -138,6 +141,10 @@ def setup_response
mock.get "/customers/1.json", {}, @luis
# sound
mock.get "/sounds/1.json", {}, @startup_sound
+ # post
+ mock.get "/posts.json", {}, @posts
+ mock.get "/posts/1.json", {}, @post
+ mock.get "/posts/1/comments.json", {}, @comments
end
Person.user = nil
View
22 test/cases/associations/builder/has_many_test.rb
@@ -0,0 +1,22 @@
+require 'abstract_unit'
+
+require 'fixtures/person'
+require 'fixtures/street_address'
+
+class ActiveResource::Associations::Builder::HasManyTest < ActiveSupport::TestCase
+ def setup
+ @klass = ActiveResource::Associations::Builder::HasMany
+ end
+
+ def test_validations_for_instance
+ object = @klass.new(Person, :street_address, {})
+ assert_equal({}, object.send(:validate_options))
+ end
+
+ def test_instance_build
+ object = @klass.new(Person, :street_address, {})
+ Person.expects(:defines_has_many_finder_method).with(:street_address, StreetAddress)
+ assert_kind_of ActiveResource::Reflection::AssociationReflection, object.build
+ end
+
+end
View
10 test/cases/base_test.rb
@@ -7,6 +7,8 @@
require "fixtures/proxy"
require "fixtures/address"
require "fixtures/subscription_plan"
+require "fixtures/post"
+require "fixtures/comment"
require 'active_support/json'
require 'active_support/core_ext/hash/conversions'
require 'mocha'
@@ -1124,6 +1126,14 @@ def test_parse_resources_with_given_has_many_resources
end
end
+ def test_parse_resources_with_has_many_makes_get_request_on_nested_route
+ Post.send(:has_many, :comments)
+ post = Post.find(1)
+ post.comments.each do |comment|
+ assert_kind_of Comment, comment
+ end
+ end
+
def test_load_yaml_array
assert_nothing_raised do
Person.format = :xml
View
3 test/fixtures/comment.rb
@@ -0,0 +1,3 @@
+class Comment < ActiveResource::Base
+ self.site = "http://37s.sunrise.i:3000/posts/:post_id"
+end
View
3 test/fixtures/post.rb
@@ -0,0 +1,3 @@
+class Post < ActiveResource::Base
+ self.site = "http://37s.sunrise.i:3000"
+end

0 comments on commit c0c6b33

Please sign in to comment.