mobility 0.1.20 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -0
  4. data/CHANGELOG.md +17 -0
  5. data/CONTRIBUTING.md +55 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +2 -56
  8. data/README.md +64 -15
  9. data/Rakefile +17 -17
  10. data/lib/mobility.rb +43 -40
  11. data/lib/mobility/active_model.rb +0 -1
  12. data/lib/mobility/active_model/backend_resetter.rb +1 -1
  13. data/lib/mobility/active_record.rb +8 -15
  14. data/lib/mobility/active_record/backend_resetter.rb +2 -0
  15. data/lib/mobility/active_record/model_translation.rb +1 -1
  16. data/lib/mobility/active_record/string_translation.rb +2 -0
  17. data/lib/mobility/active_record/text_translation.rb +2 -0
  18. data/lib/mobility/attributes.rb +74 -71
  19. data/lib/mobility/backend.rb +64 -25
  20. data/lib/mobility/backend/orm_delegator.rb +17 -7
  21. data/lib/mobility/backend/stringify_locale.rb +18 -0
  22. data/lib/mobility/backend_resetter.rb +8 -5
  23. data/lib/mobility/backends.rb +4 -0
  24. data/lib/mobility/backends/active_record.rb +20 -0
  25. data/lib/mobility/{backend → backends}/active_record/column.rb +25 -13
  26. data/lib/mobility/{backend → backends}/active_record/column/query_methods.rb +5 -3
  27. data/lib/mobility/backends/active_record/hstore.rb +29 -0
  28. data/lib/mobility/{backend → backends}/active_record/hstore/query_methods.rb +2 -2
  29. data/lib/mobility/{backend → backends}/active_record/jsonb.rb +6 -6
  30. data/lib/mobility/{backend → backends}/active_record/jsonb/query_methods.rb +4 -2
  31. data/lib/mobility/{backend → backends}/active_record/key_value.rb +10 -44
  32. data/lib/mobility/{backend → backends}/active_record/key_value/query_methods.rb +4 -2
  33. data/lib/mobility/{backend/active_record/hash_valued.rb → backends/active_record/pg_hash.rb} +13 -21
  34. data/lib/mobility/{backend → backends}/active_record/query_methods.rb +2 -2
  35. data/lib/mobility/{backend → backends}/active_record/serialized.rb +12 -28
  36. data/lib/mobility/{backend → backends}/active_record/serialized/query_methods.rb +5 -8
  37. data/lib/mobility/{backend → backends}/active_record/table.rb +11 -60
  38. data/lib/mobility/{backend → backends}/active_record/table/query_methods.rb +5 -3
  39. data/lib/mobility/{backend → backends}/column.rb +8 -4
  40. data/lib/mobility/backends/hash_valued.rb +29 -0
  41. data/lib/mobility/{backend → backends}/hstore.rb +4 -4
  42. data/lib/mobility/{backend → backends}/jsonb.rb +4 -4
  43. data/lib/mobility/backends/key_value.rb +111 -0
  44. data/lib/mobility/{backend → backends}/null.rb +4 -4
  45. data/lib/mobility/backends/sequel.rb +20 -0
  46. data/lib/mobility/backends/sequel/column.rb +52 -0
  47. data/lib/mobility/{backend → backends}/sequel/column/query_methods.rb +5 -3
  48. data/lib/mobility/backends/sequel/hstore.rb +29 -0
  49. data/lib/mobility/{backend → backends}/sequel/hstore/query_methods.rb +4 -3
  50. data/lib/mobility/{backend → backends}/sequel/jsonb.rb +6 -6
  51. data/lib/mobility/{backend → backends}/sequel/jsonb/query_methods.rb +4 -3
  52. data/lib/mobility/{backend → backends}/sequel/key_value.rb +28 -39
  53. data/lib/mobility/{backend → backends}/sequel/key_value/query_methods.rb +4 -5
  54. data/lib/mobility/backends/sequel/pg_hash.rb +46 -0
  55. data/lib/mobility/{backend → backends}/sequel/postgres_query_methods.rb +1 -2
  56. data/lib/mobility/{backend → backends}/sequel/query_methods.rb +6 -4
  57. data/lib/mobility/{backend → backends}/sequel/serialized.rb +17 -38
  58. data/lib/mobility/backends/sequel/serialized/query_methods.rb +17 -0
  59. data/lib/mobility/{backend → backends}/sequel/table.rb +29 -60
  60. data/lib/mobility/{backend → backends}/sequel/table/query_methods.rb +5 -3
  61. data/lib/mobility/{backend → backends}/serialized.rb +27 -5
  62. data/lib/mobility/{backend → backends}/table.rb +69 -29
  63. data/lib/mobility/configuration.rb +40 -0
  64. data/lib/mobility/{orm.rb → loaded.rb} +0 -0
  65. data/lib/mobility/plugins.rb +35 -0
  66. data/lib/mobility/plugins/active_model.rb +6 -0
  67. data/lib/mobility/plugins/active_model/dirty.rb +81 -0
  68. data/lib/mobility/plugins/active_record.rb +6 -0
  69. data/lib/mobility/plugins/active_record/dirty.rb +59 -0
  70. data/lib/mobility/plugins/cache.rb +54 -0
  71. data/lib/mobility/plugins/cache/translation_cacher.rb +40 -0
  72. data/lib/mobility/plugins/default.rb +73 -0
  73. data/lib/mobility/plugins/dirty.rb +61 -0
  74. data/lib/mobility/{backend → plugins}/fallbacks.rb +36 -31
  75. data/lib/mobility/plugins/fallthrough_accessors.rb +66 -0
  76. data/lib/mobility/plugins/locale_accessors.rb +84 -0
  77. data/lib/mobility/{backend → plugins}/presence.rb +15 -6
  78. data/lib/mobility/plugins/sequel.rb +6 -0
  79. data/lib/mobility/plugins/sequel/dirty.rb +59 -0
  80. data/lib/mobility/sequel.rb +5 -14
  81. data/lib/mobility/sequel/backend_resetter.rb +4 -6
  82. data/lib/mobility/sequel/column_changes.rb +4 -4
  83. data/lib/mobility/sequel/model_translation.rb +1 -1
  84. data/lib/mobility/sequel/string_translation.rb +2 -0
  85. data/lib/mobility/sequel/text_translation.rb +2 -0
  86. data/lib/mobility/translates.rb +1 -5
  87. data/lib/mobility/util.rb +126 -0
  88. data/lib/mobility/version.rb +1 -1
  89. data/lib/mobility/wrapper.rb +1 -1
  90. data/lib/rails/generators/mobility/translations_generator.rb +7 -3
  91. metadata +85 -55
  92. metadata.gz.sig +0 -0
  93. data/lib/mobility/backend/active_model.rb +0 -7
  94. data/lib/mobility/backend/active_model/dirty.rb +0 -95
  95. data/lib/mobility/backend/active_record.rb +0 -29
  96. data/lib/mobility/backend/active_record/dirty.rb +0 -54
  97. data/lib/mobility/backend/active_record/hstore.rb +0 -29
  98. data/lib/mobility/backend/cache.rb +0 -117
  99. data/lib/mobility/backend/dirty.rb +0 -38
  100. data/lib/mobility/backend/key_value.rb +0 -85
  101. data/lib/mobility/backend/sequel.rb +0 -29
  102. data/lib/mobility/backend/sequel/column.rb +0 -39
  103. data/lib/mobility/backend/sequel/dirty.rb +0 -57
  104. data/lib/mobility/backend/sequel/hash_valued.rb +0 -51
  105. data/lib/mobility/backend/sequel/hstore.rb +0 -29
  106. data/lib/mobility/backend/sequel/serialized/query_methods.rb +0 -20
  107. data/lib/mobility/core_ext/object.rb +0 -30
  108. data/lib/mobility/core_ext/string.rb +0 -16
  109. data/lib/mobility/fallthrough_accessors.rb +0 -57
  110. data/lib/mobility/locale_accessors.rb +0 -55
