From 5a2eeaa5cf1947f7b9f6267ffb2dee3b59b6d404 Mon Sep 17 00:00:00 2001 From: Tom Dunlap Date: Thu, 16 Oct 2014 14:45:32 -0400 Subject: [PATCH] Attempt to cache inverse of has_many Previous behavior was to set the inverse of `has_many` objects as attributes. This can be problematic in the case of attempting to serialize attributes (think, infinite recursion). It is also different than how most other relationship are expected to behave (i.e. saving them in the `Association@cached_data`. This commit exposes `Association#cached_data` and has the `HasManyAssociation#fetch` attempt to save the inverse relationship in the `cached_data` if such a relationship/association is defined (most often through the `AssociationProxy`. --- lib/her/model/associations/association.rb | 2 +- lib/her/model/associations/has_many_association.rb | 9 ++++++++- spec/model/associations_spec.rb | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/her/model/associations/association.rb b/lib/her/model/associations/association.rb index 81fdeb96..23708b2c 100644 --- a/lib/her/model/associations/association.rb +++ b/lib/her/model/associations/association.rb @@ -3,7 +3,7 @@ module Model module Associations class Association # @private - attr_accessor :params + attr_accessor :params, :cached_result # @private def initialize(parent, opts = {}) diff --git a/lib/her/model/associations/has_many_association.rb b/lib/her/model/associations/has_many_association.rb index 63cef796..0dad8c29 100644 --- a/lib/her/model/associations/has_many_association.rb +++ b/lib/her/model/associations/has_many_association.rb @@ -85,7 +85,14 @@ def create(attributes = {}) def fetch super.tap do |o| inverse_of = @opts[:inverse_of] || @parent.singularized_resource_name - o.each { |entry| entry.send("#{inverse_of}=", @parent) } + o.each do |entry| + inverse_association = entry.send(inverse_of).association rescue nil + if inverse_association.present? + inverse_association.cached_result = @parent + else + entry.send("#{inverse_of}=", @parent) + end + end end end diff --git a/spec/model/associations_spec.rb b/spec/model/associations_spec.rb index a3bf3f68..89fbc72c 100644 --- a/spec/model/associations_spec.rb +++ b/spec/model/associations_spec.rb @@ -173,6 +173,11 @@ @user_with_included_data.comments.where(:foo_id => 1).length.should == 1 end + it "does not set the inverse of a has_many as an attribute" do + first_comment = @user_without_included_data.comments.first + expect(first_comment.attributes.keys).to_not include("user") + end + it "fetches data that was not included through has_many only once" do @user_without_included_data.comments.first.object_id.should == @user_without_included_data.comments.first.object_id end