mobility 0.8.11 → 1.0.0.rc1
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 +69 -1
- data/Gemfile +50 -18
- data/Gemfile.lock +32 -75
- data/README.md +184 -92
- data/Rakefile +6 -4
- data/lib/mobility.rb +100 -168
- data/lib/mobility/backend.rb +27 -51
- data/lib/mobility/backends.rb +20 -0
- data/lib/mobility/backends/active_record.rb +4 -0
- data/lib/mobility/backends/active_record/column.rb +3 -1
- data/lib/mobility/backends/active_record/container.rb +10 -11
- data/lib/mobility/backends/active_record/hstore.rb +6 -4
- data/lib/mobility/backends/active_record/json.rb +5 -3
- data/lib/mobility/backends/active_record/jsonb.rb +5 -3
- data/lib/mobility/backends/active_record/key_value.rb +31 -13
- data/lib/mobility/backends/active_record/pg_hash.rb +1 -1
- data/lib/mobility/backends/active_record/serialized.rb +6 -0
- data/lib/mobility/backends/active_record/table.rb +17 -10
- data/lib/mobility/backends/column.rb +0 -6
- data/lib/mobility/backends/container.rb +10 -1
- data/lib/mobility/backends/hash.rb +39 -0
- data/lib/mobility/backends/hash_valued.rb +4 -0
- data/lib/mobility/backends/hstore.rb +0 -1
- data/lib/mobility/backends/json.rb +0 -1
- data/lib/mobility/backends/jsonb.rb +1 -2
- data/lib/mobility/backends/key_value.rb +31 -26
- data/lib/mobility/backends/null.rb +2 -0
- data/lib/mobility/backends/sequel.rb +37 -2
- data/lib/mobility/backends/sequel/column.rb +2 -0
- data/lib/mobility/backends/sequel/container.rb +11 -9
- data/lib/mobility/backends/sequel/hstore.rb +3 -1
- data/lib/mobility/backends/sequel/json.rb +3 -0
- data/lib/mobility/backends/sequel/jsonb.rb +3 -1
- data/lib/mobility/backends/sequel/key_value.rb +87 -18
- data/lib/mobility/backends/sequel/pg_hash.rb +6 -6
- data/lib/mobility/backends/sequel/serialized.rb +6 -0
- data/lib/mobility/backends/sequel/table.rb +22 -9
- data/lib/mobility/backends/serialized.rb +1 -3
- data/lib/mobility/backends/table.rb +39 -31
- data/lib/mobility/pluggable.rb +56 -0
- data/lib/mobility/plugin.rb +260 -0
- data/lib/mobility/plugins.rb +27 -24
- 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 +119 -78
- data/lib/mobility/plugins/active_record.rb +37 -0
- data/lib/mobility/plugins/active_record/backend.rb +27 -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/arel.rb +125 -0
- data/lib/mobility/plugins/arel/nodes.rb +15 -0
- data/lib/mobility/plugins/arel/nodes/pg_ops.rb +134 -0
- data/lib/mobility/plugins/attribute_methods.rb +29 -20
- data/lib/mobility/plugins/attributes.rb +72 -0
- data/lib/mobility/plugins/backend.rb +161 -0
- data/lib/mobility/plugins/backend_reader.rb +34 -0
- data/lib/mobility/plugins/cache.rb +68 -26
- data/lib/mobility/plugins/default.rb +22 -17
- data/lib/mobility/plugins/dirty.rb +12 -33
- data/lib/mobility/plugins/fallbacks.rb +52 -44
- data/lib/mobility/plugins/fallthrough_accessors.rb +25 -25
- data/lib/mobility/plugins/locale_accessors.rb +22 -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 +34 -23
- 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 +96 -78
- metadata +31 -42
- 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/model_translation.rb +0 -14
- data/lib/mobility/active_record/string_translation.rb +0 -10
- data/lib/mobility/active_record/text_translation.rb +0 -10
- data/lib/mobility/active_record/translation.rb +0 -14
- data/lib/mobility/active_record/uniqueness_validator.rb +0 -60
- data/lib/mobility/arel.rb +0 -49
- data/lib/mobility/arel/nodes.rb +0 -13
- data/lib/mobility/arel/nodes/pg_ops.rb +0 -132
- data/lib/mobility/arel/visitor.rb +0 -61
- 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/sequel/column_changes.rb +0 -28
- data/lib/mobility/sequel/hash_initializer.rb +0 -21
- data/lib/mobility/sequel/model_translation.rb +0 -20
- data/lib/mobility/sequel/sql.rb +0 -16
- data/lib/mobility/sequel/string_translation.rb +0 -10
- data/lib/mobility/sequel/text_translation.rb +0 -10
- data/lib/mobility/sequel/translation.rb +0 -53
- data/lib/mobility/translates.rb +0 -73
data/lib/mobility/backends.rb
CHANGED
@@ -1,4 +1,24 @@
|
|
1
1
|
module Mobility
|
2
2
|
module Backends
|
3
|
+
@backends = {}
|
4
|
+
|
5
|
+
class << self
|
6
|
+
# @param [Symbol, Object] backend Name of backend to load.
|
7
|
+
def load_backend(name)
|
8
|
+
return name if Module === name || name.nil?
|
9
|
+
|
10
|
+
unless (backend = @backends[name])
|
11
|
+
require "mobility/backends/#{name}"
|
12
|
+
raise LoadError, "backend #{name} did not register itself correctly in Mobility::Backends" unless (backend = @backends[name])
|
13
|
+
end
|
14
|
+
backend
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.register_backend(name, mod)
|
19
|
+
@backends[name] = mod
|
20
|
+
end
|
21
|
+
|
22
|
+
class LoadError < Error; end
|
3
23
|
end
|
4
24
|
end
|
@@ -57,7 +57,7 @@ can be run again to add new attributes or locales.)
|
|
57
57
|
# on model table
|
58
58
|
def self.build_node(attr, locale)
|
59
59
|
model_class.arel_table[Column.column_name_for(attr, locale)]
|
60
|
-
.extend(::
|
60
|
+
.extend(Plugins::Arel::MobilityExpressions)
|
61
61
|
end
|
62
62
|
|
63
63
|
private
|
@@ -73,5 +73,7 @@ can be run again to add new attributes or locales.)
|
|
73
73
|
end.compact
|
74
74
|
end
|
75
75
|
end
|
76
|
+
|
77
|
+
register_backend(:active_record_column, ActiveRecord::Column)
|
76
78
|
end
|
77
79
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "mobility/backends/active_record"
|
3
|
-
require "mobility/
|
3
|
+
require "mobility/backends/container"
|
4
|
+
require "mobility/plugins/arel/nodes/pg_ops"
|
4
5
|
|
5
6
|
module Mobility
|
6
7
|
module Backends
|
@@ -11,11 +12,7 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
|
|
11
12
|
=end
|
12
13
|
class ActiveRecord::Container
|
13
14
|
include ActiveRecord
|
14
|
-
|
15
|
-
# @!method column_name
|
16
|
-
# Returns name of json or jsonb column used to store translations
|
17
|
-
# @return [Symbol] (:translations) Name of translations column
|
18
|
-
option_reader :column_name
|
15
|
+
include Container
|
19
16
|
|
20
17
|
# @!group Backend Accessors
|
21
18
|
#
|
@@ -52,15 +49,15 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
|
|
52
49
|
|
53
50
|
# @param [String] attr Attribute name
|
54
51
|
# @param [Symbol] locale Locale
|
55
|
-
# @return [Mobility::Arel::Nodes::Json,Mobility::Arel::Nodes::Jsonb] Arel
|
52
|
+
# @return [Mobility::Plugins::Arel::Nodes::Json,Mobility::Arel::Nodes::Jsonb] Arel
|
56
53
|
# node for attribute on json or jsonb column
|
57
54
|
def build_node(attr, locale)
|
58
55
|
column = model_class.arel_table[column_name]
|
59
56
|
case column_type
|
60
57
|
when :json
|
61
|
-
Arel::Nodes::JsonContainer.new(column, build_quoted(locale), build_quoted(attr))
|
58
|
+
Plugins::Arel::Nodes::JsonContainer.new(column, build_quoted(locale), build_quoted(attr))
|
62
59
|
when :jsonb
|
63
|
-
Arel::Nodes::JsonbContainer.new(column, build_quoted(locale), build_quoted(attr))
|
60
|
+
Plugins::Arel::Nodes::JsonbContainer.new(column, build_quoted(locale), build_quoted(attr))
|
64
61
|
end
|
65
62
|
end
|
66
63
|
|
@@ -71,7 +68,7 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
|
|
71
68
|
private
|
72
69
|
|
73
70
|
def get_column_type
|
74
|
-
|
71
|
+
model_class.type_for_attribute(options[:column_name].to_s).try(:type).tap do |type|
|
75
72
|
unless %i[json jsonb].include? type
|
76
73
|
raise InvalidColumnType, "#{options[:column_name]} must be a column of type json or jsonb"
|
77
74
|
end
|
@@ -122,7 +119,7 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
|
|
122
119
|
|
123
120
|
class Coder
|
124
121
|
def self.dump(obj)
|
125
|
-
if obj.is_a? Hash
|
122
|
+
if obj.is_a? ::Hash
|
126
123
|
obj.inject({}) do |translations, (locale, value)|
|
127
124
|
value.each do |k, v|
|
128
125
|
(translations[locale] ||= {})[k] = v if v.present?
|
@@ -141,5 +138,7 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
|
|
141
138
|
|
142
139
|
class InvalidColumnType < StandardError; end
|
143
140
|
end
|
141
|
+
|
142
|
+
register_backend(:active_record_container, ActiveRecord::Container)
|
144
143
|
end
|
145
144
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'mobility/backends/active_record/pg_hash'
|
2
|
-
require 'mobility/arel/nodes/pg_ops'
|
2
|
+
require 'mobility/plugins/arel/nodes/pg_ops'
|
3
3
|
|
4
4
|
module Mobility
|
5
5
|
module Backends
|
@@ -18,19 +18,21 @@ Implements the {Mobility::Backends::Hstore} backend for ActiveRecord models.
|
|
18
18
|
|
19
19
|
# @!macro backend_writer
|
20
20
|
def write(locale, value, options = {})
|
21
|
-
super(locale, value && value.to_s, options)
|
21
|
+
super(locale, value && value.to_s, **options)
|
22
22
|
end
|
23
23
|
# @!endgroup
|
24
24
|
|
25
25
|
# @param [String] attr Attribute name
|
26
26
|
# @param [Symbol] locale Locale
|
27
|
-
# @return [Mobility::Arel::Nodes::Hstore] Arel node for value of
|
27
|
+
# @return [Mobility::Plugins::Arel::Nodes::Hstore] Arel node for value of
|
28
28
|
# attribute key on hstore column
|
29
29
|
def self.build_node(attr, locale)
|
30
30
|
column_name = column_affix % attr
|
31
|
-
Arel::Nodes::Hstore.new(model_class.arel_table[column_name], build_quoted(locale))
|
31
|
+
Plugins::Arel::Nodes::Hstore.new(model_class.arel_table[column_name], build_quoted(locale))
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
|
+
|
36
|
+
register_backend(:active_record_hstore, ActiveRecord::Hstore)
|
35
37
|
end
|
36
38
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'mobility/backends/active_record/pg_hash'
|
2
|
-
require 'mobility/arel/nodes/pg_ops'
|
2
|
+
require 'mobility/plugins/arel/nodes/pg_ops'
|
3
3
|
|
4
4
|
module Mobility
|
5
5
|
module Backends
|
@@ -32,13 +32,15 @@ Implements the {Mobility::Backends::Json} backend for ActiveRecord models.
|
|
32
32
|
|
33
33
|
# @param [String] attr Attribute name
|
34
34
|
# @param [Symbol] locale Locale
|
35
|
-
# @return [Mobility::Arel::Nodes::Json] Arel node for value of
|
35
|
+
# @return [Mobility::Plugins::Arel::Nodes::Json] Arel node for value of
|
36
36
|
# attribute key on jsonb column
|
37
37
|
def self.build_node(attr, locale)
|
38
38
|
column_name = column_affix % attr
|
39
|
-
Arel::Nodes::Json.new(model_class.arel_table[column_name], build_quoted(locale))
|
39
|
+
Plugins::Arel::Nodes::Json.new(model_class.arel_table[column_name], build_quoted(locale))
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
43
|
+
|
44
|
+
register_backend(:active_record_json, ActiveRecord::Json)
|
43
45
|
end
|
44
46
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'mobility/backends/active_record/pg_hash'
|
2
|
-
require 'mobility/arel/nodes/pg_ops'
|
2
|
+
require 'mobility/plugins/arel/nodes/pg_ops'
|
3
3
|
|
4
4
|
module Mobility
|
5
5
|
module Backends
|
@@ -32,13 +32,15 @@ Implements the {Mobility::Backends::Jsonb} backend for ActiveRecord models.
|
|
32
32
|
|
33
33
|
# @param [String] attr Attribute name
|
34
34
|
# @param [Symbol] locale Locale
|
35
|
-
# @return [Mobility::Arel::Nodes::Jsonb] Arel node for value of
|
35
|
+
# @return [Mobility::Plugins::Arel::Nodes::Jsonb] Arel node for value of
|
36
36
|
# attribute key on jsonb column
|
37
37
|
def self.build_node(attr, locale)
|
38
38
|
column_name = column_affix % attr
|
39
|
-
Arel::Nodes::Jsonb.new(model_class.arel_table[column_name], build_quoted(locale))
|
39
|
+
Plugins::Arel::Nodes::Jsonb.new(model_class.arel_table[column_name], build_quoted(locale))
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
43
|
+
|
44
|
+
register_backend(:active_record_jsonb, ActiveRecord::Jsonb)
|
43
45
|
end
|
44
46
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
require "mobility/backends/active_record"
|
3
3
|
require "mobility/backends/key_value"
|
4
|
-
require "mobility/active_record/string_translation"
|
5
|
-
require "mobility/active_record/text_translation"
|
6
4
|
|
7
5
|
module Mobility
|
8
6
|
module Backends
|
@@ -37,21 +35,21 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
|
|
37
35
|
super
|
38
36
|
if type = options[:type]
|
39
37
|
options[:association_name] ||= :"#{options[:type]}_translations"
|
40
|
-
options[:class_name] ||=
|
38
|
+
options[:class_name] ||= const_get("#{type.capitalize}Translation")
|
41
39
|
end
|
42
|
-
options[:table_alias_affix] = "#{
|
40
|
+
options[:table_alias_affix] = "#{model_class}_%s_#{options[:association_name]}"
|
43
41
|
rescue NameError
|
44
|
-
raise ArgumentError, "You must define a Mobility::ActiveRecord::#{type.capitalize}Translation class."
|
42
|
+
raise ArgumentError, "You must define a Mobility::Backends::ActiveRecord::KeyValue::#{type.capitalize}Translation class."
|
45
43
|
end
|
46
44
|
# @!endgroup
|
47
45
|
|
48
46
|
# @param [String] attr Attribute name
|
49
47
|
# @param [Symbol] _locale Locale
|
50
|
-
# @return [Mobility::Arel::Attribute] Arel attribute for aliased
|
48
|
+
# @return [Mobility::Plugins::Arel::Attribute] Arel attribute for aliased
|
51
49
|
# translation table value column
|
52
50
|
def build_node(attr, locale)
|
53
51
|
aliased_table = class_name.arel_table.alias(table_alias(attr, locale))
|
54
|
-
Arel::Attribute.new(aliased_table, :value, locale, self,
|
52
|
+
Plugins::Arel::Attribute.new(aliased_table, :value, locale, self, attr.to_sym)
|
55
53
|
end
|
56
54
|
|
57
55
|
# Joins translations using either INNER/OUTER join appropriate to the query.
|
@@ -119,7 +117,7 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
|
|
119
117
|
# The title predicate has a non-nil value, so we can use an INNER JOIN,
|
120
118
|
# whereas we are searching for nil content, which requires an OUTER JOIN.
|
121
119
|
#
|
122
|
-
class Visitor < Arel::Visitor
|
120
|
+
class Visitor < Plugins::Arel::Visitor
|
123
121
|
private
|
124
122
|
|
125
123
|
def visit_Arel_Nodes_Equality(object)
|
@@ -137,11 +135,11 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
|
|
137
135
|
alias :visit_Array :visit_collection
|
138
136
|
|
139
137
|
def visit_Arel_Nodes_Or(object)
|
140
|
-
[object.left, object.right].map(&method(:visit)).compact.inject(
|
138
|
+
[object.left, object.right].map(&method(:visit)).compact.inject(:merge).
|
141
139
|
transform_values { OUTER_JOIN }
|
142
140
|
end
|
143
141
|
|
144
|
-
def
|
142
|
+
def visit_Mobility_Plugins_Arel_Attribute(object)
|
145
143
|
if object.backend_class == backend_class && object.locale == locale
|
146
144
|
{ object.attribute_name => OUTER_JOIN }
|
147
145
|
end
|
@@ -194,8 +192,8 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
|
|
194
192
|
|
195
193
|
# Returns translation for a given locale, or builds one if none is present.
|
196
194
|
# @param [Symbol] locale
|
197
|
-
# @return [Mobility::ActiveRecord::TextTranslation,Mobility::ActiveRecord::StringTranslation]
|
198
|
-
def translation_for(locale,
|
195
|
+
# @return [Mobility::Backends::ActiveRecord::KeyValue::TextTranslation,Mobility::Backends::ActiveRecord::KeyValue::StringTranslation]
|
196
|
+
def translation_for(locale, **)
|
199
197
|
translation = translations.find { |t| t.key == attribute && t.locale == locale.to_s }
|
200
198
|
translation ||= translations.build(locale: locale, key: attribute)
|
201
199
|
translation
|
@@ -205,12 +203,32 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
|
|
205
203
|
def self.included(model_class)
|
206
204
|
model_class.after_destroy do
|
207
205
|
[:string, :text].each do |type|
|
208
|
-
Mobility::ActiveRecord.const_get("#{type.capitalize}Translation").
|
206
|
+
Mobility::Backends::ActiveRecord::KeyValue.const_get("#{type.capitalize}Translation").
|
209
207
|
where(translatable: self).destroy_all
|
210
208
|
end
|
211
209
|
end
|
212
210
|
end
|
213
211
|
end
|
212
|
+
|
213
|
+
class Translation < ::ActiveRecord::Base
|
214
|
+
self.abstract_class = true
|
215
|
+
|
216
|
+
belongs_to :translatable, polymorphic: true, touch: true
|
217
|
+
|
218
|
+
validates :key, presence: true, uniqueness: { scope: [:translatable_id, :translatable_type, :locale], case_sensitive: true }
|
219
|
+
validates :translatable, presence: true
|
220
|
+
validates :locale, presence: true
|
221
|
+
end
|
222
|
+
|
223
|
+
class TextTranslation < Translation
|
224
|
+
self.table_name = "mobility_text_translations"
|
225
|
+
end
|
226
|
+
|
227
|
+
class StringTranslation < Translation
|
228
|
+
self.table_name = "mobility_string_translations"
|
229
|
+
end
|
214
230
|
end
|
231
|
+
|
232
|
+
register_backend(:active_record_key_value, ActiveRecord::KeyValue)
|
215
233
|
end
|
216
234
|
end
|
@@ -30,7 +30,7 @@ Internal class used by ActiveRecord backends backed by a Postgres data type
|
|
30
30
|
|
31
31
|
class Coder
|
32
32
|
def self.dump(obj)
|
33
|
-
if obj.is_a? Hash
|
33
|
+
if obj.is_a? ::Hash
|
34
34
|
obj.inject({}) do |translations, (locale, value)|
|
35
35
|
translations[locale] = value if value.present?
|
36
36
|
translations
|
@@ -30,6 +30,10 @@ Implements {Mobility::Backends::Serialized} backend for ActiveRecord models.
|
|
30
30
|
include ActiveRecord
|
31
31
|
include HashValued
|
32
32
|
|
33
|
+
def self.valid_keys
|
34
|
+
super + [:format]
|
35
|
+
end
|
36
|
+
|
33
37
|
# @!group Backend Configuration
|
34
38
|
# @param (see Backends::Serialized.configure)
|
35
39
|
# @option (see Backends::Serialized.configure)
|
@@ -72,5 +76,7 @@ Implements {Mobility::Backends::Serialized} backend for ActiveRecord models.
|
|
72
76
|
EOM
|
73
77
|
end
|
74
78
|
end
|
79
|
+
|
80
|
+
register_backend(:active_record_serialized, ActiveRecord::Serialized)
|
75
81
|
end
|
76
82
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
require "mobility/backends/active_record"
|
3
3
|
require "mobility/backends/table"
|
4
|
-
require "mobility/active_record/model_translation"
|
5
4
|
|
6
5
|
module Mobility
|
7
6
|
module Backends
|
@@ -101,7 +100,7 @@ columns to that table.
|
|
101
100
|
# @option options [Symbol] subclass_name (:Translation) Name of subclass
|
102
101
|
# to append to model class to generate translation class
|
103
102
|
def configure(options)
|
104
|
-
table_name =
|
103
|
+
table_name = model_class.table_name
|
105
104
|
options[:table_name] ||= "#{table_name.singularize}_translations"
|
106
105
|
options[:foreign_key] ||= table_name.downcase.singularize.camelize.foreign_key
|
107
106
|
if (association_name = options[:association_name]).present?
|
@@ -116,10 +115,10 @@ columns to that table.
|
|
116
115
|
|
117
116
|
# @param [String] attr Attribute name
|
118
117
|
# @param [Symbol] _locale Locale
|
119
|
-
# @return [Mobility::Arel::Attribute] Arel node for column on translation table
|
118
|
+
# @return [Mobility::Plugins::Arel::Attribute] Arel node for column on translation table
|
120
119
|
def build_node(attr, locale)
|
121
120
|
aliased_table = model_class.const_get(subclass_name).arel_table.alias(table_alias(locale))
|
122
|
-
Arel::Attribute.new(aliased_table, attr, locale, self)
|
121
|
+
Plugins::Arel::Attribute.new(aliased_table, attr, locale, self)
|
123
122
|
end
|
124
123
|
|
125
124
|
# Joins translations using either INNER/OUTER join appropriate to the
|
@@ -153,7 +152,7 @@ columns to that table.
|
|
153
152
|
def already_joined?(relation, locale, join_type)
|
154
153
|
if join = get_join(relation, locale)
|
155
154
|
return true if (join_type == Visitor::OUTER_JOIN) || (Visitor::INNER_JOIN === join)
|
156
|
-
relation.joins_values
|
155
|
+
relation.joins_values -= [join]
|
157
156
|
end
|
158
157
|
false
|
159
158
|
end
|
@@ -190,7 +189,7 @@ columns to that table.
|
|
190
189
|
# we need an OUTER JOIN. In the second case, one attribute is matched
|
191
190
|
# against a non-nil value, so we can use an INNER JOIN.
|
192
191
|
#
|
193
|
-
class Visitor < Arel::Visitor
|
192
|
+
class Visitor < Plugins::Arel::Visitor
|
194
193
|
private
|
195
194
|
|
196
195
|
def visit_Arel_Nodes_Equality(object)
|
@@ -227,7 +226,7 @@ columns to that table.
|
|
227
226
|
end
|
228
227
|
end
|
229
228
|
|
230
|
-
def
|
229
|
+
def visit_Mobility_Plugins_Arel_Attribute(object)
|
231
230
|
# We compare table names here to ensure that attributes defined on
|
232
231
|
# different backends but the same table will correctly get an OUTER
|
233
232
|
# join when required. Use options[:table_name] here since we don't
|
@@ -245,7 +244,7 @@ columns to that table.
|
|
245
244
|
if self.const_defined?(subclass_name, false)
|
246
245
|
const_get(subclass_name, false)
|
247
246
|
else
|
248
|
-
const_set(subclass_name, Class.new(
|
247
|
+
const_set(subclass_name, Class.new(Translation))
|
249
248
|
end
|
250
249
|
|
251
250
|
translation_class.table_name = options[:table_name]
|
@@ -265,7 +264,7 @@ columns to that table.
|
|
265
264
|
touch: true
|
266
265
|
|
267
266
|
before_save do
|
268
|
-
required_attributes = self.class.
|
267
|
+
required_attributes = translation_class.attribute_names.select { |name| self.class.mobility_attribute?(name) }
|
269
268
|
send(association_name).destroy_empty_translations(required_attributes)
|
270
269
|
end
|
271
270
|
|
@@ -283,7 +282,7 @@ columns to that table.
|
|
283
282
|
|
284
283
|
# Returns translation for a given locale, or builds one if none is present.
|
285
284
|
# @param [Symbol] locale
|
286
|
-
def translation_for(locale,
|
285
|
+
def translation_for(locale, **)
|
287
286
|
translation = translations.in_locale(locale)
|
288
287
|
translation ||= translations.build(locale: locale)
|
289
288
|
translation
|
@@ -303,6 +302,14 @@ columns to that table.
|
|
303
302
|
destroy(empty_translations) if empty_translations.any?
|
304
303
|
end
|
305
304
|
end
|
305
|
+
|
306
|
+
# Subclassed dynamically to generate translation class.
|
307
|
+
class Translation < ::ActiveRecord::Base
|
308
|
+
self.abstract_class = true
|
309
|
+
validates :locale, presence: true
|
310
|
+
end
|
306
311
|
end
|
312
|
+
|
313
|
+
register_backend(:active_record_table, ActiveRecord::Table)
|
307
314
|
end
|
308
315
|
end
|
@@ -27,8 +27,6 @@ be ignored if set, since it would cause a conflict with column accessors.
|
|
27
27
|
|
28
28
|
=end
|
29
29
|
module Column
|
30
|
-
extend Backend::OrmDelegator
|
31
|
-
|
32
30
|
# Returns name of column where translated attribute is stored
|
33
31
|
# @param [Symbol] locale
|
34
32
|
# @return [String]
|
@@ -44,10 +42,6 @@ be ignored if set, since it would cause a conflict with column accessors.
|
|
44
42
|
normalized_locale = Mobility.normalize_locale(locale)
|
45
43
|
"#{attribute}_#{normalized_locale}".to_sym
|
46
44
|
end
|
47
|
-
|
48
|
-
def self.included(base)
|
49
|
-
base.extend Backend::OrmDelegator
|
50
|
-
end
|
51
45
|
end
|
52
46
|
end
|
53
47
|
end
|
@@ -19,7 +19,16 @@ stored).
|
|
19
19
|
|
20
20
|
=end
|
21
21
|
module Container
|
22
|
-
|
22
|
+
def self.included(backend_class)
|
23
|
+
backend_class.extend ClassMethods
|
24
|
+
backend_class.option_reader :column_name
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
def valid_keys
|
29
|
+
[:column_name]
|
30
|
+
end
|
31
|
+
end
|
23
32
|
end
|
24
33
|
end
|
25
34
|
end
|