@@ -1,7 +1,9 @@
1
+ require "mobility/backends/sequel/query_methods"
2
+
1
3
  module Mobility
2
- module Backend
4
+ module Backends
3
5
  class Sequel::KeyValue::QueryMethods < Sequel::QueryMethods
4
- def initialize(attributes, association_name: nil, class_name: nil, **_)
6
+ def initialize(attributes, association_name: nil, class_name: nil, **)
5
7
  super
6
8
 
7
9
  define_join_method(association_name, class_name)
@@ -34,9 +36,6 @@ module Mobility
34
36
  end
35
37
 
36
38
  def define_query_methods(association_name)
37
- # TODO: find a better way to do this that doesn't involve overriding
38
- # a private method...
39
- #
40
39
  attributes_extractor = @attributes_extractor
41
40
 
42
41
  %w[exclude or where].each do |method_name|
@@ -0,0 +1,46 @@
1
+ require "mobility/util"
2
+ require "mobility/backends/sequel"
3
+ require "mobility/backends/hash_valued"
4
+ require "mobility/backend/stringify_locale"
5
+
6
+ module Mobility
7
+ module Backends
8
+ =begin
9
+
10
+ Internal class used by Sequel backends backed by a Postgres data type (hstore,
11
+ jsonb).
12
+
13
+ =end
14
+ class Sequel::PgHash
15
+ include Sequel
16
+ include HashValued
17
+ include StringifyLocale
18
+
19
+ # @!macro backend_iterator
20
+ def each_locale
21
+ super { |l| yield l.to_sym }
22
+ end
23
+
24
+ def translations
25
+ model[attribute.to_sym]
26
+ end
27
+
28
+ setup do |attributes|
29
+ method_overrides = Module.new do
30
+ define_method :initialize_set do |values|
31
+ attributes.each { |attribute| self[attribute.to_sym] = {} }
32
+ super(values)
33
+ end
34
+ define_method :before_validation do
35
+ attributes.each do |attribute|
36
+ self[attribute.to_sym].delete_if { |_, v| Util.blank?(v) }
37
+ end
38
+ super()
39
+ end
40
+ end
41
+ include method_overrides
42
+ include Mobility::Sequel::ColumnChanges.new(attributes)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,6 +1,5 @@
1
-
2
1
  module Mobility
