Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

has_many associations respect nested resources #17

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/active_resource/associations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,22 @@ def defines_belongs_to_finder_method(method_name, association_model, finder_key)
end
end

# Defines the has_many finder method
def defines_has_many_finder_method(method_name, association_model)
ivar_name = :"@#{method_name}"

if method_defined?(method_name)
instance_variable_set(ivar_name, nil)
remove_method(method_name)
end

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}))
instance_variable_set(ivar_name, association_model.find(:all, :from => "#{element_base_path}/#{method_name}.#{association_model.format.extension}"))
end
end
end
Expand Down
35 changes: 32 additions & 3 deletions lib/active_resource/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -685,10 +685,35 @@ def prefix(options={}) "#{prefix_call}" end
# # => /posts/5/comments/1.json?active=1
#
def element_path(id, prefix_options = {}, query_options = nil)
check_prefix_options(prefix_options)

prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}.#{format.extension}#{query_string(query_options)}"
"#{element_base_path(id, prefix_options)}.#{format.extension}#{query_string(query_options)}"
end

# Gets the element base path for the given ID in +id+. This will never return a format extension or params,
# it is useful for building prefix paths. See <tt>element_path</tt> if you need format extensions and params.
#
# ==== Options
# +prefix_options+ - A \hash to add a \prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt>
# would yield a URL like <tt>/accounts/19</tt>).
#
# ==== Examples
# Class Post < ActiveResource::Base
# self.site = "https://37s.sunrise.com/api"
# end
#
# Post.element_base_path(1)
# # => /api/posts/1
#
# class Comment < ActiveResource::Base
# self.site = "https://37s.sunrise.com/api/posts/:post_id"
# end
#
# Comment.element_base_path(1, :post_id => 5)
# # => /api/posts/5/comments/1
#
def element_base_path(id, prefix_options = {})
check_prefix_options(prefix_options)
"#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}"
end

# Gets the new element path for REST resources.
Expand Down Expand Up @@ -1423,6 +1448,10 @@ def id_from_response(response)
def element_path(options = nil)
self.class.element_path(to_param, options || prefix_options)
end

def element_base_path(options = nil)
self.class.element_base_path(to_param, options || prefix_options)
end

def new_element_path
self.class.new_element_path(prefix_options)
Expand Down
4 changes: 4 additions & 0 deletions test/abstract_unit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ def setup_response
@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
@post_two = {:id => 2, :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
@comments_two = [{:id => 3, :post_id => 2, :content => 'Interesting post'},{:id => 4, :post_id => 2, :content => 'I agree'}].to_json

# - deep nested resource -
# - Luis (Customer)
Expand Down Expand Up @@ -148,6 +150,8 @@ def setup_response
mock.get "/posts.json", {}, @posts
mock.get "/posts/1.json", {}, @post
mock.get "/posts/1/comments.json", {}, @comments
mock.get "/api/posts/2.json", {}, @post_two
mock.get "/api/posts/2/comments.json", {}, @comments_two
# products
mock.get '/products/1.json', {}, @product
mock.get '/products/1/inventory.json', {}, @inventory
Expand Down
23 changes: 23 additions & 0 deletions test/cases/base_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,29 @@ def test_parse_resources_with_has_many_makes_get_request_on_nested_route
end
end

def test_parse_resources_with_has_many_infers_association_prefix
Post.send(:has_many, :comments)
post = Post.find(1)
post.comments.each do |comment|
assert_kind_of Comment, comment
end
end

def test_has_many_honors_prefix
c_prefix = Comment.prefix
p_prefix = Post.prefix
Comment.prefix = "/api/"
Post.prefix = "/api/"
Post.send(:has_many, :comments)
post = Post.find(2)
post.comments.each do |comment|
assert_kind_of Comment, comment
end
ensure
Comment.prefix = c_prefix
Post.prefix = p_prefix
end

def test_parse_resource_with_has_one_makes_get_request_on_child_route
Product.send(:has_one, :inventory)
product = Product.find(1)
Expand Down