Skip to content

Commit

Permalink
Fix uninitialized constant error loading resources with inverse assoc…
Browse files Browse the repository at this point in the history
…iations
  • Loading branch information
jbgo committed Mar 3, 2016
1 parent 5c4b4a8 commit 0b475c6
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 21 deletions.
21 changes: 12 additions & 9 deletions lib/active_resource/associations.rb
Expand Up @@ -117,7 +117,8 @@ def belongs_to(name, options={})
end

# Defines the belongs_to association finder method
def defines_belongs_to_finder_method(method_name, association_model, finder_key)
def defines_belongs_to_finder_method(reflection)
method_name = reflection.name
ivar_name = :"@#{method_name}"

if method_defined?(method_name)
Expand All @@ -130,13 +131,14 @@ def defines_belongs_to_finder_method(method_name, association_model, finder_key)
instance_variable_get(ivar_name)
elsif attributes.include?(method_name)
attributes[method_name]
elsif association_id = send(finder_key)
instance_variable_set(ivar_name, association_model.find(association_id))
elsif association_id = send(reflection.foreign_key)
instance_variable_set(ivar_name, reflection.klass.find(association_id))
end
end
end

def defines_has_many_finder_method(method_name, association_model)
def defines_has_many_finder_method(reflection)
method_name = reflection.name
ivar_name = :"@#{method_name}"

define_method(method_name) do
Expand All @@ -145,26 +147,27 @@ def defines_has_many_finder_method(method_name, association_model)
elsif attributes.include?(method_name)
attributes[method_name]
elsif !new_record?
instance_variable_set(ivar_name, association_model.find(:all, :params => {:"#{self.class.element_name}_id" => self.id}))
instance_variable_set(ivar_name, reflection.klass.find(:all, :params => {:"#{self.class.element_name}_id" => self.id}))
else
instance_variable_set(ivar_name, self.class.collection_parser.new)
end
end
end

# Defines the has_one association
def defines_has_one_finder_method(method_name, association_model)
def defines_has_one_finder_method(reflection)
method_name = reflection.name
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]
elsif association_model.respond_to?(:singleton_name)
instance_variable_set(ivar_name, association_model.find(:params => {:"#{self.class.element_name}_id" => self.id}))
elsif reflection.klass.respond_to?(:singleton_name)
instance_variable_set(ivar_name, reflection.klass.find(:params => {:"#{self.class.element_name}_id" => self.id}))
else
instance_variable_set(ivar_name, association_model.find(:one, :from => "/#{self.class.collection_name}/#{self.id}/#{method_name}#{self.class.format_extension}"))
instance_variable_set(ivar_name, reflection.klass.find(:one, :from => "/#{self.class.collection_name}/#{self.id}/#{method_name}#{self.class.format_extension}"))
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/active_resource/associations/builder/belongs_to.rb
Expand Up @@ -7,7 +7,7 @@ class BelongsTo < Association
def build
validate_options
reflection = model.create_reflection(self.class.macro, name, options)
model.defines_belongs_to_finder_method(reflection.name, reflection.klass, reflection.foreign_key)
model.defines_belongs_to_finder_method(reflection)
return reflection
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/active_resource/associations/builder/has_many.rb
Expand Up @@ -5,7 +5,7 @@ class HasMany < Association
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)
model.defines_has_many_finder_method(reflection)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/active_resource/associations/builder/has_one.rb
Expand Up @@ -5,7 +5,7 @@ class HasOne < Association
def build
validate_options
model.create_reflection(self.class.macro, name, options).tap do |reflection|
model.defines_has_one_finder_method(reflection.name, reflection.klass)
model.defines_has_one_finder_method(reflection)
end
end
end
Expand Down
23 changes: 20 additions & 3 deletions test/cases/association_test.rb
Expand Up @@ -8,6 +8,7 @@
class AssociationTest < ActiveSupport::TestCase
def setup
@klass = ActiveResource::Associations::Builder::Association
@reflection = ActiveResource::Reflection::AssociationReflection.new :belongs_to, :customer, {}
end


Expand Down Expand Up @@ -55,7 +56,7 @@ def test_belongs_to
end

def test_defines_belongs_to_finder_method_with_instance_variable_cache
Person.defines_belongs_to_finder_method(:customer, Customer, 'customer_id')
Person.defines_belongs_to_finder_method(@reflection)

person = Person.new
assert !person.instance_variable_defined?(:@customer)
Expand All @@ -66,7 +67,7 @@ def test_defines_belongs_to_finder_method_with_instance_variable_cache
end

def test_belongs_to_with_finder_key
Person.defines_belongs_to_finder_method(:customer, Customer, 'customer_id')
Person.defines_belongs_to_finder_method(@reflection)

person = Person.new
person.stubs(:customer_id).returns(1)
Expand All @@ -75,11 +76,27 @@ def test_belongs_to_with_finder_key
end

def test_belongs_to_with_nil_finder_key
Person.defines_belongs_to_finder_method(:customer, Customer, 'customer_id')
Person.defines_belongs_to_finder_method(@reflection)

person = Person.new
person.stubs(:customer_id).returns(nil)
Customer.expects(:find).with(nil).never()
person.customer
end

def test_inverse_associations_do_not_create_circular_dependencies
code = <<-CODE
class Park < ActiveResource::Base
has_many :trails
end
class Trail < ActiveResource::Base
belongs_to :park
end
CODE

assert_nothing_raised do
eval code
end
end
end
10 changes: 8 additions & 2 deletions test/cases/associations/builder/belongs_to_test.rb
Expand Up @@ -19,8 +19,14 @@ def test_validations_for_instance

def test_instance_build
object = @klass.new(Person, :customer, {})
Person.expects(:defines_belongs_to_finder_method).with(:customer, Customer, 'customer_id')
assert_kind_of ActiveResource::Reflection::AssociationReflection, object.build
Person.expects(:defines_belongs_to_finder_method).with(kind_of(ActiveResource::Reflection::AssociationReflection))

reflection = object.build

assert_kind_of ActiveResource::Reflection::AssociationReflection, reflection
assert_equal :customer, reflection.name
assert_equal Customer, reflection.klass
assert_equal 'customer_id', reflection.foreign_key
end


Expand Down
9 changes: 7 additions & 2 deletions test/cases/associations/builder/has_many_test.rb
Expand Up @@ -15,8 +15,13 @@ def test_validations_for_instance

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
Person.expects(:defines_has_many_finder_method).with(kind_of(ActiveResource::Reflection::AssociationReflection))

reflection = object.build

assert_kind_of ActiveResource::Reflection::AssociationReflection, reflection
assert_equal :street_address, reflection.name
assert_equal StreetAddress, reflection.klass
end

end
8 changes: 6 additions & 2 deletions test/cases/associations/builder/has_one_test.rb
Expand Up @@ -15,9 +15,13 @@ def test_validations_for_instance

def test_instance_build
object = @klass.new(Product, :inventory, {})
Product.expects(:defines_has_one_finder_method).with(kind_of(ActiveResource::Reflection::AssociationReflection))

Product.expects(:defines_has_one_finder_method).with(:inventory, Inventory)
assert_kind_of ActiveResource::Reflection::AssociationReflection, object.build
reflection = object.build

assert_kind_of ActiveResource::Reflection::AssociationReflection, reflection
assert_equal :inventory, reflection.name
assert_equal Inventory, reflection.klass
end

end

0 comments on commit 0b475c6

Please sign in to comment.