3
- module Backend
2
+ module Backends
4
3
  module PostgresQueryMethods
5
4
  private
6
5
 
@@ -1,5 +1,7 @@
1
+ require "mobility/util"
2
+
1
3
  module Mobility
2
- module Backend
4
+ module Backends
3
5
  module Sequel
4
6
  =begin
5
7
 
@@ -9,10 +11,10 @@ models. For details see backend-specific subclasses.
9
11
  =end
10
12
  class QueryMethods < Module
11
13
  # @param [Array<String>] attributes Translated attributes
12
- def initialize(attributes, **_)
13
- @attributes = attributes.map! &:to_sym
14
+ def initialize(attributes, _)
15
+ @attributes = attributes.map!(&:to_sym)
14
16
  @attributes_extractor = lambda do |cond|
15
- cond.is_a?(Hash) && (cond.keys & attributes).presence
17
+ cond.is_a?(Hash) && Util.presence(cond.keys & attributes)
16
18
  end
17
19
  end
18
20
  end
@@ -1,8 +1,12 @@
1
+ require "mobility/backends/sequel"
2
+ require "mobility/backends/hash_valued"
3
+ require "mobility/backends/serialized"
4
+
1
5
  module Mobility
2
- module Backend
6
+ module Backends
3
7
  =begin
4
8
 
5
- Implements {Mobility::Backend::Serialized} backend for Sequel models, using the
9
+ Implements {Mobility::Backends::Serialized} backend for Sequel models, using the
6
10
  Sequel serialization plugin.
7
11
 
8
12
  @see http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/Serialization.html Sequel serialization plugin
@@ -10,7 +14,7 @@ Sequel serialization plugin.
10
14
 
11
15
  @example Define attribute with serialized backend
12
16
  class Post < Sequel::Model
13
- include Mobility
17
+ extend Mobility
14
18
  translates :title, backend: :serialized, format: :yaml
15
19
  end
16
20
 
@@ -23,35 +27,22 @@ Sequel serialization plugin.
23
27
  post.save
24
28
  post.deserialized_values[:title] # get deserialized value
25
29
  #=> {:en=>"foo", :ja=>"あああ"}
26
- post.title_before_mobility # get serialized value
30
+ post.title(super: true) # get serialized value
27
31
  #=> "---\n:en: foo\n:ja: \"あああ\"\n"
28
32
 
29
33
  =end
30
34
  class Sequel::Serialized
31
35
  include Sequel
36
+ include HashValued
32
37
 
