Skip to content

Commit 21ef5e3

Browse files
committed
Fix data cache on model for associations, fixes remi#248
1 parent 0c3ff4e commit 21ef5e3

File tree

3 files changed

+30
-11
lines changed

3 files changed

+30
-11
lines changed

lib/her/model/associations/association.rb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,12 @@ def fetch(opts = {})
4747
attribute_value = @parent.attributes[@name]
4848
return @opts[:default].try(:dup) if @parent.attributes.include?(@name) && (attribute_value.nil? || !attribute_value.nil? && attribute_value.empty?) && @params.empty?
4949

50-
if @parent.attributes[@name].blank? || @params.any?
51-
path = build_association_path lambda { "#{@parent.request_path(@params)}#{@opts[:path]}" }
52-
@klass.get(path, @params)
53-
else
54-
@parent.attributes[@name]
50+
return @cached_result unless @params.any? || @cached_result.nil?
51+
return @parent.attributes[@name] unless @params.any? || @parent.attributes[@name].blank?
52+
53+
path = build_association_path lambda { "#{@parent.request_path(@params)}#{@opts[:path]}" }
54+
@klass.get(path, @params).tap do |result|
55+
@cached_result = result unless @params.any?
5556
end
5657
end
5758

lib/her/model/associations/belongs_to_association.rb

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,13 @@ def fetch
7676
data_key_value = @parent.attributes[@opts[:data_key].to_sym]
7777
return @opts[:default].try(:dup) if (@parent.attributes.include?(@name) && @parent.attributes[@name].nil? && @params.empty?) || (@parent.persisted? && foreign_key_value.blank? && data_key_value.blank?)
7878

79-
if @parent.attributes[@name].blank? || @params.any?
80-
path_params = @parent.attributes.merge(@params.merge(@klass.primary_key => foreign_key_value))
81-
path = build_association_path lambda { @klass.build_request_path(path_params) }
82-
@klass.get(path, @params)
83-
else
84-
@parent.attributes[@name]
79+
return @cached_result unless @params.any? || @cached_result.nil?
80+
return @parent.attributes[@name] unless @params.any? || @parent.attributes[@name].blank?
81+
82+
path_params = @parent.attributes.merge(@params.merge(@klass.primary_key => foreign_key_value))
83+
path = build_association_path lambda { @klass.build_request_path(path_params) }
84+
@klass.get(path, @params).tap do |result|
85+
@cached_result = result if @params.blank?
8586
end
8687
end
8788

spec/model/associations_spec.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
let(:user_with_included_data_after_create) { Foo::User.create }
138138
let(:user_with_included_data_after_save_existing) { Foo::User.save_existing(5, :name => "Clancy Brown") }
139139
let(:user_with_included_data_after_destroy) { Foo::User.new(:id => 5).destroy }
140+
let(:comment_without_included_parent_data) { Foo::Comment.new(:id => 7, :user_id => 1) }
140141

141142
it "maps an array of included data through has_many" do
142143
@user_with_included_data.comments.first.should be_a(Foo::Comment)
@@ -149,6 +150,14 @@
149150
@user_with_included_data.comments.first.user.object_id.should == @user_with_included_data.object_id
150151
end
151152

153+
it "does fetch the parent models data only once" do
154+
comment_without_included_parent_data.user.object_id.should == comment_without_included_parent_data.user.object_id
155+
end
156+
157+
it "does fetch the parent models data that was cached if called with parameters" do
158+
comment_without_included_parent_data.user.object_id.should_not == comment_without_included_parent_data.user.where(:a => 2).object_id
159+
end
160+
152161
it "uses the given inverse_of key to set the parent model" do
153162
@user_with_included_data.posts.first.admin.object_id.should == @user_with_included_data.object_id
154163
end
@@ -164,6 +173,14 @@
164173
@user_with_included_data.comments.where(:foo_id => 1).length.should == 1
165174
end
166175

176+
it "fetches data that was not included through has_many only once" do
177+
@user_without_included_data.comments.first.object_id.should == @user_without_included_data.comments.first.object_id
178+
end
179+
180+
it "fetches data that was cached through has_many if called with parameters" do
181+
@user_without_included_data.comments.first.object_id.should_not == @user_without_included_data.comments.where(:foo_id => 1).first.object_id
182+
end
183+
167184
it "maps an array of included data through has_one" do
168185
@user_with_included_data.role.should be_a(Foo::Role)
169186
@user_with_included_data.role.object_id.should == @user_with_included_data.role.object_id

0 commit comments

Comments
 (0)