mobility 0.0.1 → 0.1.0
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
- data/Gemfile +19 -0
- data/Gemfile.lock +153 -0
- data/Guardfile +70 -0
- data/README.md +603 -13
- data/Rakefile +42 -0
- data/lib/generators/mobility/install_generator.rb +45 -0
- data/lib/generators/mobility/templates/create_string_translations.rb +15 -0
- data/lib/generators/mobility/templates/create_text_translations.rb +15 -0
- data/lib/mobility.rb +203 -2
- data/lib/mobility/active_model.rb +6 -0
- data/lib/mobility/active_model/attribute_methods.rb +27 -0
- data/lib/mobility/active_model/backend_resetter.rb +26 -0
- data/lib/mobility/active_record.rb +39 -0
- data/lib/mobility/active_record/backend_resetter.rb +26 -0
- data/lib/mobility/active_record/model_translation.rb +14 -0
- data/lib/mobility/active_record/string_translation.rb +7 -0
- data/lib/mobility/active_record/text_translation.rb +7 -0
- data/lib/mobility/active_record/translation.rb +14 -0
- data/lib/mobility/attributes.rb +210 -0
- data/lib/mobility/backend.rb +152 -0
- data/lib/mobility/backend/active_model.rb +7 -0
- data/lib/mobility/backend/active_model/dirty.rb +84 -0
- data/lib/mobility/backend/active_record.rb +13 -0
- data/lib/mobility/backend/active_record/column.rb +52 -0
- data/lib/mobility/backend/active_record/column/query_methods.rb +40 -0
- data/lib/mobility/backend/active_record/hash_valued.rb +58 -0
- data/lib/mobility/backend/active_record/hstore.rb +36 -0
- data/lib/mobility/backend/active_record/hstore/query_methods.rb +53 -0
- data/lib/mobility/backend/active_record/jsonb.rb +43 -0
- data/lib/mobility/backend/active_record/jsonb/query_methods.rb +53 -0
- data/lib/mobility/backend/active_record/key_value.rb +126 -0
- data/lib/mobility/backend/active_record/key_value/query_methods.rb +63 -0
- data/lib/mobility/backend/active_record/query_methods.rb +36 -0
- data/lib/mobility/backend/active_record/serialized.rb +93 -0
- data/lib/mobility/backend/active_record/serialized/query_methods.rb +32 -0
- data/lib/mobility/backend/active_record/table.rb +197 -0
- data/lib/mobility/backend/active_record/table/query_methods.rb +91 -0
- data/lib/mobility/backend/cache.rb +110 -0
- data/lib/mobility/backend/column.rb +52 -0
- data/lib/mobility/backend/dirty.rb +28 -0
- data/lib/mobility/backend/fallbacks.rb +89 -0
- data/lib/mobility/backend/hstore.rb +21 -0
- data/lib/mobility/backend/jsonb.rb +21 -0
- data/lib/mobility/backend/key_value.rb +71 -0
- data/lib/mobility/backend/null.rb +24 -0
- data/lib/mobility/backend/orm_delegator.rb +33 -0
- data/lib/mobility/backend/sequel.rb +14 -0
- data/lib/mobility/backend/sequel/column.rb +40 -0
- data/lib/mobility/backend/sequel/column/query_methods.rb +24 -0
- data/lib/mobility/backend/sequel/dirty.rb +54 -0
- data/lib/mobility/backend/sequel/hash_valued.rb +51 -0
- data/lib/mobility/backend/sequel/hstore.rb +36 -0
- data/lib/mobility/backend/sequel/hstore/query_methods.rb +42 -0
- data/lib/mobility/backend/sequel/jsonb.rb +43 -0
- data/lib/mobility/backend/sequel/jsonb/query_methods.rb +42 -0
- data/lib/mobility/backend/sequel/key_value.rb +139 -0
- data/lib/mobility/backend/sequel/key_value/query_methods.rb +48 -0
- data/lib/mobility/backend/sequel/query_methods.rb +22 -0
- data/lib/mobility/backend/sequel/serialized.rb +133 -0
- data/lib/mobility/backend/sequel/serialized/query_methods.rb +20 -0
- data/lib/mobility/backend/sequel/table.rb +149 -0
- data/lib/mobility/backend/sequel/table/query_methods.rb +48 -0
- data/lib/mobility/backend/serialized.rb +53 -0
- data/lib/mobility/backend/table.rb +93 -0
- data/lib/mobility/backend_resetter.rb +44 -0
- data/lib/mobility/configuration.rb +31 -0
- data/lib/mobility/core_ext/nil.rb +10 -0
- data/lib/mobility/core_ext/object.rb +19 -0
- data/lib/mobility/core_ext/string.rb +16 -0
- data/lib/mobility/instance_methods.rb +34 -0
- data/lib/mobility/orm.rb +4 -0
- data/lib/mobility/sequel.rb +26 -0
- data/lib/mobility/sequel/backend_resetter.rb +26 -0
- data/lib/mobility/sequel/column_changes.rb +29 -0
- data/lib/mobility/sequel/model_translation.rb +20 -0
- data/lib/mobility/sequel/string_translation.rb +7 -0
- data/lib/mobility/sequel/text_translation.rb +7 -0
- data/lib/mobility/sequel/translation.rb +53 -0
- data/lib/mobility/translates.rb +75 -0
- data/lib/mobility/wrapper.rb +31 -0
- metadata +152 -12
- data/.gitignore +0 -9
- data/.rspec +0 -2
- data/.travis.yml +0 -5
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/mobility.gemspec +0 -32
@@ -0,0 +1,13 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Backend
|
3
|
+
module ActiveRecord
|
4
|
+
autoload :Column, 'mobility/backend/active_record/column'
|
5
|
+
autoload :Hstore, 'mobility/backend/active_record/hstore'
|
6
|
+
autoload :Jsonb, 'mobility/backend/active_record/jsonb'
|
7
|
+
autoload :KeyValue, 'mobility/backend/active_record/key_value'
|
8
|
+
autoload :Serialized, 'mobility/backend/active_record/serialized'
|
9
|
+
autoload :QueryMethods, 'mobility/backend/active_record/query_methods'
|
10
|
+
autoload :Table, 'mobility/backend/active_record/table'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Backend
|
3
|
+
=begin
|
4
|
+
|
5
|
+
Implements the {Mobility::Backend::Column} backend for ActiveRecord models.
|
6
|
+
|
7
|
+
@note This backend disables the +accessor_locales+ option, which would
|
8
|
+
otherwise interfere with column methods.
|
9
|
+
|
10
|
+
@example
|
11
|
+
class Post < ActiveRecord::Base
|
12
|
+
translates :title, backend: :column
|
13
|
+
end
|
14
|
+
|
15
|
+
Mobility.locale = :en
|
16
|
+
post = Post.create(title: "foo")
|
17
|
+
post.title
|
18
|
+
#=> "foo"
|
19
|
+
post.title_en
|
20
|
+
#=> "foo"
|
21
|
+
=end
|
22
|
+
class ActiveRecord::Column
|
23
|
+
include Backend
|
24
|
+
include Mobility::Backend::Column
|
25
|
+
|
26
|
+
autoload :QueryMethods, 'mobility/backend/active_record/column/query_methods'
|
27
|
+
|
28
|
+
# @!group Backend Accessors
|
29
|
+
# @!macro backend_reader
|
30
|
+
# @!method read(locale, **options)
|
31
|
+
|
32
|
+
# @!group Backend Accessors
|
33
|
+
# @!macro backend_writer
|
34
|
+
# @!method write(locale, value, **options)
|
35
|
+
|
36
|
+
# @!group Backend Configuration
|
37
|
+
def self.configure!(options)
|
38
|
+
options[:locale_accessors] = false
|
39
|
+
end
|
40
|
+
# @!endgroup
|
41
|
+
|
42
|
+
setup do |attributes, options|
|
43
|
+
mod = Module.new do
|
44
|
+
define_method :i18n do
|
45
|
+
@mobility_scope ||= super().extending(QueryMethods.new(attributes, options))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
extend mod
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Backend
|
3
|
+
class ActiveRecord::Column::QueryMethods < Backend::ActiveRecord::QueryMethods
|
4
|
+
def initialize(attributes, **options)
|
5
|
+
super
|
6
|
+
attributes_extractor = @attributes_extractor
|
7
|
+
|
8
|
+
define_method :where! do |opts, *rest|
|
9
|
+
if i18n_keys = attributes_extractor.call(opts)
|
10
|
+
opts = opts.with_indifferent_access
|
11
|
+
i18n_keys.each { |attr| opts[Column.column_name_for(attr)] = opts.delete(attr) }
|
12
|
+
end
|
13
|
+
super(opts, *rest)
|
14
|
+
end
|
15
|
+
|
16
|
+
attributes.each do |attribute|
|
17
|
+
define_method :"find_by_#{attribute}" do |value|
|
18
|
+
find_by(Column.column_name_for(attribute) => value)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def extended(relation)
|
24
|
+
super
|
25
|
+
attributes_extractor = @attributes_extractor
|
26
|
+
|
27
|
+
mod = Module.new do
|
28
|
+
define_method :not do |opts, *rest|
|
29
|
+
if i18n_keys = attributes_extractor.call(opts)
|
30
|
+
opts = opts.with_indifferent_access
|
31
|
+
i18n_keys.each { |attr| opts[Column.column_name_for(attr)] = opts.delete(attr) }
|
32
|
+
end
|
33
|
+
super(opts, *rest)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
relation.model.mobility_where_chain.prepend(mod)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Backend
|
3
|
+
=begin
|
4
|
+
|
5
|
+
Internal class used by ActiveRecord backends that store values as a hash.
|
6
|
+
|
7
|
+
=end
|
8
|
+
class ActiveRecord::HashValued
|
9
|
+
include Backend
|
10
|
+
|
11
|
+
# @!group Backend Accessors
|
12
|
+
#
|
13
|
+
# @!macro backend_reader
|
14
|
+
def read(locale, **options)
|
15
|
+
translations[locale]
|
16
|
+
end
|
17
|
+
|
18
|
+
# @!macro backend_writer
|
19
|
+
def write(locale, value, **options)
|
20
|
+
translations[locale] = value
|
21
|
+
end
|
22
|
+
# @!endgroup
|
23
|
+
|
24
|
+
def translations
|
25
|
+
model.read_attribute(attribute)
|
26
|
+
end
|
27
|
+
alias_method :new_cache, :translations
|
28
|
+
|
29
|
+
def write_to_cache?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
setup do |attributes, options|
|
34
|
+
attributes.each { |attribute| store attribute, coder: Coder }
|
35
|
+
before_validation do
|
36
|
+
attributes.each { |attribute| self.send(:"#{attribute}=", {}) if send(attribute).nil? }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Coder
|
41
|
+
def self.dump(obj)
|
42
|
+
if obj.is_a? Hash
|
43
|
+
obj = obj.inject({}) do |translations, (locale, value)|
|
44
|
+
translations[locale] = value if value.present?
|
45
|
+
translations
|
46
|
+
end
|
47
|
+
else
|
48
|
+
raise ArgumentError, "Attribute is supposed to be a Hash, but was a #{obj.class}. -- #{obj.inspect}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.load(obj)
|
53
|
+
obj
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'mobility/backend/active_record/hash_valued'
|
2
|
+
|
3
|
+
module Mobility
|
4
|
+
module Backend
|
5
|
+
=begin
|
6
|
+
|
7
|
+
Implements the {Mobility::Backend::Hstore} backend for ActiveRecord models.
|
8
|
+
|
9
|
+
@see Mobility::Backend::ActiveRecord::HashValued
|
10
|
+
|
11
|
+
=end
|
12
|
+
class ActiveRecord::Hstore < ActiveRecord::HashValued
|
13
|
+
autoload :QueryMethods, 'mobility/backend/active_record/hstore/query_methods'
|
14
|
+
|
15
|
+
# @!group Backend Accessors
|
16
|
+
# @!macro backend_reader
|
17
|
+
# @!method read(locale, **options)
|
18
|
+
|
19
|
+
# @!group Backend Accessors
|
20
|
+
# @!macro backend_writer
|
21
|
+
def write(locale, value, **options)
|
22
|
+
translations[locale] = value && value.to_s
|
23
|
+
end
|
24
|
+
# @!endgroup
|
25
|
+
|
26
|
+
setup do |attributes, options|
|
27
|
+
query_methods = Module.new do
|
28
|
+
define_method :i18n do
|
29
|
+
@mobility_scope ||= super().extending(QueryMethods.new(attributes, options))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
extend query_methods
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Backend
|
3
|
+
class ActiveRecord::Hstore::QueryMethods < ActiveRecord::QueryMethods
|
4
|
+
def initialize(attributes, **options)
|
5
|
+
super
|
6
|
+
attributes_extractor = @attributes_extractor
|
7
|
+
|
8
|
+
define_method :where! do |opts, *rest|
|
9
|
+
if i18n_keys = attributes_extractor.call(opts)
|
10
|
+
locale = Mobility.locale
|
11
|
+
opts = opts.with_indifferent_access
|
12
|
+
|
13
|
+
result = i18n_keys.inject(all) do |scope, attr|
|
14
|
+
value = opts.delete(attr)
|
15
|
+
if value.nil?
|
16
|
+
scope.where.not("#{table_name}.#{attr} ? '#{locale}'")
|
17
|
+
else
|
18
|
+
scope.where!("#{table_name}.#{attr} @> hstore('#{locale}', ?)", value.to_s)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
result = result.where!(opts, *rest) if opts.present?
|
22
|
+
result
|
23
|
+
else
|
24
|
+
super(opts, *rest)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def extended(relation)
|
30
|
+
super
|
31
|
+
attributes_extractor = @attributes_extractor
|
32
|
+
table_name = relation.model.table_name
|
33
|
+
|
34
|
+
mod = Module.new do
|
35
|
+
define_method :not do |opts, *rest|
|
36
|
+
if i18n_keys = attributes_extractor.call(opts)
|
37
|
+
locale = Mobility.locale
|
38
|
+
opts = opts.with_indifferent_access
|
39
|
+
|
40
|
+
i18n_keys.inject(relation) { |scope, attr|
|
41
|
+
scope.where!("#{table_name}.#{attr} ? '#{locale}'").
|
42
|
+
where.not("#{table_name}.#{attr} @> hstore('#{locale}', ?)", opts.delete(attr).to_s)
|
43
|
+
}.where.not(opts, *rest)
|
44
|
+
else
|
45
|
+
super(opts, *rest)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
relation.model.mobility_where_chain.prepend(mod)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'mobility/backend/active_record/hash_valued'
|
2
|
+
|
3
|
+
module Mobility
|
4
|
+
module Backend
|
5
|
+
=begin
|
6
|
+
|
7
|
+
Implements the {Mobility::Backend::Jsonb} backend for ActiveRecord models.
|
8
|
+
|
9
|
+
@see Mobility::Backend::ActiveRecord::HashValued
|
10
|
+
|
11
|
+
=end
|
12
|
+
class ActiveRecord::Jsonb < ActiveRecord::HashValued
|
13
|
+
autoload :QueryMethods, 'mobility/backend/active_record/jsonb/query_methods'
|
14
|
+
|
15
|
+
# @!group Backend Accessors
|
16
|
+
#
|
17
|
+
# @note Translation may be string, integer or boolean-valued since
|
18
|
+
# value is stored on a JSON hash.
|
19
|
+
# @param [Symbol] locale Locale to read
|
20
|
+
# @param [Hash] options
|
21
|
+
# @return [String,Integer,Boolean] Value of translation
|
22
|
+
# @!method read(locale, **options)
|
23
|
+
|
24
|
+
# @!group Backend Accessors
|
25
|
+
# @note Translation may be string, integer or boolean-valued since
|
26
|
+
# value is stored on a JSON hash.
|
27
|
+
# @param [Symbol] locale Locale to write
|
28
|
+
# @param [String,Integer,Boolean] value Value to write
|
29
|
+
# @param [Hash] options
|
30
|
+
# @return [String,Integer,Boolean] Updated value
|
31
|
+
# @!method write(locale, value, **options)
|
32
|
+
|
33
|
+
setup do |attributes, options|
|
34
|
+
query_methods = Module.new do
|
35
|
+
define_method :i18n do
|
36
|
+
@mobility_scope ||= super().extending(QueryMethods.new(attributes, options))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
extend query_methods
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Backend
|
3
|
+
class ActiveRecord::Jsonb::QueryMethods < ActiveRecord::QueryMethods
|
4
|
+
def initialize(attributes, **options)
|
5
|
+
super
|
6
|
+
attributes_extractor = @attributes_extractor
|
7
|
+
|
8
|
+
define_method :where! do |opts, *rest|
|
9
|
+
if i18n_keys = attributes_extractor.call(opts)
|
10
|
+
locale = Mobility.locale
|
11
|
+
opts = opts.with_indifferent_access
|
12
|
+
|
13
|
+
result = i18n_keys.inject(all) do |scope, attr|
|
14
|
+
value = opts.delete(attr)
|
15
|
+
if value.nil?
|
16
|
+
scope.where.not("#{table_name}.#{attr} ? :locale", locale: locale)
|
17
|
+
else
|
18
|
+
scope.where!("#{table_name}.#{attr} @> (?)::jsonb", { locale => value }.to_json)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
result = result.where!(opts, *rest) if opts.present?
|
22
|
+
result
|
23
|
+
else
|
24
|
+
super(opts, *rest)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def extended(relation)
|
30
|
+
super
|
31
|
+
attributes_extractor = @attributes_extractor
|
32
|
+
table_name = relation.model.table_name
|
33
|
+
|
34
|
+
mod = Module.new do
|
35
|
+
define_method :not do |opts, *rest|
|
36
|
+
if i18n_keys = attributes_extractor.call(opts)
|
37
|
+
locale = Mobility.locale
|
38
|
+
opts = opts.with_indifferent_access
|
39
|
+
|
40
|
+
i18n_keys.inject(relation) { |scope, attr|
|
41
|
+
scope.where!("#{table_name}.#{attr} ? :locale", locale: locale).
|
42
|
+
where.not("#{table_name}.#{attr} @> (?)::jsonb", { locale => opts.delete(attr) }.to_json)
|
43
|
+
}.where.not(opts, *rest)
|
44
|
+
else
|
45
|
+
super(opts, *rest)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
relation.model.mobility_where_chain.prepend(mod)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Backend
|
3
|
+
=begin
|
4
|
+
|
5
|
+
Implements the {Mobility::Backend::KeyValue} backend for ActiveRecord models.
|
6
|
+
|
7
|
+
@example
|
8
|
+
class Post < ActiveRecord::Base
|
9
|
+
translates :title, backend: :key_value, association_name: :translations, type: :string
|
10
|
+
end
|
11
|
+
|
12
|
+
post = Post.create(title: "foo")
|
13
|
+
post.translations
|
14
|
+
#=> #<ActiveRecord::Associations::CollectionProxy ... >
|
15
|
+
post.translations.first.value
|
16
|
+
#=> "foo"
|
17
|
+
post.translations.first.class
|
18
|
+
#=> Mobility::ActiveRercord::StringTranslation
|
19
|
+
|
20
|
+
=end
|
21
|
+
class ActiveRecord::KeyValue
|
22
|
+
include Backend
|
23
|
+
|
24
|
+
autoload :QueryMethods, 'mobility/backend/active_record/key_value/query_methods'
|
25
|
+
|
26
|
+
# @return [Symbol] Name of the association
|
27
|
+
attr_reader :association_name
|
28
|
+
|
29
|
+
# @!macro backend_constructor
|
30
|
+
# @option options [Symbol] association_name Name of association
|
31
|
+
def initialize(model, attribute, **options)
|
32
|
+
super
|
33
|
+
@association_name = options[:association_name]
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!group Backend Accessors
|
37
|
+
# @!macro backend_reader
|
38
|
+
def read(locale, **options)
|
39
|
+
translation_for(locale).value
|
40
|
+
end
|
41
|
+
|
42
|
+
# @!macro backend_reader
|
43
|
+
def write(locale, value, **options)
|
44
|
+
translation_for(locale).tap { |t| t.value = value }.value
|
45
|
+
end
|
46
|
+
# @!endgroup
|
47
|
+
|
48
|
+
# @!group Backend Configuration
|
49
|
+
# @option options [Symbol] type (:text) Column type to use
|
50
|
+
# @option options [Symbol] association_name (:mobility_text_translations) Name of association method
|
51
|
+
# @option options [String,Class] class_name ({Mobility::ActiveRecord::TextTranslation}) Translation class
|
52
|
+
# @raise [ArgumentError] if type is not either :text or :string
|
53
|
+
def self.configure!(options)
|
54
|
+
options[:type] ||= :text
|
55
|
+
case type = options[:type].to_sym
|
56
|
+
when :text, :string
|
57
|
+
options[:class_name] ||= Mobility::ActiveRecord.const_get("#{type.capitalize}Translation")
|
58
|
+
else
|
59
|
+
raise ArgumentError, "type must be one of: [text, string]"
|
60
|
+
end
|
61
|
+
options[:class_name] = options[:class_name].constantize if options[:class_name].is_a?(String)
|
62
|
+
options[:association_name] ||= options[:class_name].table_name.to_sym
|
63
|
+
%i[type association_name].each { |key| options[key] = options[key].to_sym }
|
64
|
+
end
|
65
|
+
# @!endgroup
|
66
|
+
|
67
|
+
setup do |attributes, options|
|
68
|
+
association_name = options[:association_name]
|
69
|
+
translations_class = options[:class_name]
|
70
|
+
|
71
|
+
# Track all attributes for this association, so that we can limit the scope
|
72
|
+
# of keys for the association to only these attributes. We need to track the
|
73
|
+
# attributes assigned to the association in case this setup code is called
|
74
|
+
# multiple times, so we don't "forget" earlier attributes.
|
75
|
+
#
|
76
|
+
attrs_method_name = :"__#{association_name}_attributes"
|
77
|
+
association_attributes = (instance_variable_get(:"@#{attrs_method_name}") || []) + attributes
|
78
|
+
instance_variable_set(:"@#{attrs_method_name}", association_attributes)
|
79
|
+
|
80
|
+
has_many association_name, ->{ where key: association_attributes },
|
81
|
+
as: :translatable,
|
82
|
+
class_name: translations_class,
|
83
|
+
dependent: :destroy,
|
84
|
+
inverse_of: :translatable,
|
85
|
+
autosave: true
|
86
|
+
before_save do
|
87
|
+
send(association_name).select { |t| t.value.blank? }.each do |translation|
|
88
|
+
send(association_name).destroy(translation)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
mod = Module.new do
|
93
|
+
define_method :i18n do
|
94
|
+
@mobility_scope ||= super().extending(QueryMethods.new(attributes, options))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
extend mod
|
98
|
+
end
|
99
|
+
|
100
|
+
# @!group Cache Methods
|
101
|
+
# @return [KeyValue::TranslationsCache]
|
102
|
+
def new_cache
|
103
|
+
KeyValue::TranslationsCache.new(self)
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Boolean]
|
107
|
+
def write_to_cache?
|
108
|
+
true
|
109
|
+
end
|
110
|
+
# @!endgroup
|
111
|
+
|
112
|
+
# Returns translation for a given locale, or builds one if none is present.
|
113
|
+
# @param [Symbol] locale
|
114
|
+
# @return [Mobility::ActiveRecord::TextTranslation,Mobility::ActiveRecord::StringTranslation]
|
115
|
+
def translation_for(locale)
|
116
|
+
translation = translations.find { |t| t.key == attribute && t.locale == locale.to_s }
|
117
|
+
translation ||= translations.build(locale: locale, key: attribute)
|
118
|
+
translation
|
119
|
+
end
|
120
|
+
|
121
|
+
def translations
|
122
|
+
model.send(association_name)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|