33
- require 'mobility/backend/sequel/serialized/query_methods'
34
-
35
- # @!group Backend Accessors
36
- #
37
- # @!macro backend_reader
38
- def read(locale, **_)
39
- translations[locale]
40
- end
41
-
42
- # @!macro backend_reader
43
- def write(locale, value, **_)
44
- translations[locale] = value
45
- end
46
- # @!endgroup
38
+ require 'mobility/backends/sequel/serialized/query_methods'
47
39
 
48
40
  # @!group Backend Configuration
49
- # @option options [Symbol] format (:yaml) Serialization format
50
- # @raise [ArgumentError] if a format other than +:yaml+ or +:json+ is passed in
41
+ # @param (see Backends::Serialized.configure)
42
+ # @option (see Backends::Serialized.configure)
43
+ # @raise (see Backends::Serialized.configure)
51
44
  def self.configure(options)
52
- options[:format] ||= :yaml
53
- options[:format] = options[:format].downcase.to_sym
54
- raise ArgumentError, "Serialized backend only supports yaml or json formats." unless [:yaml, :json].include?(options[:format])
45
+ Serialized.configure(options)
55
46
  end
56
47
  # @!endgroup
57
48
 
@@ -68,7 +59,7 @@ Sequel serialization plugin.
68
59
 
69
60
  method_overrides = Module.new do
70
61
  define_method :initialize_set do |values|
71
- attributes.each { |attribute| send(:"#{attribute}_before_mobility=", {}.send(:"to_#{format}")) }
62
+ attributes.each { |attribute| self[attribute.to_sym] = {}.send(:"to_#{format}") }
72
63
  super(values)
73
64
  end
74
65
  end
@@ -92,24 +83,12 @@ Sequel serialization plugin.
92
83
  end
93
84
  end
94
85
 
95
- # @!group Cache Methods
96
- # @return [Hash]
97
- def new_cache
98
- translations
99
- end
100
-
101
- # @return [Boolean]
102
- def write_to_cache?
103
- true
104
- end
105
- # @!endgroup
106
-
107
86
  # @note The original serialization_modification_detection plugin sets
108
87
  # +@original_deserialized_values+ to be +@deserialized_values+, which
109
88
  # doesn't work. Setting it to a new empty hash seems to work better.
110
89
  module SerializationModificationDetectionFix
111
90
  def after_save
112
- super()
91
+ super
113
92
  @original_deserialized_values = {}
114
93
  end
115
94
  end
@@ -121,7 +100,7 @@ Sequel serialization plugin.
121
100
  end
122
101
 
123
102
  def serialized_value
124
- model.send("#{attribute}_before_mobility")
103
+ model[attribute.to_sym]
125
104
  end
126
105
  end
127
106
  end
@@ -0,0 +1,17 @@
1
+ require "mobility/backends/sequel/query_methods"
2
+
3
+ module Mobility
4
+ module Backends
5
+ class Sequel::Serialized::QueryMethods < Sequel::QueryMethods
6
+ def initialize(attributes, _)
7
+ super
8
+ attributes_extractor = @attributes_extractor
9
+ cond_checker = Backends::Serialized.attr_checker(attributes_extractor)
10
+
11
+ define_method :where do |*cond, &block|
12
+ cond_checker.call(cond.first) || super(*cond, &block)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,14 +1,21 @@
1
+ require "mobility/util"
2
+ require "mobility/backends/sequel"
3
+ require "mobility/backends/key_value"
4
+ require "mobility/sequel/model_translation"
5
+
1
6
  module Mobility
2
- module Backend
7
+ module Backends
3
8
  =begin
4
9
 
5
- Implements the {Mobility::Backend::Table} backend for Sequel models.
10
+ Implements the {Mobility::Backends::Table} backend for Sequel models.
6
11
 
7
12
  =end
8
13
  class Sequel::Table
9
14
  include Sequel
15
+ include Table
16
+ include Util
10
17
 
11
- require 'mobility/backend/sequel/table/query_methods'
18
+ require 'mobility/backends/sequel/table/query_methods'
12
19
 
13
20
  # @return [Symbol] name of the association method
14
21
  attr_reader :association_name
@@ -17,26 +24,13 @@ Implements the {Mobility::Backend::Table} backend for Sequel models.
17
24
  attr_reader :translation_class
18
25
 
19
26
  # @!macro backend_constructor
20
- # @option options [Symbol] association_name Name of association
21
- def initialize(model, attribute, **options)
27
+ def initialize(model, attribute, options = {})
22
28
  super
