mobility 0.8.8 → 0.8.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|