mobility 0.8.13 → 1.0.0.alpha
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 +26 -0
- data/Gemfile +5 -2
- data/Gemfile.lock +79 -8
- data/README.md +183 -91
- data/lib/mobility.rb +40 -166
- data/lib/mobility/arel/nodes/pg_ops.rb +1 -1
- data/lib/mobility/backend.rb +19 -41
- data/lib/mobility/backends.rb +20 -0
- data/lib/mobility/backends/active_record.rb +4 -0
- data/lib/mobility/backends/active_record/column.rb +2 -0
- data/lib/mobility/backends/active_record/container.rb +4 -2
- data/lib/mobility/backends/active_record/hstore.rb +2 -0
- data/lib/mobility/backends/active_record/json.rb +2 -0
- data/lib/mobility/backends/active_record/jsonb.rb +2 -0
- data/lib/mobility/backends/active_record/key_value.rb +5 -3
- data/lib/mobility/backends/active_record/pg_hash.rb +1 -1
- data/lib/mobility/backends/active_record/serialized.rb +2 -0
- data/lib/mobility/backends/active_record/table.rb +5 -3
- data/lib/mobility/backends/column.rb +0 -6
- data/lib/mobility/backends/container.rb +2 -1
- data/lib/mobility/backends/hash.rb +39 -0
- data/lib/mobility/backends/hstore.rb +0 -1
- data/lib/mobility/backends/json.rb +0 -1
- data/lib/mobility/backends/jsonb.rb +0 -1
- data/lib/mobility/backends/key_value.rb +22 -14
- data/lib/mobility/backends/null.rb +2 -0
- data/lib/mobility/backends/sequel.rb +3 -0
- data/lib/mobility/backends/sequel/column.rb +2 -0
- data/lib/mobility/backends/sequel/container.rb +3 -1
- data/lib/mobility/backends/sequel/hstore.rb +2 -0
- data/lib/mobility/backends/sequel/json.rb +2 -0
- data/lib/mobility/backends/sequel/jsonb.rb +3 -1
- data/lib/mobility/backends/sequel/key_value.rb +8 -6
- data/lib/mobility/backends/sequel/serialized.rb +2 -0
- data/lib/mobility/backends/sequel/table.rb +5 -2
- data/lib/mobility/backends/serialized.rb +1 -3
- data/lib/mobility/backends/table.rb +14 -6
- data/lib/mobility/pluggable.rb +36 -0
- data/lib/mobility/plugin.rb +260 -0
- data/lib/mobility/plugins.rb +26 -25
- data/lib/mobility/plugins/active_model.rb +17 -0
- data/lib/mobility/plugins/active_model/cache.rb +26 -0
- data/lib/mobility/plugins/active_model/dirty.rb +112 -77
- data/lib/mobility/plugins/active_record.rb +34 -0
- data/lib/mobility/plugins/active_record/backend.rb +25 -0
- data/lib/mobility/plugins/active_record/cache.rb +28 -0
- data/lib/mobility/plugins/active_record/dirty.rb +34 -17
- data/lib/mobility/plugins/active_record/query.rb +43 -31
- data/lib/mobility/plugins/active_record/uniqueness_validation.rb +60 -0
- data/lib/mobility/plugins/attribute_methods.rb +28 -20
- data/lib/mobility/plugins/attributes.rb +70 -0
- data/lib/mobility/plugins/backend.rb +138 -0
- data/lib/mobility/plugins/backend_reader.rb +34 -0
- data/lib/mobility/plugins/cache.rb +59 -24
- data/lib/mobility/plugins/default.rb +22 -17
- data/lib/mobility/plugins/dirty.rb +12 -33
- data/lib/mobility/plugins/fallbacks.rb +51 -43
- data/lib/mobility/plugins/fallthrough_accessors.rb +20 -23
- data/lib/mobility/plugins/locale_accessors.rb +25 -35
- data/lib/mobility/plugins/presence.rb +28 -21
- data/lib/mobility/plugins/query.rb +8 -17
- data/lib/mobility/plugins/reader.rb +50 -0
- data/lib/mobility/plugins/sequel.rb +34 -0
- data/lib/mobility/plugins/sequel/backend.rb +25 -0
- data/lib/mobility/plugins/sequel/cache.rb +24 -0
- data/lib/mobility/plugins/sequel/dirty.rb +32 -21
- data/lib/mobility/plugins/sequel/query.rb +21 -6
- data/lib/mobility/plugins/writer.rb +44 -0
- data/lib/mobility/translations.rb +95 -0
- data/lib/mobility/version.rb +12 -1
- data/lib/rails/generators/mobility/templates/initializer.rb +95 -77
- metadata +28 -27
- metadata.gz.sig +0 -0
- data/lib/mobility/active_model.rb +0 -4
- data/lib/mobility/active_model/backend_resetter.rb +0 -26
- data/lib/mobility/active_record.rb +0 -23
- data/lib/mobility/active_record/backend_resetter.rb +0 -26
- data/lib/mobility/active_record/uniqueness_validator.rb +0 -60
- data/lib/mobility/attributes.rb +0 -324
- data/lib/mobility/backend/orm_delegator.rb +0 -44
- data/lib/mobility/backend_resetter.rb +0 -50
- data/lib/mobility/configuration.rb +0 -138
- data/lib/mobility/fallbacks.rb +0 -28
- data/lib/mobility/interface.rb +0 -0
- data/lib/mobility/loaded.rb +0 -4
- data/lib/mobility/plugins/active_record/attribute_methods.rb +0 -38
- data/lib/mobility/plugins/cache/translation_cacher.rb +0 -40
- data/lib/mobility/sequel.rb +0 -9
- data/lib/mobility/sequel/backend_resetter.rb +0 -23
- data/lib/mobility/translates.rb +0 -73
@@ -42,106 +42,132 @@ the ActiveRecord dirty plugin for more information.
|
|
42
42
|
|
43
43
|
=end
|
44
44
|
module Dirty
|
45
|
-
|
46
|
-
# attributes so they act like normal dirty-tracked attributes.
|
47
|
-
class MethodsBuilder < Module
|
48
|
-
delegate :dirty_class, :handler_methods_module, :method_patterns, to: :class
|
45
|
+
extend Plugin
|
49
46
|
|
50
|
-
|
51
|
-
|
47
|
+
requires :dirty, include: false
|
48
|
+
|
49
|
+
initialize_hook do
|
50
|
+
if options[:dirty]
|
51
|
+
define_dirty_methods(names)
|
52
|
+
include dirty_handler_methods
|
52
53
|
end
|
54
|
+
end
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
model_class.include handler_methods_module
|
56
|
+
included_hook do |klass, backend_class|
|
57
|
+
raise TypeError, "#{name} should include ActiveModel::Dirty to use the active_model plugin" unless active_model_dirty_class?(klass)
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
59
|
+
if options[:dirty]
|
60
|
+
private_methods = InstanceMethods.instance_methods & klass.private_instance_methods
|
61
|
+
klass.include InstanceMethods
|
62
|
+
klass.class_eval { private(*private_methods) }
|
65
63
|
|
66
|
-
|
67
|
-
Mobility.normalize_locale_accessor(attr_name)
|
64
|
+
backend_class.include BackendMethods
|
68
65
|
end
|
66
|
+
end
|
69
67
|
|
70
|
-
|
68
|
+
private
|
71
69
|
|
72
|
-
|
73
|
-
|
70
|
+
# Overridden in AR::Dirty plugin to define a different HandlerMethods module
|
71
|
+
def dirty_handler_methods
|
72
|
+
HandlerMethods
|
73
|
+
end
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
mutations_from_mobility.send(pattern % 'attribute', m.append_locale(name), *args)
|
79
|
-
end
|
80
|
-
end
|
75
|
+
def active_model_dirty_class?(klass)
|
76
|
+
klass.ancestors.include?(::ActiveModel::Dirty)
|
77
|
+
end
|
81
78
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
79
|
+
def define_dirty_methods(attribute_names)
|
80
|
+
attribute_names.each do |name|
|
81
|
+
dirty_handler_methods.each_pattern(name) do |method_name, attribute_method|
|
82
|
+
define_method(method_name) do |*args|
|
83
|
+
mutations_from_mobility.send(attribute_method, Dirty.append_locale(name), *args)
|
88
84
|
end
|
89
85
|
end
|
90
86
|
|
91
|
-
#
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
private :restore_attribute!
|
98
|
-
end
|
99
|
-
|
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)
|
87
|
+
define_method "restore_#{name}!" do
|
88
|
+
locale_accessor = Dirty.append_locale(name)
|
89
|
+
if mutations_from_mobility.attribute_changed?(locale_accessor)
|
90
|
+
__send__("#{name}=", mutations_from_mobility.attribute_was(locale_accessor))
|
91
|
+
mutations_from_mobility.restore_attribute!(locale_accessor)
|
92
|
+
end
|
118
93
|
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# This private method override is necessary to make
|
97
|
+
# +restore_attributes+ (which is public) work with translated
|
98
|
+
# attributes.
|
99
|
+
define_method :restore_attribute! do |attr|
|
100
|
+
attribute_names.include?(attr.to_s) ? send("restore_#{attr}!") : super(attr)
|
101
|
+
end
|
102
|
+
private :restore_attribute!
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.append_locale(attr_name)
|
106
|
+
Mobility.normalize_locale_accessor(attr_name)
|
107
|
+
end
|
119
108
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
109
|
+
# Module builder which mimics dirty method handlers on a given dirty class.
|
110
|
+
# Used to mimic ActiveModel::Dirty and ActiveRecord::Dirty, which have
|
111
|
+
# similar but slightly different sets of handler methods. Doing it this
|
112
|
+
# way with introspection allows us to support basically all AR/AM
|
113
|
+
# versions without changes here.
|
114
|
+
class HandlerMethodsBuilder < Module
|
115
|
+
attr_reader :klass
|
116
|
+
|
117
|
+
# @param [Class] klass Dirty class to mimic
|
118
|
+
def initialize(klass)
|
119
|
+
@klass = klass
|
120
|
+
define_handler_methods
|
121
|
+
end
|
122
|
+
|
123
|
+
def each_pattern(attr_name)
|
124
|
+
patterns.each do |pattern|
|
125
|
+
yield pattern % attr_name, pattern % 'attribute'
|
125
126
|
end
|
127
|
+
end
|
126
128
|
|
127
|
-
|
128
|
-
|
129
|
-
|
129
|
+
def define_handler_methods
|
130
|
+
public_patterns.each do |pattern|
|
131
|
+
method_name = pattern % 'attribute'
|
132
|
+
|
133
|
+
module_eval <<-EOM, __FILE__, __LINE__ + 1
|
134
|
+
def #{method_name}(attr_name, *rest)
|
135
|
+
if (mutations_from_mobility.attribute_changed?(attr_name) ||
|
136
|
+
mutations_from_mobility.attribute_previously_changed?(attr_name))
|
137
|
+
mutations_from_mobility.send(#{method_name.inspect}, attr_name, *rest)
|
138
|
+
else
|
139
|
+
super
|
140
|
+
end
|
130
141
|
end
|
142
|
+
EOM
|
131
143
|
end
|
144
|
+
end
|
132
145
|
|
133
|
-
|
134
|
-
|
135
|
-
|
146
|
+
# Get method suffixes. Creating an object just to get the list of
|
147
|
+
# suffixes is simplest given they change from Rails version to version.
|
148
|
+
def patterns
|
149
|
+
@patterns ||=
|
150
|
+
(klass.attribute_method_matchers.map { |p| "#{p.prefix}%s#{p.suffix}" } - excluded_patterns)
|
151
|
+
end
|
136
152
|
|
137
|
-
|
153
|
+
private
|
138
154
|
|
139
|
-
|
140
|
-
|
155
|
+
def public_patterns
|
156
|
+
@public_patterns ||= patterns.select do |p|
|
157
|
+
klass.public_method_defined?(p % 'attribute')
|
141
158
|
end
|
142
159
|
end
|
160
|
+
|
161
|
+
def excluded_patterns
|
162
|
+
['%s', 'restore_%s!']
|
163
|
+
end
|
143
164
|
end
|
144
165
|
|
166
|
+
# Module which defines generic handler methods like
|
167
|
+
# +attribute_changed?+ that are patched to work with translated
|
168
|
+
# attributes.
|
169
|
+
HandlerMethods = HandlerMethodsBuilder.new(Class.new { include ::ActiveModel::Dirty })
|
170
|
+
|
145
171
|
module InstanceMethods
|
146
172
|
def changed_attributes
|
147
173
|
super.merge(mutations_from_mobility.changed_attributes)
|
@@ -186,9 +212,16 @@ the ActiveRecord dirty plugin for more information.
|
|
186
212
|
end
|
187
213
|
end
|
188
214
|
|
189
|
-
#
|
190
|
-
|
191
|
-
|
215
|
+
# @note Seriously, I really don't want to reproduce all of
|
216
|
+
# ActiveModel::Dirty here, but having fought with upstream changes
|
217
|
+
# many many times I finally decided it's more future-proof to just
|
218
|
+
# re-implement the stuff we need here, to avoid weird breakage.
|
219
|
+
#
|
220
|
+
# Although this is somewhat ugly, at least it's explicit and since
|
221
|
+
# it's self-defined (rather than hooking into fickle private methods
|
222
|
+
# in Rails), it won't break all of a sudden. We just need to ensure
|
223
|
+
# that specs are up-to-date with the latest weird dirty method
|
224
|
+
# pattern Rails has decided to support.
|
192
225
|
class MobilityMutationTracker
|
193
226
|
OPTION_NOT_GIVEN = Object.new
|
194
227
|
|
@@ -316,5 +349,7 @@ the ActiveRecord dirty plugin for more information.
|
|
316
349
|
end
|
317
350
|
end
|
318
351
|
end
|
352
|
+
|
353
|
+
register_plugin(:active_model_dirty, ActiveModel::Dirty)
|
319
354
|
end
|
320
355
|
end
|
@@ -1,6 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "./active_record/backend"
|
3
|
+
require_relative "./active_record/dirty"
|
4
|
+
require_relative "./active_record/cache"
|
5
|
+
require_relative "./active_record/query"
|
6
|
+
require_relative "./active_record/uniqueness_validation"
|
7
|
+
|
1
8
|
module Mobility
|
9
|
+
=begin
|
10
|
+
|
11
|
+
Plugin for ActiveRecord models.
|
12
|
+
|
13
|
+
=end
|
2
14
|
module Plugins
|
3
15
|
module ActiveRecord
|
16
|
+
extend Plugin
|
17
|
+
|
18
|
+
requires :active_record_backend, include: :after
|
19
|
+
requires :active_record_dirty
|
20
|
+
requires :active_record_cache
|
21
|
+
requires :active_record_query
|
22
|
+
requires :active_record_uniqueness_validation
|
23
|
+
|
24
|
+
included_hook do |klass|
|
25
|
+
unless active_record_class?(klass)
|
26
|
+
name = klass.name || klass.to_s
|
27
|
+
raise TypeError, "#{name} should be a subclass of ActiveRecord::Base to use the active_record plugin"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def active_record_class?(klass)
|
34
|
+
klass < ::ActiveRecord::Base
|
35
|
+
end
|
4
36
|
end
|
37
|
+
|
38
|
+
register_plugin(:active_record, ActiveRecord)
|
5
39
|
end
|
6
40
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Plugins
|
3
|
+
module ActiveRecord
|
4
|
+
module Backend
|
5
|
+
extend Plugin
|
6
|
+
|
7
|
+
requires :backend, include: :before
|
8
|
+
|
9
|
+
def load_backend(backend)
|
10
|
+
if Symbol === backend
|
11
|
+
require "mobility/backends/active_record/#{backend}"
|
12
|
+
Backends.load_backend("active_record_#{backend}".to_sym)
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
rescue LoadError => e
|
17
|
+
raise unless e.message =~ /active_record\/#{backend}/
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
register_plugin(:active_record_backend, ActiveRecord::Backend)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
require "mobility/plugins/active_model/cache"
|
3
|
+
|
4
|
+
module Mobility
|
5
|
+
module Plugins
|
6
|
+
module ActiveRecord
|
7
|
+
=begin
|
8
|
+
|
9
|
+
Resets cache on calls to +reload+, in addition to other AM dirty reset
|
10
|
+
methods.
|
11
|
+
|
12
|
+
=end
|
13
|
+
module Cache
|
14
|
+
extend Plugin
|
15
|
+
|
16
|
+
requires :cache, include: false
|
17
|
+
|
18
|
+
included_hook do |klass, _|
|
19
|
+
if options[:cache]
|
20
|
+
define_cache_hooks(klass, :changes_applied, :clear_changes_information, :reload)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
register_plugin(:active_record_cache, ActiveRecord::Cache)
|
27
|
+
end
|
28
|
+
end
|
@@ -40,29 +40,44 @@ locale suffix, so +title_en+, +title_pt_br+, etc.)
|
|
40
40
|
|
41
41
|
=end
|
42
42
|
module Dirty
|
43
|
-
|
44
|
-
# @param [Attributes] attributes
|
45
|
-
def included(model_class)
|
46
|
-
super
|
43
|
+
extend Plugin
|
47
44
|
|
48
|
-
|
45
|
+
requires :dirty, include: false
|
46
|
+
requires :active_model_dirty, include: :before
|
47
|
+
|
48
|
+
initialize_hook do
|
49
|
+
if options[:dirty]
|
50
|
+
include InstanceMethods
|
49
51
|
end
|
52
|
+
end
|
50
53
|
|
51
|
-
|
52
|
-
|
53
|
-
|
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)
|
62
|
-
end
|
54
|
+
included_hook do |_, backend_class|
|
55
|
+
if options[:dirty]
|
56
|
+
backend_class.include BackendMethods
|
63
57
|
end
|
64
58
|
end
|
65
59
|
|
60
|
+
private
|
61
|
+
|
62
|
+
def dirty_handler_methods
|
63
|
+
HandlerMethods
|
64
|
+
end
|
65
|
+
|
66
|
+
# Module which defines generic ActiveRecord::Dirty handler methods like
|
67
|
+
# +attribute_before_last_save+ that are patched to work with translated
|
68
|
+
# attributes.
|
69
|
+
HandlerMethods = ActiveModel::Dirty::HandlerMethodsBuilder.new(
|
70
|
+
Class.new do
|
71
|
+
# In earlier versions of Rails, these are needed to avoid an
|
72
|
+
# exception when including the AR Dirty module outside of an
|
73
|
+
# AR::Base class. Eventually we should be able to drop them.
|
74
|
+
def self.after_create; end
|
75
|
+
def self.after_update; end
|
76
|
+
|
77
|
+
include ::ActiveRecord::AttributeMethods::Dirty
|
78
|
+
end
|
79
|
+
)
|
80
|
+
|
66
81
|
module InstanceMethods
|
67
82
|
if ::ActiveRecord::VERSION::STRING >= '5.1' # define patterns added in 5.1
|
68
83
|
def saved_changes
|
@@ -98,5 +113,7 @@ locale suffix, so +title_en+, +title_pt_br+, etc.)
|
|
98
113
|
BackendMethods = ActiveModel::Dirty::BackendMethods
|
99
114
|
end
|
100
115
|
end
|
116
|
+
|
117
|
+
register_plugin(:active_record_dirty, ActiveRecord::Dirty)
|
101
118
|
end
|
102
119
|
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
|
+
require "active_record/relation"
|
3
|
+
|
2
4
|
module Mobility
|
3
5
|
module Plugins
|
4
6
|
=begin
|
@@ -15,45 +17,47 @@ enabled for any one attribute on the model.
|
|
15
17
|
=end
|
16
18
|
module ActiveRecord
|
17
19
|
module Query
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
extend Plugin
|
21
|
+
|
22
|
+
requires :query, include: false
|
23
|
+
|
24
|
+
included_hook do |klass, backend_class|
|
25
|
+
plugin = self
|
26
|
+
if options[:query]
|
27
|
+
raise MissingBackend, "backend required for Query plugin" unless backend_class
|
28
|
+
|
29
|
+
klass.class_eval do
|
21
30
|
extend QueryMethod
|
22
|
-
extend FindByMethods.new(*
|
23
|
-
singleton_class.send :alias_method,
|
31
|
+
extend FindByMethods.new(*plugin.names)
|
32
|
+
singleton_class.send :alias_method, plugin.query_method, :__mobility_query_scope__
|
24
33
|
end
|
25
|
-
|
34
|
+
backend_class.include BackendMethods
|
26
35
|
end
|
36
|
+
end
|
27
37
|
|
38
|
+
class << self
|
28
39
|
def attribute_alias(attribute, locale = Mobility.locale)
|
29
40
|
"__mobility_%s_%s__" % [attribute, ::Mobility.normalize_locale(locale)]
|
30
41
|
end
|
31
42
|
end
|
32
43
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
44
|
+
module BackendMethods
|
45
|
+
# @note We use +instance_variable_get+ here to get the +AttributeSet+
|
46
|
+
# rather than the hash of attributes. Getting the full hash of
|
47
|
+
# attributes is a performance hit and better to avoid if unnecessary.
|
48
|
+
# TODO: Improve this.
|
49
|
+
def read(locale, **)
|
50
|
+
if model.instance_variable_defined?(:@attributes) &&
|
51
|
+
(model_attributes = model.instance_variable_get(:@attributes)).key?(alias_ = Query.attribute_alias(attribute, locale))
|
52
|
+
model_attributes[alias_].value
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
43
56
|
end
|
44
57
|
end
|
45
58
|
|
46
|
-
private
|
47
|
-
|
48
|
-
def model_attributes_defined?
|
49
|
-
model.instance_variable_defined?(:@attributes)
|
50
|
-
end
|
51
|
-
|
52
|
-
def model_attributes
|
53
|
-
model.instance_variable_get(:@attributes)
|
54
|
-
end
|
55
|
-
|
56
59
|
module QueryMethod
|
60
|
+
# This is required for UniquenessValidator.
|
57
61
|
def __mobility_query_scope__(locale: Mobility.locale, &block)
|
58
62
|
if block_given?
|
59
63
|
VirtualRow.build_query(self, locale, &block)
|
@@ -121,7 +125,7 @@ enabled for any one attribute on the model.
|
|
121
125
|
case opts
|
122
126
|
when Symbol, String
|
123
127
|
@klass.mobility_attribute?(opts) ? order({ opts => :asc }, *rest) : super
|
124
|
-
when Hash
|
128
|
+
when ::Hash
|
125
129
|
i18n_keys, keys = opts.keys.partition(&@klass.method(:mobility_attribute?))
|
126
130
|
return super if i18n_keys.empty?
|
127
131
|
|
@@ -182,7 +186,7 @@ enabled for any one attribute on the model.
|
|
182
186
|
|
183
187
|
class << self
|
184
188
|
def build(scope, where_opts, invert: false, &block)
|
185
|
-
return yield unless Hash === where_opts
|
189
|
+
return yield unless ::Hash === where_opts
|
186
190
|
|
187
191
|
opts = where_opts.with_indifferent_access
|
188
192
|
locale = opts.delete(:locale) || Mobility.locale
|
@@ -195,11 +199,11 @@ enabled for any one attribute on the model.
|
|
195
199
|
# Builds a translated relation for a given opts hash and optional
|
196
200
|
# invert boolean.
|
197
201
|
def _build(scope, opts, locale, invert)
|
198
|
-
return yield
|
202
|
+
return yield if (mods = attribute_modules(scope)).empty?
|
199
203
|
|
200
204
|
keys, predicates = opts.keys.map(&:to_s), []
|
201
205
|
|
202
|
-
query_map =
|
206
|
+
query_map = mods.inject(IDENTITY) do |qm, mod|
|
203
207
|
i18n_keys = mod.names & keys
|
204
208
|
next qm if i18n_keys.empty?
|
205
209
|
|
@@ -215,7 +219,11 @@ enabled for any one attribute on the model.
|
|
215
219
|
return yield if query_map == IDENTITY
|
216
220
|
|
217
221
|
relation = opts.empty? ? scope : yield(opts)
|
218
|
-
query_map[relation.where(predicates.inject(
|
222
|
+
query_map[relation.where(predicates.inject(:and))]
|
223
|
+
end
|
224
|
+
|
225
|
+
def attribute_modules(scope)
|
226
|
+
scope.model.ancestors.grep(::Mobility::Translations)
|
219
227
|
end
|
220
228
|
|
221
229
|
def build_predicate(node, values)
|
@@ -267,6 +275,10 @@ enabled for any one attribute on the model.
|
|
267
275
|
|
268
276
|
private_constant :QueryExtension, :FindByMethods
|
269
277
|
end
|
278
|
+
|
279
|
+
class MissingBackend < Mobility::Error; end
|
270
280
|
end
|
281
|
+
|
282
|
+
register_plugin(:active_record_query, ActiveRecord::Query)
|
271
283
|
end
|
272
284
|
end
|