23
- @association_name = options[:association_name]
24
29
  @translation_class = options[:model_class].const_get(options[:subclass_name])
25
30
  end
26
31
 
27
- # @!group Backend Accessors
28
- # @!macro backend_reader
29
- def read(locale, **_)
30
- translation_for(locale).send(attribute)
31
- end
32
-
33
- # @!macro backend_reader
34
- def write(locale, value, **_)
35
- translation_for(locale).tap { |t| t.send("#{attribute}=", value) }.send(attribute)
36
- end
37
-
38
32
  # @!group Backend Configuration
39
- # @option options [Symbol] association_name (:mobility_model_translations) Name of association method
33
+ # @option options [Symbol] association_name (:translations) Name of association method
40
34
  # @option options [Symbol] table_name Name of translation table
41
35
  # @option options [Symbol] foreign_key Name of foreign key
42
36
  # @option options [Symbol] subclass_name Name of subclass to append to model class to generate translation class
@@ -44,12 +38,12 @@ Implements the {Mobility::Backend::Table} backend for Sequel models.
44
38
  def self.configure(options)
45
39
  raise CacheRequired, "Cache required for Sequel::Table backend" if options[:cache] == false
46
40
  table_name = options[:model_class].table_name
47
- options[:table_name] ||= :"#{table_name.to_s.singularize}_translations"
48
- options[:foreign_key] ||= table_name.to_s.downcase.singularize.camelize.foreign_key
49
- if (association_name = options[:association_name]).present?
50
- options[:subclass_name] ||= association_name.to_s.singularize.camelize
41
+ options[:table_name] ||= :"#{singularize(table_name)}_translations"
42
+ options[:foreign_key] ||= foreign_key(camelize(singularize(table_name.to_s.downcase)))
43
+ if association_name = options[:association_name]
44
+ options[:subclass_name] ||= camelize(singularize(association_name))
51
45
  else
52
- options[:association_name] = :mobility_model_translations
46
+ options[:association_name] = :translations
53
47
  options[:subclass_name] ||= :Translation
54
48
  end
55
49
  %i[table_name foreign_key association_name subclass_name].each { |key| options[key] = options[key].to_sym }
@@ -60,10 +54,6 @@ Implements the {Mobility::Backend::Table} backend for Sequel models.
60
54
  association_name = options[:association_name]
61
55
  subclass_name = options[:subclass_name]
62
56
 
63
- cache_accessor_name = :"__#{association_name}_cache"
64
-
65
- attr_accessor cache_accessor_name
66
-
67
57
  translation_class =
68
58
  if self.const_defined?(subclass_name, false)
69
59
  const_get(subclass_name, false)
@@ -88,9 +78,10 @@ Implements the {Mobility::Backend::Table} backend for Sequel models.
88
78
  callback_methods = Module.new do
89
79
  define_method :after_save do
90
80
  super()
91
- send(cache_accessor_name).each_value do |translation|
92
- translation.id ? translation.save : send("add_#{association_name.to_s.singularize}", translation)
93
- end if send(cache_accessor_name)
81
+ cache_accessor = instance_variable_get(:"@__mobility_#{association_name}_cache")
82
+ cache_accessor.each_value do |translation|
83
+ translation.id ? translation.save : send("add_#{Util.singularize(association_name)}", translation)
84
+ end if cache_accessor
94
85
  end
95
86
  end
96
87
  include callback_methods
@@ -100,42 +91,20 @@ Implements the {Mobility::Backend::Table} backend for Sequel models.
100
91
 
101
92
  setup_query_methods(QueryMethods)
102
93
 
103
- # @!group Cache Methods
104
- # @return [Table::TranslationsCache]
105
- def new_cache
106
- reset_model_cache unless model_cache
107
- model_cache.for(attribute)
108
- end
109
-
110
- # @return [Boolean]
111
- def write_to_cache?
112
- true
113
- end
114
-
115
- def clear_cache
116
- model_cache.clear if model_cache
117
- end
118
- # @!endgroup
119
-
120
- private
121
-
122
- def translation_for(locale)
123
- translation = translations.find { |t| t.locale == locale.to_s }
94
+ def translation_for(locale, _)
95
+ translation = model.send(association_name).find { |t| t.locale == locale.to_s }
124
96
  translation ||= translation_class.new(locale: locale)
