Skip to content

Commit 021a699

Browse files
committed
[MODEL] Perform partial updates in model where the ActiveModel support is available
When the model implements the `before_save` callback and the `changed_attributes` method, intercept attribute changes, store them in the `@__changed_attributes` variable, and perform a partial update (PUT .../_update) when updating the document in the index in the `update_document` method Fallback to full reindex via the `index_document` when changed attributes are not accessible.
1 parent d527240 commit 021a699

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

elasticsearch-model/lib/elasticsearch/model/indexing.rb

+26-3
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,21 @@ def settings(settings={}, &block)
157157
end
158158

159159
module InstanceMethods
160+
161+
def self.included(base)
162+
# Register callback for storing changed attributes for models
163+
# which implement `before_save` and `changed_attributes` methods
164+
#
165+
# @note This is typically triggered only when the module would be
166+
# included in the model directly, not within the proxy.
167+
#
168+
base.before_save do |instance|
169+
instance_variable_set(:@__changed_attributes,
170+
Hash[ instance.changes.map { |key, value| [key, value.last] } ])
171+
# puts "--- STORING changes --- (#{self.__elasticsearch__.instance_variable_get(:@__changed_attributes)})"
172+
end if base.respond_to?(:before_save) && base.instance_methods.include?(:changed_attributes)
173+
end
174+
160175
def index_document(options={})
161176
document = self.as_indexed_json
162177

@@ -177,9 +192,17 @@ def delete_document(options={})
177192
end
178193

179194
def update_document(options={})
180-
# TODO: Intercept changes to the record, and use `changed_attributes`
181-
# to perform update by partial doc.
182-
index_document(options)
195+
# puts "--- STORED changes --- (#{self.instance_variable_get(:@__changed_attributes)})"
196+
if changed_attributes = self.instance_variable_get(:@__changed_attributes)
197+
client.update(
198+
{ index: index_name,
199+
type: document_type,
200+
id: self.id,
201+
body: { doc: changed_attributes } }.merge(options)
202+
)
203+
else
204+
index_document(options)
205+
end
183206
end
184207
end
185208

elasticsearch-model/lib/elasticsearch/model/proxy.rb

+13-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ module Model
3030
module Proxy
3131

3232
# Define the `__elasticsearch__` class and instance methods
33-
# in including class.
33+
# in including class and register the callback for intercepting changes in the model
34+
#
35+
# @note The callback is triggered only when `Elasticsearch::Model` is included in the
36+
# module and the functionality is accessible via the proxy.
3437
#
3538
def self.included(base)
3639
base.class_eval do
@@ -49,6 +52,15 @@ def __elasticsearch__ &block
4952
@__elasticsearch__.instance_eval(&block) if block_given?
5053
@__elasticsearch__
5154
end
55+
56+
# Register callback for storing changed attributes for models which implement
57+
# `before_save` and `changed_attributes` methods (when `Elasticsearch::Model` is included)
58+
#
59+
before_save do |i|
60+
i.__elasticsearch__.instance_variable_set(:@__changed_attributes,
61+
Hash[ i.changes.map { |key, value| [key, value.last] } ])
62+
# puts "--- STORING changes --- (#{self.__elasticsearch__.instance_variable_get(:@__changed_attributes)})"
63+
end if respond_to?(:before_save) && instance_methods.include?(:changed_attributes)
5264
end
5365
end
5466

0 commit comments

Comments
 (0)