mobility 0.8.8 → 0.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +8 -4
- data/README.md +2 -2
- data/lib/mobility/plugins/active_model/dirty.rb +265 -44
- data/lib/mobility/plugins/active_record/dirty.rb +52 -98
- data/lib/mobility/plugins/dirty.rb +1 -1
- data/lib/mobility/plugins/sequel/dirty.rb +17 -15
- data/lib/mobility/version.rb +1 -1
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 792cd0d08532672e8bef3620b2e0741c6dab8bbe7105b80638ac5c0468e02a43
|
4
|
+
data.tar.gz: 76d31ca70d2b207c9612284a934f10b2ea0d68ad56f98ee92e03207323239841
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8194524ecaa6bd398d911b028f9a4029e374db423887ac1a7e21b68e501290531284c718733795df08b6d9d173033188bb28ac57c1aca9b897271788a812a7c
|
7
|
+
data.tar.gz: a89d634b7350cf01758cc929d36e354376ac9c2f9ee08b183e24f0200377756ba6950cd5d80b62b045527cbb43cf5a0c1e739564f1890b81bbfbcf68c8800cd5
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
|
3
3
|
## 0.8
|
4
4
|
|
5
|
+
### 0.8.9 (October 25, 2019)
|
6
|
+
* Fix Dirty plugin to work with Rails 6
|
7
|
+
([#343](https://github.com/shioyama/mobility/pull/343),
|
8
|
+
[#348](https://github.com/shioyama/mobility/pull/348),
|
9
|
+
[#352](https://github.com/shioyama/mobility/pull/352) on master branch, plus
|
10
|
+
[#351](https://github.com/shioyama/mobility/pull/351) to sync to 0-8-stable
|
11
|
+
branch). Summary of changes
|
12
|
+
[here](https://github.com/shioyama/mobility/pull/347#issuecomment-544742401).
|
13
|
+
|
5
14
|
### 0.8.8 (September 18, 2019)
|
6
15
|
* Accept any number of arguments to `Arel::Visitors::Visitor#visit`
|
7
16
|
([#339](https://github.com/shioyama/mobility/pull/339)). (Thanks to
|
data/Gemfile
CHANGED
@@ -11,11 +11,11 @@ group :development, :test do
|
|
11
11
|
gem 'activerecord', '>= 4.2.6', '< 5.0'
|
12
12
|
elsif ENV['RAILS_VERSION'] == '5.1'
|
13
13
|
gem 'activerecord', '>= 5.1', '< 5.2'
|
14
|
-
elsif ENV['RAILS_VERSION'] == '
|
15
|
-
gem 'activerecord', '>= 6.0.0.beta1'
|
16
|
-
else # Default is Rails 5.2
|
14
|
+
elsif ENV['RAILS_VERSION'] == '5.2'
|
17
15
|
gem 'activerecord', '>= 5.2.0', '< 5.3'
|
18
16
|
gem 'railties', '>= 5.2.0.rc2', '< 5.3'
|
17
|
+
else # Default is Rails 6.0
|
18
|
+
gem 'activerecord', '>= 6.0.0', '< 6.1'
|
19
19
|
end
|
20
20
|
gem "generator_spec", '~> 0.9.4'
|
21
21
|
elsif ENV['ORM'] == 'sequel'
|
@@ -31,7 +31,11 @@ group :development, :test do
|
|
31
31
|
platforms :ruby do
|
32
32
|
gem 'guard-rspec'
|
33
33
|
gem 'pry-byebug'
|
34
|
-
|
34
|
+
if ENV['ORM'] == 'active_record' && ENV['RAILS_VERSION'] < '5.2'
|
35
|
+
gem 'sqlite3', '~> 1.3.13'
|
36
|
+
else
|
37
|
+
gem 'sqlite3', '~> 1.4.1'
|
38
|
+
end
|
35
39
|
gem 'mysql2', '~> 0.4.9'
|
36
40
|
gem 'pg', '< 1.0'
|
37
41
|
end
|
data/README.md
CHANGED
@@ -51,7 +51,7 @@ Installation
|
|
51
51
|
Add this line to your application's Gemfile:
|
52
52
|
|
53
53
|
```ruby
|
54
|
-
gem 'mobility', '~> 0.8.
|
54
|
+
gem 'mobility', '~> 0.8.9'
|
55
55
|
```
|
56
56
|
|
57
57
|
Mobility is cryptographically signed. To be sure the gem you install hasn't
|
@@ -68,7 +68,7 @@ installation of unsigned dependencies.
|
|
68
68
|
### ActiveRecord (Rails)
|
69
69
|
|
70
70
|
Requirements:
|
71
|
-
- ActiveRecord >= 5.0
|
71
|
+
- ActiveRecord >= 5.0 (including 6.0)
|
72
72
|
|
73
73
|
(Support for most backends and features is also supported with
|
74
74
|
ActiveRecord/Rails 4.2, but there are some tests still failing. To see exactly
|
@@ -17,81 +17,302 @@ following methods:
|
|
17
17
|
- +title_previous_change+
|
18
18
|
- +restore_title!+
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
The following methods are also patched to work with translated attributes:
|
21
|
+
- +changed_attributes+
|
22
|
+
- +changes+
|
23
|
+
- +changed+
|
24
|
+
- +changed?+
|
25
|
+
- +previous_changes+
|
26
|
+
- +clear_attribute_changes+
|
27
|
+
- +restore_attributes+
|
28
|
+
|
29
|
+
In addition, the following ActiveModel attribute handler methods are also
|
30
|
+
patched to work with translated attributes:
|
31
|
+
- +attribute_changed?+
|
32
|
+
- +attribute_previously_changed?+
|
33
|
+
- +attribute_was+
|
34
|
+
|
35
|
+
(When using these methods, you must pass the attribute name along with its
|
36
|
+
locale suffix, so +title_en+, +title_pt_br+, etc.)
|
37
|
+
|
38
|
+
Other methods are also included for ActiveRecord models, see documentation on
|
39
|
+
the ActiveRecord dirty plugin for more information.
|
22
40
|
|
23
41
|
@see http://api.rubyonrails.org/classes/ActiveModel/Dirty.html Rails documentation for Active Model Dirty module
|
24
42
|
|
25
43
|
=end
|
26
44
|
module Dirty
|
27
|
-
# @!group Backend Accessors
|
28
|
-
# @!macro backend_writer
|
29
|
-
# @param [Hash] options
|
30
|
-
def write(locale, value, options = {})
|
31
|
-
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale)
|
32
|
-
if model.changed_attributes.has_key?(locale_accessor) && model.changed_attributes[locale_accessor] == value
|
33
|
-
model.send(:attributes_changed_by_setter).except!(locale_accessor)
|
34
|
-
elsif read(locale, options.merge(locale: true)) != value
|
35
|
-
model.send(:mobility_changed_attributes) << locale_accessor
|
36
|
-
model.send(:attribute_will_change!, locale_accessor)
|
37
|
-
end
|
38
|
-
super
|
39
|
-
end
|
40
|
-
# @!endgroup
|
41
|
-
|
42
45
|
# Builds module which adds suffix/prefix methods for translated
|
43
46
|
# attributes so they act like normal dirty-tracked attributes.
|
44
47
|
class MethodsBuilder < Module
|
48
|
+
delegate :dirty_class, :handler_methods_module, :method_patterns, to: :class
|
49
|
+
|
45
50
|
def initialize(*attribute_names)
|
51
|
+
define_dirty_methods(attribute_names)
|
52
|
+
end
|
53
|
+
|
54
|
+
def included(model_class)
|
55
|
+
model_class.include InstanceMethods
|
56
|
+
model_class.include handler_methods_module
|
57
|
+
|
58
|
+
# In earlier versions of Rails, these methods are private
|
59
|
+
%i[clear_attribute_changes clear_changes_information changes_applied].each do |method_name|
|
60
|
+
if dirty_class.private_instance_methods.include?(method_name)
|
61
|
+
model_class.class_eval { private method_name }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def append_locale(attr_name)
|
67
|
+
Mobility.normalize_locale_accessor(attr_name)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def define_dirty_methods(attribute_names)
|
73
|
+
m = self
|
74
|
+
|
46
75
|
attribute_names.each do |name|
|
47
|
-
|
48
|
-
define_method
|
49
|
-
|
76
|
+
method_patterns.each do |pattern|
|
77
|
+
define_method(pattern % name) do |*args|
|
78
|
+
mutations_from_mobility.send(pattern % 'attribute', m.append_locale(name), *args)
|
50
79
|
end
|
51
80
|
end
|
52
81
|
|
53
82
|
define_method "restore_#{name}!" do
|
54
|
-
locale_accessor =
|
55
|
-
if attribute_changed?(locale_accessor)
|
56
|
-
__send__("#{name}=",
|
83
|
+
locale_accessor = m.append_locale(name)
|
84
|
+
if mutations_from_mobility.attribute_changed?(locale_accessor)
|
85
|
+
__send__("#{name}=", mutations_from_mobility.attribute_was(locale_accessor))
|
86
|
+
mutations_from_mobility.restore_attribute!(locale_accessor)
|
57
87
|
end
|
58
88
|
end
|
59
89
|
end
|
60
90
|
|
91
|
+
# This private method override is necessary to make
|
92
|
+
# +restore_attributes+ (which is public) work with translated
|
93
|
+
# attributes.
|
61
94
|
define_method :restore_attribute! do |attr|
|
62
95
|
attribute_names.include?(attr.to_s) ? send("restore_#{attr}!") : super(attr)
|
63
96
|
end
|
64
97
|
private :restore_attribute!
|
65
98
|
end
|
66
99
|
|
67
|
-
|
68
|
-
|
100
|
+
class << self
|
101
|
+
def handler_methods_module
|
102
|
+
@handler_methods_module ||= (AttributeHandlerMethods.new.tap do |mod|
|
103
|
+
public_method_patterns.each do |pattern|
|
104
|
+
method_name = pattern % 'attribute'
|
105
|
+
|
106
|
+
mod.module_eval <<-EOM, __FILE__, __LINE__ + 1
|
107
|
+
def #{method_name}(attr_name, *rest)
|
108
|
+
if (mutations_from_mobility.attribute_changed?(attr_name) ||
|
109
|
+
mutations_from_mobility.attribute_previously_changed?(attr_name))
|
110
|
+
mutations_from_mobility.send(#{method_name.inspect}, attr_name, *rest)
|
111
|
+
else
|
112
|
+
super
|
113
|
+
end
|
114
|
+
end
|
115
|
+
EOM
|
116
|
+
end
|
117
|
+
end)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Get method suffixes. Creating an object just to get the list of
|
121
|
+
# suffixes is simplest given they change from Rails version to version.
|
122
|
+
def method_patterns
|
123
|
+
@method_patterns ||=
|
124
|
+
(dirty_class.attribute_method_matchers.map { |p| "#{p.prefix}%s#{p.suffix}" } - excluded_method_patterns)
|
125
|
+
end
|
126
|
+
|
127
|
+
def public_method_patterns
|
128
|
+
@public_method_patterns ||= method_patterns.select do |p|
|
129
|
+
!dirty_class.private_instance_methods.include?(:"#{p % 'attribute'}")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def dirty_class
|
134
|
+
@dirty_class ||= Class.new { include ::ActiveModel::Dirty }
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def excluded_method_patterns
|
140
|
+
['%s', 'restore_%s!']
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
module InstanceMethods
|
146
|
+
def changed_attributes
|
147
|
+
super.merge(mutations_from_mobility.changed_attributes)
|
148
|
+
end
|
149
|
+
|
150
|
+
def changes_applied
|
151
|
+
super
|
152
|
+
mutations_from_mobility.finalize_changes
|
153
|
+
end
|
154
|
+
|
155
|
+
def changes
|
156
|
+
super.merge(mutations_from_mobility.changes)
|
157
|
+
end
|
158
|
+
|
159
|
+
def changed
|
160
|
+
# uniq is required for Rails < 6.0
|
161
|
+
(super + mutations_from_mobility.changed).uniq
|
162
|
+
end
|
163
|
+
|
164
|
+
def changed?
|
165
|
+
super || mutations_from_mobility.changed?
|
166
|
+
end
|
167
|
+
|
168
|
+
def previous_changes
|
169
|
+
super.merge(mutations_from_mobility.previous_changes)
|
170
|
+
end
|
171
|
+
|
172
|
+
def clear_changes_information
|
173
|
+
@mutations_from_mobility = nil
|
174
|
+
super
|
175
|
+
end
|
176
|
+
|
177
|
+
def clear_attribute_changes(attr_names)
|
178
|
+
attr_names.each { |attr_name| mutations_from_mobility.restore_attribute!(attr_name) }
|
179
|
+
super
|
69
180
|
end
|
70
181
|
|
71
182
|
private
|
72
183
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
184
|
+
def mutations_from_mobility
|
185
|
+
@mutations_from_mobility ||= MobilityMutationTracker.new(self)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Give the module builder a name so it's easier to see in the model's ancestors
|
190
|
+
class AttributeHandlerMethods < Module; end
|
191
|
+
|
192
|
+
class MobilityMutationTracker
|
193
|
+
OPTION_NOT_GIVEN = Object.new
|
194
|
+
|
195
|
+
attr_reader :previous_changes
|
196
|
+
|
197
|
+
def initialize(model)
|
198
|
+
@model = model
|
199
|
+
@current_changes = {}.with_indifferent_access
|
200
|
+
@previous_changes = {}.with_indifferent_access
|
201
|
+
end
|
202
|
+
|
203
|
+
def finalize_changes
|
204
|
+
@previous_changes = changes
|
205
|
+
@current_changes = {}.with_indifferent_access
|
206
|
+
end
|
207
|
+
|
208
|
+
def changed
|
209
|
+
attr_names.select { |attr_name| attribute_changed?(attr_name) }
|
210
|
+
end
|
211
|
+
|
212
|
+
def changed_attributes
|
213
|
+
attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
|
214
|
+
if attribute_changed?(attr_name)
|
215
|
+
result[attr_name] = attribute_was(attr_name)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def changes
|
221
|
+
attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
|
222
|
+
if change = attribute_change(attr_name)
|
223
|
+
result.merge!(attr_name => change)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def changed?
|
229
|
+
attr_names.any? { |attr| attribute_changed?(attr) }
|
230
|
+
end
|
231
|
+
|
232
|
+
def attribute_change(attr_name)
|
233
|
+
if attribute_changed?(attr_name)
|
234
|
+
[attribute_was(attr_name), fetch_value(attr_name)]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def attribute_previous_change(attr_name)
|
239
|
+
previous_changes[attr_name]
|
240
|
+
end
|
90
241
|
|
91
|
-
|
92
|
-
|
242
|
+
def attribute_previously_was(attr_name)
|
243
|
+
if attribute_previously_changed?(attr_name)
|
244
|
+
# Calling +first+ here fetches the value before change from the
|
245
|
+
# hash.
|
246
|
+
previous_changes[attr_name].first
|
93
247
|
end
|
94
248
|
end
|
249
|
+
|
250
|
+
def attribute_changed?(attr_name, from: OPTION_NOT_GIVEN, to: OPTION_NOT_GIVEN)
|
251
|
+
current_changes.include?(attr_name) &&
|
252
|
+
(OPTION_NOT_GIVEN == from || attribute_was(attr_name) == from) &&
|
253
|
+
(OPTION_NOT_GIVEN == to || fetch_value(attr_name) == to)
|
254
|
+
end
|
255
|
+
|
256
|
+
def attribute_previously_changed?(attr_name)
|
257
|
+
previous_changes.include?(attr_name)
|
258
|
+
end
|
259
|
+
|
260
|
+
def attribute_was(attr_name)
|
261
|
+
if attribute_changed?(attr_name)
|
262
|
+
current_changes[attr_name]
|
263
|
+
else
|
264
|
+
fetch_value(attr_name)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def attribute_will_change!(attr_name)
|
269
|
+
current_changes[attr_name] = fetch_value(attr_name) unless current_changes.include?(attr_name)
|
270
|
+
end
|
271
|
+
|
272
|
+
def restore_attribute!(attr_name)
|
273
|
+
current_changes.delete(attr_name)
|
274
|
+
end
|
275
|
+
|
276
|
+
# These are for ActiveRecord, but we'll define them here.
|
277
|
+
alias_method :saved_change_to_attribute?, :attribute_previously_changed?
|
278
|
+
alias_method :saved_change_to_attribute, :attribute_previous_change
|
279
|
+
alias_method :attribute_before_last_save, :attribute_previously_was
|
280
|
+
alias_method :will_save_change_to_attribute?, :attribute_changed?
|
281
|
+
alias_method :attribute_change_to_be_saved, :attribute_change
|
282
|
+
alias_method :attribute_in_database, :attribute_was
|
283
|
+
|
284
|
+
private
|
285
|
+
attr_reader :model, :current_changes
|
286
|
+
|
287
|
+
def attr_names
|
288
|
+
current_changes.keys
|
289
|
+
end
|
290
|
+
|
291
|
+
def fetch_value(attr_name)
|
292
|
+
model.__send__(attr_name)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
module BackendMethods
|
297
|
+
# @!group Backend Accessors
|
298
|
+
# @!macro backend_writer
|
299
|
+
# @param [Hash] options
|
300
|
+
def write(locale, value, options = {})
|
301
|
+
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale)
|
302
|
+
if model.changed_attributes.has_key?(locale_accessor) && model.changed_attributes[locale_accessor] == value
|
303
|
+
mutations_from_mobility.restore_attribute!(locale_accessor)
|
304
|
+
elsif read(locale, options.merge(locale: true)) != value
|
305
|
+
mutations_from_mobility.attribute_will_change!(locale_accessor)
|
306
|
+
end
|
307
|
+
super
|
308
|
+
end
|
309
|
+
# @!endgroup
|
310
|
+
|
311
|
+
private
|
312
|
+
|
313
|
+
def mutations_from_mobility
|
314
|
+
model.send(:mutations_from_mobility)
|
315
|
+
end
|
95
316
|
end
|
96
317
|
end
|
97
318
|
end
|
@@ -12,7 +12,6 @@ details on usage.
|
|
12
12
|
In addition to methods added by {Mobility::Plugins::ActiveModel::Dirty}, the
|
13
13
|
AR::Dirty plugin adds support for the following persistence-specific methods
|
14
14
|
(for a model with a translated attribute +title+):
|
15
|
-
- +saved_changes+
|
16
15
|
- +saved_change_to_title?+
|
17
16
|
- +saved_change_to_title+
|
18
17
|
- +title_before_last_save+
|
@@ -20,128 +19,83 @@ AR::Dirty plugin adds support for the following persistence-specific methods
|
|
20
19
|
- +title_change_to_be_saved+
|
21
20
|
- +title_in_database+
|
22
21
|
|
22
|
+
The following methods are also patched to include translated attribute changes:
|
23
|
+
- +saved_changes+
|
24
|
+
- +has_changes_to_save?+
|
25
|
+
- +changes_to_save+
|
26
|
+
- +changed_attribute_names_to_save+
|
27
|
+
- +attributes_in_database+
|
28
|
+
|
29
|
+
In addition, the following ActiveModel attribute handler methods are also
|
30
|
+
patched to work with translated attributes:
|
31
|
+
- +saved_change_to_attribute?+
|
32
|
+
- +saved_change_to_attribute+
|
33
|
+
- +attribute_before_last_save+
|
34
|
+
- +will_save_change_to_attribute?+
|
35
|
+
- +attribute_change_to_be_saved+
|
36
|
+
- +attribute_in_database+
|
37
|
+
|
38
|
+
(When using these methods, you must pass the attribute name along with its
|
39
|
+
locale suffix, so +title_en+, +title_pt_br+, etc.)
|
40
|
+
|
23
41
|
=end
|
24
42
|
module Dirty
|
25
|
-
include ActiveModel::Dirty
|
26
|
-
|
27
|
-
# Builds module which patches a few AR methods to handle changes to
|
28
|
-
# translated attributes just like normal attributes.
|
29
43
|
class MethodsBuilder < ActiveModel::Dirty::MethodsBuilder
|
30
|
-
def initialize(*attribute_names)
|
31
|
-
super
|
32
|
-
@attribute_names = attribute_names
|
33
|
-
define_method_overrides if ::ActiveRecord::VERSION::STRING < '5.2'
|
34
|
-
define_attribute_methods if ::ActiveRecord::VERSION::STRING >= '5.1'
|
35
|
-
end
|
36
|
-
|
37
|
-
# Overrides +ActiveRecord::AttributeMethods::ClassMethods#has_attribute+ (in AR 5.1) and
|
38
|
-
# +ActiveModel::AttributeMethods#_read_attribute+ (in AR >= 5.2) to
|
39
|
-
# ensure that fallthrough attribute methods are treated like "real"
|
40
|
-
# attribute methods.
|
41
|
-
#
|
42
|
-
# @note Patching +has_attribute?+ is necessary in AR 5.1 due to this commit[https://github.com/rails/rails/commit/4fed08fa787a316fa51f14baca9eae11913f5050].
|
43
44
|
# @param [Attributes] attributes
|
44
45
|
def included(model_class)
|
45
46
|
super
|
46
47
|
|
47
|
-
|
48
|
-
names = @attribute_names
|
49
|
-
method_name_regex = /\A(#{names.join('|')})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
50
|
-
has_attribute = Module.new do
|
51
|
-
define_method :has_attribute? do |attr_name|
|
52
|
-
super(attr_name) || (String === attr_name && !!method_name_regex.match(attr_name))
|
53
|
-
end
|
54
|
-
end
|
55
|
-
model_class.extend has_attribute
|
56
|
-
elsif ::ActiveRecord::VERSION::STRING >= '5.2'
|
57
|
-
model_class.include ReadAttribute
|
58
|
-
end
|
48
|
+
model_class.include InstanceMethods
|
59
49
|
end
|
60
50
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
51
|
+
class << self
|
52
|
+
def dirty_class
|
53
|
+
@dirty_class ||= (Class.new do
|
54
|
+
# In earlier versions of Rails, these are needed to avoid an
|
55
|
+
# exception when including the AR Dirty module outside of an
|
56
|
+
# AR::Base class. Eventually we should be able to drop them.
|
57
|
+
def self.after_create; end
|
58
|
+
def self.after_update; end
|
59
|
+
|
60
|
+
include ::ActiveRecord::AttributeMethods::Dirty
|
61
|
+
end)
|
71
62
|
end
|
63
|
+
end
|
64
|
+
end
|
72
65
|
|
73
|
-
|
74
|
-
|
75
|
-
|
66
|
+
module InstanceMethods
|
67
|
+
if ::ActiveRecord::VERSION::STRING >= '5.1' # define patterns added in 5.1
|
68
|
+
def saved_changes
|
69
|
+
super.merge(mutations_from_mobility.previous_changes)
|
76
70
|
end
|
77
71
|
|
78
|
-
|
79
|
-
|
72
|
+
def changes_to_save
|
73
|
+
super.merge(mutations_from_mobility.changes)
|
80
74
|
end
|
81
|
-
end
|
82
75
|
|
83
|
-
|
84
|
-
|
85
|
-
define_method :saved_changes do
|
86
|
-
(@previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new).merge(super())
|
76
|
+
def changed_attribute_names_to_save
|
77
|
+
super + mutations_from_mobility.changed
|
87
78
|
end
|
88
79
|
|
89
|
-
|
90
|
-
|
91
|
-
previous_changes.include?(Mobility.normalize_locale_accessor(name))
|
92
|
-
end
|
93
|
-
|
94
|
-
define_method :"saved_change_to_#{name}" do
|
95
|
-
previous_changes[Mobility.normalize_locale_accessor(name)]
|
96
|
-
end
|
97
|
-
|
98
|
-
define_method :"#{name}_before_last_save" do
|
99
|
-
previous_changes[Mobility.normalize_locale_accessor(name)].first
|
100
|
-
end
|
101
|
-
|
102
|
-
alias_method :"will_save_change_to_#{name}?", :"#{name}_changed?"
|
103
|
-
alias_method :"#{name}_change_to_be_saved", :"#{name}_change"
|
104
|
-
alias_method :"#{name}_in_database", :"#{name}_was"
|
80
|
+
def attributes_in_database
|
81
|
+
super.merge(mutations_from_mobility.changed_attributes)
|
105
82
|
end
|
106
|
-
end
|
107
83
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
#
|
112
|
-
# For background on why this is necessary, see:
|
113
|
-
# https://github.com/shioyama/mobility/issues/115
|
114
|
-
module ReadAttribute
|
115
|
-
# @note We first check if attributes has the key +attr+ to avoid
|
116
|
-
# doing any extra work in case this is a "normal"
|
117
|
-
# (non-translated) attribute.
|
118
|
-
def _read_attribute(attr, *args)
|
119
|
-
if @attributes.key?(attr)
|
120
|
-
super
|
121
|
-
else
|
122
|
-
mobility_changed_attributes.include?(attr) ? __send__(attr) : super
|
84
|
+
if ::ActiveRecord::VERSION::STRING >= '6.0'
|
85
|
+
def has_changes_to_save?
|
86
|
+
super || mutations_from_mobility.changed?
|
123
87
|
end
|
124
88
|
end
|
89
|
+
end
|
125
90
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
# be cases where @attributes has been set, but there are *other*
|
130
|
-
# changes on virtual translated attributes which need to also be
|
131
|
-
# assigned. In this case, we use the presence of such changed
|
132
|
-
# virtual attributes as an alternative trigger to set this variable.
|
133
|
-
#
|
134
|
-
# See:
|
135
|
-
# - https://github.com/rails/rails/commit/e126078a0e013acfe0a397a8dad33b2c9de78732
|
136
|
-
# - https://github.com/shioyama/mobility/pull/166
|
137
|
-
def changes_applied
|
138
|
-
if defined?(@attributes) && mobility_changed_attributes.any?
|
139
|
-
@previously_changed = changes
|
140
|
-
end
|
141
|
-
super
|
91
|
+
def reload(*)
|
92
|
+
super.tap do
|
93
|
+
@mutations_from_mobility = nil
|
142
94
|
end
|
143
95
|
end
|
144
96
|
end
|
97
|
+
|
98
|
+
BackendMethods = ActiveModel::Dirty::BackendMethods
|
145
99
|
end
|
146
100
|
end
|
147
101
|
end
|
@@ -50,7 +50,7 @@ details.
|
|
50
50
|
else
|
51
51
|
raise ArgumentError, "#{model_class} does not support Dirty module."
|
52
52
|
end
|
53
|
-
backend_class.include dirty_module
|
53
|
+
backend_class.include dirty_module.const_get(:BackendMethods)
|
54
54
|
model_class.include dirty_module.const_get(:MethodsBuilder).new(*attribute_names)
|
55
55
|
end
|
56
56
|
end
|
@@ -13,21 +13,6 @@ Automatically includes dirty plugin in model class when enabled.
|
|
13
13
|
=end
|
14
14
|
module Sequel
|
15
15
|
module Dirty
|
16
|
-
# @!group Backend Accessors
|
17
|
-
# @!macro backend_writer
|
18
|
-
# @param [Hash] options
|
19
|
-
def write(locale, value, options = {})
|
20
|
-
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale).to_sym
|
21
|
-
if model.column_changes.has_key?(locale_accessor) && model.initial_values[locale_accessor] == value
|
22
|
-
super
|
23
|
-
[model.changed_columns, model.initial_values].each { |h| h.delete(locale_accessor) }
|
24
|
-
elsif read(locale, options.merge(fallback: false)) != value
|
25
|
-
model.will_change_column(locale_accessor)
|
26
|
-
super
|
27
|
-
end
|
28
|
-
end
|
29
|
-
# @!endgroup
|
30
|
-
|
31
16
|
# Builds module which overrides dirty methods to handle translated as
|
32
17
|
# well as normal (untranslated) attributes.
|
33
18
|
class MethodsBuilder < Module
|
@@ -53,6 +38,23 @@ Automatically includes dirty plugin in model class when enabled.
|
|
53
38
|
model_class.plugin :dirty
|
54
39
|
end
|
55
40
|
end
|
41
|
+
|
42
|
+
module BackendMethods
|
43
|
+
# @!group Backend Accessors
|
44
|
+
# @!macro backend_writer
|
45
|
+
# @param [Hash] options
|
46
|
+
def write(locale, value, options = {})
|
47
|
+
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale).to_sym
|
48
|
+
if model.column_changes.has_key?(locale_accessor) && model.initial_values[locale_accessor] == value
|
49
|
+
super
|
50
|
+
[model.changed_columns, model.initial_values].each { |h| h.delete(locale_accessor) }
|
51
|
+
elsif read(locale, options.merge(fallback: false)) != value
|
52
|
+
model.will_change_column(locale_accessor)
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
# @!endgroup
|
57
|
+
end
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
data/lib/mobility/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mobility
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Salzberg
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
cbyauX5dx2EyKhuidQ7l3jDOcpFUDWeaqqZllz/0i2LFBILAlYRy82zaspW5k6g3
|
36
36
|
YL4OF4e7t6EeQyBoILL36f8LpD9odUTRdNruhmuEtoQ+kchZ
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2019-
|
38
|
+
date: 2019-10-25 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: request_store
|
metadata.gz.sig
CHANGED
Binary file
|