125
97
  translation
126
98
  end
127
99
 
128
- def translations
129
- model.send(association_name)
130
- end
100
+ module Cache
101
+ include Table::Cache
131
102
 
132
- def model_cache
133
- model.send(:"__#{association_name}_cache")
134
- end
103
+ private
135
104
 
136
- def reset_model_cache
137
- model.send(:"__#{association_name}_cache=",
138
- Table::TranslationsCache.new { |locale| translation_for(locale) })
105
+ def translations
106
+ (model.send(association_name) + cache.values).uniq
107
+ end
139
108
  end
140
109
 
141
110
  class CacheRequired < ::StandardError; end
@@ -1,5 +1,7 @@
1
+ require "mobility/backends/sequel/query_methods"
2
+
1
3
  module Mobility
2
- module Backend
4
+ module Backends
3
5
  class Sequel::Table::QueryMethods < Sequel::QueryMethods
4
6
  def initialize(attributes, association_name: nil, model_class: nil, subclass_name: nil, **options)
5
7
  super
@@ -15,7 +17,7 @@ module Mobility
15
17
  end
16
18
  end
17
19
 
18
- def define_join_method(association_name, translation_class, table_name: nil, foreign_key: nil, **_)
20
+ def define_join_method(association_name, translation_class, table_name: nil, foreign_key: nil, **)
19
21
  define_method :"join_#{association_name}" do |**options|
20
22
  return self if (@__mobility_table_joined || []).include?(table_name)
21
23
  (@__mobility_table_joined ||= []) << table_name
@@ -29,7 +31,7 @@ module Mobility
29
31
  end
30
32
  end
31
33
 
32
- def define_query_methods(association_name, translation_class, **_)
34
+ def define_query_methods(association_name, translation_class, **)
33
35
  attributes_extractor = @attributes_extractor
34
36
 
35
37
  # See note in AR Table QueryMethods class about limitations of
@@ -1,5 +1,7 @@
1
+ require "mobility/util"
2
+
1
3
  module Mobility
2
- module Backend
4
+ module Backends
3
5
  =begin
4
6
 
5
7
  Stores translations as serialized attributes in a single text column. This
@@ -15,20 +17,31 @@ with the same name as the translated attribute.
15
17
 
16
18
  Format for serialization. Either +:yaml+ (default) or +:json+.
17
19
 
18
- @see Mobility::Backend::ActiveRecord::Serialized
19
- @see Mobility::Backend::Sequel::Serialized
20
+ @see Mobility::Backends::ActiveRecord::Serialized
21
+ @see Mobility::Backends::Sequel::Serialized
20
22
 
21
23
  =end
22
24
  module Serialized
23
- include OrmDelegator
25
+ extend Backend::OrmDelegator
24
26
 
25
27
  class << self
28
+
29
+ # @!group Backend Configuration
30
+ # @option options [Symbol] format (:yaml) Serialization format
31
+ # @raise [ArgumentError] if a format other than +:yaml+ or +:json+ is passed in
32
+ def configure(options)
33
+ options[:format] ||= :yaml
34
+ options[:format] = options[:format].downcase.to_sym
35
+ raise ArgumentError, "Serialized backend only supports yaml or json formats." unless [:yaml, :json].include?(options[:format])
36
+ end
37
+ # @!endgroup
38
+
26
39
  def serializer_for(format)
27
40
  lambda do |obj|
28
41
  return if obj.nil?
29
42
  if obj.is_a? Hash
30
43
  obj = obj.inject({}) do |translations, (locale, value)|
31
- translations[locale] = value.to_s if value.present?
44
+ translations[locale] = value.to_s if Util.present?(value)
32
45
  translations
33
46
  end
34
47
  else
@@ -47,6 +60,15 @@ Format for serialization. Either +:yaml+ (default) or +:json+.
47
60
  lambda { |v| JSON.parse(v, symbolize_names: true) }
48
61
  end
49
62
  end
63
+
64
+ def attr_checker(attributes_extractor)
65
+ lambda do |cond|
66
+ if keys = attributes_extractor.call(cond)
67
+ raise ArgumentError,
68
+ "You cannot query on mobility attributes translated with the Serialized backend (#{keys.join(", ")})."
69
+ end
70
+ end
71
+ end
50
72
  end
51
73
  end
52
74
  end