mobility 0.1.6 → 0.1.7
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/CHANGELOG.md +29 -12
- data/Gemfile.lock +17 -17
- data/README.md +22 -7
- data/lib/generators/{mobility → rails/mobility}/install_generator.rb +0 -0
- data/lib/generators/{mobility → rails/mobility}/templates/create_string_translations.rb +2 -1
- data/lib/generators/{mobility → rails/mobility}/templates/create_text_translations.rb +1 -1
- data/lib/mobility.rb +1 -2
- data/lib/mobility/backend.rb +2 -3
- data/lib/mobility/backend/active_model/dirty.rb +1 -1
- data/lib/mobility/backend/active_record/column.rb +1 -1
- data/lib/mobility/backend/active_record/key_value.rb +4 -7
- data/lib/mobility/backend/active_record/key_value/query_methods.rb +38 -29
- data/lib/mobility/backend/active_record/table/query_methods.rb +40 -33
- data/lib/mobility/backend/fallbacks.rb +25 -11
- data/lib/mobility/backend/key_value.rb +14 -0
- data/lib/mobility/backend/sequel/column.rb +1 -1
- data/lib/mobility/backend/sequel/dirty.rb +2 -1
- data/lib/mobility/backend/sequel/key_value.rb +5 -8
- data/lib/mobility/backend/sequel/key_value/query_methods.rb +20 -9
- data/lib/mobility/backend/sequel/serialized.rb +7 -7
- data/lib/mobility/backend/sequel/table/query_methods.rb +17 -14
- data/lib/mobility/rails.rb +2 -0
- data/lib/mobility/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c83db6c82d88d2972c328ea414426416b57aee7
|
|
4
|
+
data.tar.gz: b058744cc114446d2d641046b3d14cbc843eef8f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5d44c71b7381046f0fc63ea7cb7aed5506aa2860324dced1a6d58c07d3b1aa9fe9c10d337d17d42e4807a722a78faca46b2e386611b4e2a984176daaf90efdd3
|
|
7
|
+
data.tar.gz: 3e29ad8f1a11cb343291dbe0fa63633433e2463a40e70b85834898f808064b85fb129fba59db7588471743e4ee90c2bf276a8f50f90b8c9993cc2b1870d39107
|
data/CHANGELOG.md
CHANGED
|
@@ -2,30 +2,47 @@
|
|
|
2
2
|
|
|
3
3
|
## 0.1
|
|
4
4
|
|
|
5
|
+
### 0.1.7
|
|
6
|
+
* Allow passing fallback locale or locales to getter method
|
|
7
|
+
([#9](https://github.com/shioyama/mobility/pull/9))
|
|
8
|
+
* Add missing indices on key-value string/text translation tables
|
|
9
|
+
([1e00e0](https://github.com/shioyama/mobility/commit/1e00e0d957478f2408fbac1ee853f829489263e2),
|
|
10
|
+
[574172](https://github.com/shioyama/mobility/commit/574172dc88823a35c60ff963ff9c40b7c05771d7))
|
|
11
|
+
|
|
12
|
+
### 0.1.6
|
|
13
|
+
* Return accessor locales instead of Proc from default_accessor_locales
|
|
14
|
+
([825f75](https://github.com/shioyama/mobility/commit/825f75de6107287a5de70db439d8aec5e4a47977))
|
|
15
|
+
* Fix support for locales in dirty modules
|
|
16
|
+
([0b40d6](https://github.com/shioyama/mobility/commit/0b40d66ea0c816d4fb57deceff9344f5128a593f))
|
|
17
|
+
* Add FallthroughAccessors for use in dirty modules
|
|
18
|
+
([#4](https://github.com/shioyama/mobility/pull/4))
|
|
19
|
+
* Only raise InvalidLocale exception if I18n.enforce_available_locales is true
|
|
20
|
+
([979c36](https://github.com/shioyama/mobility/commit/979c365794d3df90a2d23ad50519ff354686a493))
|
|
21
|
+
|
|
5
22
|
### 0.1.5
|
|
6
|
-
* Add `accessor_method` to default initializer ([
|
|
7
|
-
* Include AR version in generated migrations ([
|
|
8
|
-
* Add `untranslated_attributes` method ([
|
|
9
|
-
* Do not require `active_support/core_ext/nil` ([
|
|
10
|
-
* Handle false values correctly when getting and setting ([
|
|
11
|
-
* Use proc to define accessor locales from `I18n.available_locales` ([
|
|
23
|
+
* Add `accessor_method` to default initializer ([d4a9da](https://github.com/shioyama/mobility/commit/d4a9da98cae71de2fb9ee3d29c64decef5a16010))
|
|
24
|
+
* Include AR version in generated migrations ([ac3dfb](https://github.com/shioyama/mobility/commit/ac3dfbbc053089b01dcc73d0b617fefaeaaa85cb))
|
|
25
|
+
* Add `untranslated_attributes` method ([50e97f](https://github.com/shioyama/mobility/commit/50e97f12ea219321ef9f61792e909299f570ba23))
|
|
26
|
+
* Do not require `active_support/core_ext/nil` ([39e245](https://github.com/shioyama/mobility/commit/39e24596482f03302542e524ca6f17275a778644))
|
|
27
|
+
* Handle false values correctly when getting and setting ([bdf6f1](https://github.com/shioyama/mobility/commit/bdf6f199aaa8318a73c5aa6332aee8d7aad254f6))
|
|
28
|
+
* Use proc to define accessor locales from `I18n.available_locales` ([3cd786](https://github.com/shioyama/mobility/commit/3cd786814d8044ae5d64f939c3a7b5c49b322bc6))
|
|
12
29
|
* Do not mark attribute as changed if value is the same (fixed in [#2](https://github.com/shioyama/mobility/pull/2))
|
|
13
30
|
* Pass on any args to original reload method when overriding (fixed in [#3](https://github.com/shioyama/mobility/pull/3))
|
|
14
31
|
|
|
15
32
|
### 0.1.4
|
|
16
|
-
* Fix configuration reload issue ([#1](https://github.com/shioyama/mobility/issues/1), fixed in [
|
|
17
|
-
* Code refactoring/cleanup ([
|
|
18
|
-
* Allow using Sequel `plugin` to include Mobility in model ([
|
|
33
|
+
* Fix configuration reload issue ([#1](https://github.com/shioyama/mobility/issues/1), fixed in [478b66](https://github.com/shioyama/mobility/commit/478b669dae90edf9feb7c011ae93e8157dc4e2b4))
|
|
34
|
+
* Code refactoring/cleanup ([e4dcc7](https://github.com/shioyama/mobility/commit/e4dcc791c246e377352b9ac154d2b1c4aec8e98e), [64f434](https://github.com/shioyama/mobility/commit/64f434ea7a46c9353c3638c58a3258f0fcb81821), [8df2bb](https://github.com/shioyama/mobility/commit/8df2bbdead883725d2c87020f836b644b4d28e5c), [326a09](https://github.com/shioyama/mobility/commit/326a0977c98348dad85a927c20dd69fe5acb2a9e))
|
|
35
|
+
* Allow using Sequel `plugin` to include Mobility in model ([b0db7c](https://github.com/shioyama/mobility/commit/b0db7cc28a47e13c6888ef263260e8dff281543d))
|
|
19
36
|
|
|
20
37
|
### 0.1.3
|
|
21
38
|
|
|
22
39
|
* Add homepage to gemspec
|
|
23
40
|
* Pass backend class as context to `translates`
|
|
24
|
-
([
|
|
41
|
+
([adf93e](https://github.com/shioyama/mobility/commit/adf93e3c6bb314b73fbd43b221819310a1407c4d))
|
|
25
42
|
|
|
26
43
|
### 0.1.2
|
|
27
44
|
|
|
28
45
|
* Fix issues with querying in ActiveRecord jsonb and hstore backends
|
|
29
|
-
([
|
|
46
|
+
([527908](https://github.com/shioyama/mobility/commit/527908d9317daee6bf91e3e1a188fb64365f7bab)
|
|
30
47
|
and
|
|
31
|
-
[
|
|
48
|
+
[5e6add](https://github.com/shioyama/mobility/commit/5e6addd6f01cf255f5e71666324502ace96d3eac))
|
data/Gemfile.lock
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
mobility (0.1.
|
|
4
|
+
mobility (0.1.6)
|
|
5
5
|
i18n (>= 0.6.10)
|
|
6
6
|
request_store (~> 1.0)
|
|
7
7
|
|
|
8
8
|
GEM
|
|
9
9
|
remote: https://rubygems.org/
|
|
10
10
|
specs:
|
|
11
|
-
actionpack (5.0.
|
|
12
|
-
actionview (= 5.0.
|
|
13
|
-
activesupport (= 5.0.
|
|
11
|
+
actionpack (5.0.2)
|
|
12
|
+
actionview (= 5.0.2)
|
|
13
|
+
activesupport (= 5.0.2)
|
|
14
14
|
rack (~> 2.0)
|
|
15
15
|
rack-test (~> 0.6.3)
|
|
16
16
|
rails-dom-testing (~> 2.0)
|
|
17
17
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
18
|
-
actionview (5.0.
|
|
19
|
-
activesupport (= 5.0.
|
|
18
|
+
actionview (5.0.2)
|
|
19
|
+
activesupport (= 5.0.2)
|
|
20
20
|
builder (~> 3.1)
|
|
21
21
|
erubis (~> 2.7.0)
|
|
22
22
|
rails-dom-testing (~> 2.0)
|
|
23
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.
|
|
24
|
-
activemodel (5.0.
|
|
25
|
-
activesupport (= 5.0.
|
|
26
|
-
activerecord (5.0.
|
|
27
|
-
activemodel (= 5.0.
|
|
28
|
-
activesupport (= 5.0.
|
|
23
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
|
24
|
+
activemodel (5.0.2)
|
|
25
|
+
activesupport (= 5.0.2)
|
|
26
|
+
activerecord (5.0.2)
|
|
27
|
+
activemodel (= 5.0.2)
|
|
28
|
+
activesupport (= 5.0.2)
|
|
29
29
|
arel (~> 7.0)
|
|
30
|
-
activesupport (5.0.
|
|
30
|
+
activesupport (5.0.2)
|
|
31
31
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
32
32
|
i18n (~> 0.7)
|
|
33
33
|
minitest (~> 5.1)
|
|
@@ -36,7 +36,7 @@ GEM
|
|
|
36
36
|
builder (3.2.3)
|
|
37
37
|
byebug (9.0.6)
|
|
38
38
|
coderay (1.1.1)
|
|
39
|
-
concurrent-ruby (1.0.
|
|
39
|
+
concurrent-ruby (1.0.5)
|
|
40
40
|
database_cleaner (1.5.3)
|
|
41
41
|
diff-lcs (1.3)
|
|
42
42
|
erubis (2.7.0)
|
|
@@ -92,9 +92,9 @@ GEM
|
|
|
92
92
|
nokogiri (~> 1.6)
|
|
93
93
|
rails-html-sanitizer (1.0.3)
|
|
94
94
|
loofah (~> 2.0)
|
|
95
|
-
railties (5.0.
|
|
96
|
-
actionpack (= 5.0.
|
|
97
|
-
activesupport (= 5.0.
|
|
95
|
+
railties (5.0.2)
|
|
96
|
+
actionpack (= 5.0.2)
|
|
97
|
+
activesupport (= 5.0.2)
|
|
98
98
|
method_source
|
|
99
99
|
rake (>= 0.8.7)
|
|
100
100
|
thor (>= 0.18.1, < 2.0)
|
data/README.md
CHANGED
|
@@ -56,7 +56,7 @@ Mobility](http://dejimata.com/2017/3/3/translating-with-mobility).
|
|
|
56
56
|
Add this line to your application's Gemfile:
|
|
57
57
|
|
|
58
58
|
```ruby
|
|
59
|
-
gem 'mobility', '~> 0.1.
|
|
59
|
+
gem 'mobility', '~> 0.1.7'
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
To translate attributes on a model, you must include (or extend) `Mobility`,
|
|
@@ -386,7 +386,7 @@ Alternatively, just using `locale_accessors: true` will enable all locales in
|
|
|
386
386
|
|
|
387
387
|
An alternative to using the `locale_accessors` option is to use the
|
|
388
388
|
`fallthrough_accessors` option (defined in {Mobility::FallthroughAccessors})
|
|
389
|
-
with `fallthrough_accessors: true`. This uses
|
|
389
|
+
with `fallthrough_accessors: true`. This uses `method_missing` to implicitly
|
|
390
390
|
define the same methods as above, but supporting any locale without any method
|
|
391
391
|
definitions. [Dirty tracking](#dirty) enables fallthrough locales for tracking
|
|
392
392
|
attribute changes. (Both locale accessors and fallthrough locales can be used
|
|
@@ -427,6 +427,9 @@ class Post < ActiveRecord::Base
|
|
|
427
427
|
end
|
|
428
428
|
```
|
|
429
429
|
|
|
430
|
+
Internally, Mobility assigns the fallbacks hash to an instance of
|
|
431
|
+
`I18n::Locale::Fallbacks.new`.
|
|
432
|
+
|
|
430
433
|
By setting fallbacks for English and French to Japanese, values will fall
|
|
431
434
|
through to the Japanese value if none is present for either of these locales:
|
|
432
435
|
|
|
@@ -445,17 +448,29 @@ post.title_fr
|
|
|
445
448
|
|
|
446
449
|
You can optionally disable fallbacks to get the real value for a given locale
|
|
447
450
|
(for example, to check if a value in a particular locale is set or not) by
|
|
448
|
-
passing `
|
|
451
|
+
passing `fallback: false` (note that the key is the *singular*, not plural) to
|
|
452
|
+
the getter method:
|
|
449
453
|
|
|
450
454
|
```ruby
|
|
451
|
-
post.title(
|
|
455
|
+
post.title(fallback: false)
|
|
452
456
|
#=> nil
|
|
453
|
-
post.
|
|
457
|
+
post.title(locale: :fr, fallback: false)
|
|
454
458
|
#=> nil
|
|
455
459
|
```
|
|
456
460
|
|
|
457
|
-
|
|
458
|
-
|
|
461
|
+
You can also set the fallback locales for a single read by passing one or more
|
|
462
|
+
locales, like this:
|
|
463
|
+
|
|
464
|
+
```ruby
|
|
465
|
+
post.title_fr = "mobilité: aptitude à bouger, à se déplacer, à changer, à évoluer"
|
|
466
|
+
post.save
|
|
467
|
+
post.title
|
|
468
|
+
#=> nil
|
|
469
|
+
post.title(fallback: :fr)
|
|
470
|
+
#=> "mobilité: aptitude à bouger, à se déplacer, à changer, à évoluer"
|
|
471
|
+
post.title(fallback: [:ja, :fr])
|
|
472
|
+
#=> "Mobility(名詞):動きやすさ、可動性"
|
|
473
|
+
```
|
|
459
474
|
|
|
460
475
|
For more details, see: {Mobility::Backend::Fallbacks}.
|
|
461
476
|
|
|
File without changes
|
|
@@ -10,6 +10,7 @@ class CreateStringTranslations < ActiveRecord::Migration[<%= ActiveRecord::Migra
|
|
|
10
10
|
t.timestamps
|
|
11
11
|
end
|
|
12
12
|
add_index :mobility_string_translations, [:translatable_id, :translatable_type, :locale, :key], unique: true, name: :index_mobility_string_translations_on_keys
|
|
13
|
-
add_index :mobility_string_translations, [:translatable_id, :translatable_type], name: :
|
|
13
|
+
add_index :mobility_string_translations, [:translatable_id, :translatable_type, :key], name: :index_mobility_string_translations_on_translatable_attribute
|
|
14
|
+
add_index :mobility_string_translations, [:translatable_type, :key, :value, :locale], name: :index_mobility_string_translations_on_query_keys
|
|
14
15
|
end
|
|
15
16
|
end
|
|
@@ -10,6 +10,6 @@ class CreateTextTranslations < ActiveRecord::Migration[<%= ActiveRecord::Migrati
|
|
|
10
10
|
t.timestamps
|
|
11
11
|
end
|
|
12
12
|
add_index :mobility_text_translations, [:translatable_id, :translatable_type, :locale, :key], unique: true, name: :index_mobility_text_translations_on_keys
|
|
13
|
-
add_index :mobility_text_translations, [:translatable_id, :translatable_type], name: :
|
|
13
|
+
add_index :mobility_text_translations, [:translatable_id, :translatable_type, :key], name: :index_mobility_text_translations_on_translatable_attribute
|
|
14
14
|
end
|
|
15
15
|
end
|
data/lib/mobility.rb
CHANGED
|
@@ -58,10 +58,9 @@ module Mobility
|
|
|
58
58
|
|
|
59
59
|
begin
|
|
60
60
|
require "rails"
|
|
61
|
-
autoload :InstallGenerator, "generators/mobility/install_generator"
|
|
62
61
|
Loaded::Rails = true
|
|
62
|
+
require "mobility/rails"
|
|
63
63
|
rescue LoadError
|
|
64
|
-
class InstallGenerator; end
|
|
65
64
|
Loaded::Rails = false
|
|
66
65
|
end
|
|
67
66
|
|
data/lib/mobility/backend.rb
CHANGED
|
@@ -76,12 +76,11 @@ On top of this, a backend will normally:
|
|
|
76
76
|
# @!macro [new] backend_constructor
|
|
77
77
|
# @param model Model on which backend is defined
|
|
78
78
|
# @param [String] attribute Backend attribute
|
|
79
|
-
# @
|
|
80
|
-
def initialize(model, attribute, **options)
|
|
79
|
+
# @param [Hash] fallbacks Fallbacks hash
|
|
80
|
+
def initialize(model, attribute, fallbacks: nil, **options)
|
|
81
81
|
@model = model
|
|
82
82
|
@attribute = attribute
|
|
83
83
|
@options = options
|
|
84
|
-
fallbacks = options[:fallbacks]
|
|
85
84
|
@fallbacks = I18n::Locale::Fallbacks.new(fallbacks) if fallbacks.is_a?(Hash)
|
|
86
85
|
end
|
|
87
86
|
|
|
@@ -28,7 +28,7 @@ value of the translated attribute if passed to it.
|
|
|
28
28
|
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale)
|
|
29
29
|
if model.changed_attributes.has_key?(locale_accessor) && model.changed_attributes[locale_accessor] == value
|
|
30
30
|
model.attributes_changed_by_setter.except!(locale_accessor)
|
|
31
|
-
elsif read(locale, options.merge(
|
|
31
|
+
elsif read(locale, options.merge(fallback: false)) != value
|
|
32
32
|
model.send(:attribute_will_change!, locale_accessor)
|
|
33
33
|
end
|
|
34
34
|
super
|
|
@@ -21,7 +21,7 @@ Implements the {Mobility::Backend::Column} backend for ActiveRecord models.
|
|
|
21
21
|
=end
|
|
22
22
|
class ActiveRecord::Column
|
|
23
23
|
include Backend
|
|
24
|
-
include
|
|
24
|
+
include Backend::Column
|
|
25
25
|
|
|
26
26
|
autoload :QueryMethods, 'mobility/backend/active_record/column/query_methods'
|
|
27
27
|
|
|
@@ -20,6 +20,7 @@ Implements the {Mobility::Backend::KeyValue} backend for ActiveRecord models.
|
|
|
20
20
|
=end
|
|
21
21
|
class ActiveRecord::KeyValue
|
|
22
22
|
include Backend
|
|
23
|
+
include Backend::KeyValue
|
|
23
24
|
|
|
24
25
|
autoload :QueryMethods, 'mobility/backend/active_record/key_value/query_methods'
|
|
25
26
|
|
|
@@ -51,13 +52,9 @@ Implements the {Mobility::Backend::KeyValue} backend for ActiveRecord models.
|
|
|
51
52
|
# @option options [String,Class] class_name ({Mobility::ActiveRecord::TextTranslation}) Translation class
|
|
52
53
|
# @raise [ArgumentError] if type is not either :text or :string
|
|
53
54
|
def self.configure!(options)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
|
55
|
+
super
|
|
56
|
+
type = options[:type]
|
|
57
|
+
options[:class_name] ||= Mobility::ActiveRecord.const_get("#{type.capitalize}Translation")
|
|
61
58
|
options[:class_name] = options[:class_name].constantize if options[:class_name].is_a?(String)
|
|
62
59
|
options[:association_name] ||= options[:class_name].table_name.to_sym
|
|
63
60
|
%i[type association_name].each { |key| options[key] = options[key].to_sym }
|
|
@@ -1,37 +1,12 @@
|
|
|
1
1
|
module Mobility
|
|
2
2
|
module Backend
|
|
3
3
|
class ActiveRecord::KeyValue::QueryMethods < ActiveRecord::QueryMethods
|
|
4
|
-
def initialize(attributes, **
|
|
4
|
+
def initialize(attributes, association_name: nil, class_name: nil, **_)
|
|
5
5
|
super
|
|
6
|
-
association_name
|
|
7
|
-
@association_name = association_name
|
|
8
|
-
attributes_extractor = @attributes_extractor
|
|
9
|
-
|
|
10
|
-
define_method :"join_#{association_name}" do |*attributes, **options|
|
|
11
|
-
attributes.inject(self) do |relation, attribute|
|
|
12
|
-
t = translations_class.arel_table.alias(:"#{attribute}_#{association_name}")
|
|
13
|
-
m = arel_table
|
|
14
|
-
join_type = options[:outer_join] ? Arel::Nodes::OuterJoin : Arel::Nodes::InnerJoin
|
|
15
|
-
relation.joins(m.join(t, join_type).
|
|
16
|
-
on(t[:key].eq(attribute).
|
|
17
|
-
and(t[:locale].eq(Mobility.locale).
|
|
18
|
-
and(t[:translatable_type].eq(name).
|
|
19
|
-
and(t[:translatable_id].eq(m[:id]))))).join_sources)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
6
|
+
@association_name = association_name
|
|
22
7
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
opts = opts.with_indifferent_access
|
|
26
|
-
i18n_nulls = i18n_keys.select { |key| opts[key].nil? }
|
|
27
|
-
i18n_keys.each { |attr| opts["#{attr}_#{association_name}"] = { value: opts.delete(attr) }}
|
|
28
|
-
super(opts, *rest).
|
|
29
|
-
send("join_#{association_name}", *(i18n_keys - i18n_nulls)).
|
|
30
|
-
send("join_#{association_name}", *i18n_nulls, outer_join: true)
|
|
31
|
-
else
|
|
32
|
-
super(opts, *rest)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
8
|
+
define_join_method(association_name, class_name)
|
|
9
|
+
define_query_methods(association_name)
|
|
35
10
|
|
|
36
11
|
attributes.each do |attribute|
|
|
37
12
|
define_method :"find_by_#{attribute}" do |value|
|
|
@@ -58,6 +33,40 @@ module Mobility
|
|
|
58
33
|
end
|
|
59
34
|
relation.model.mobility_where_chain.prepend(mod)
|
|
60
35
|
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def define_join_method(association_name, translation_class)
|
|
40
|
+
define_method :"join_#{association_name}" do |*attributes, **options|
|
|
41
|
+
attributes.inject(self) do |relation, attribute|
|
|
42
|
+
t = translation_class.arel_table.alias(:"#{attribute}_#{association_name}")
|
|
43
|
+
m = arel_table
|
|
44
|
+
join_type = options[:outer_join] ? Arel::Nodes::OuterJoin : Arel::Nodes::InnerJoin
|
|
45
|
+
relation.joins(m.join(t, join_type).
|
|
46
|
+
on(t[:key].eq(attribute).
|
|
47
|
+
and(t[:locale].eq(Mobility.locale).
|
|
48
|
+
and(t[:translatable_type].eq(name).
|
|
49
|
+
and(t[:translatable_id].eq(m[:id]))))).join_sources)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def define_query_methods(association_name)
|
|
55
|
+
attributes_extractor = @attributes_extractor
|
|
56
|
+
|
|
57
|
+
define_method :where! do |opts, *rest|
|
|
58
|
+
if i18n_keys = attributes_extractor.call(opts)
|
|
59
|
+
opts = opts.with_indifferent_access
|
|
60
|
+
i18n_nulls = i18n_keys.select { |key| opts[key].nil? }
|
|
61
|
+
i18n_keys.each { |attr| opts["#{attr}_#{association_name}"] = { value: opts.delete(attr) }}
|
|
62
|
+
super(opts, *rest).
|
|
63
|
+
send("join_#{association_name}", *(i18n_keys - i18n_nulls)).
|
|
64
|
+
send("join_#{association_name}", *i18n_nulls, outer_join: true)
|
|
65
|
+
else
|
|
66
|
+
super(opts, *rest)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
61
70
|
end
|
|
62
71
|
end
|
|
63
72
|
end
|
|
@@ -1,16 +1,45 @@
|
|
|
1
1
|
module Mobility
|
|
2
2
|
module Backend
|
|
3
3
|
class ActiveRecord::Table::QueryMethods < ActiveRecord::QueryMethods
|
|
4
|
-
def initialize(attributes, **options)
|
|
4
|
+
def initialize(attributes, association_name: nil, model_class: nil, subclass_name: nil, **options)
|
|
5
5
|
super
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@
|
|
6
|
+
|
|
7
|
+
@association_name = association_name
|
|
8
|
+
@translation_class = translation_class = model_class.const_get(subclass_name)
|
|
9
|
+
|
|
10
|
+
define_join_method(association_name, translation_class, **options)
|
|
11
|
+
define_query_methods(association_name, translation_class, **options)
|
|
12
|
+
|
|
13
|
+
attributes.each do |attribute|
|
|
14
|
+
define_method :"find_by_#{attribute}" do |value|
|
|
15
|
+
find_by(attribute.to_sym => value)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def extended(relation)
|
|
21
|
+
super
|
|
22
|
+
association_name = @association_name
|
|
9
23
|
attributes_extractor = @attributes_extractor
|
|
10
|
-
translation_class =
|
|
11
|
-
|
|
12
|
-
|
|
24
|
+
translation_class = @translation_class
|
|
25
|
+
|
|
26
|
+
mod = Module.new do
|
|
27
|
+
define_method :not do |opts, *rest|
|
|
28
|
+
if i18n_keys = attributes_extractor.call(opts)
|
|
29
|
+
opts = opts.with_indifferent_access
|
|
30
|
+
i18n_keys.each { |attr| opts["#{translation_class.table_name}.#{attr}"] = opts.delete(attr) }
|
|
31
|
+
super(opts, *rest).send("join_#{association_name}")
|
|
32
|
+
else
|
|
33
|
+
super(opts, *rest)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
relation.model.mobility_where_chain.prepend(mod)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
13
41
|
|
|
42
|
+
def define_join_method(association_name, translation_class, foreign_key: nil, table_name: nil, **_)
|
|
14
43
|
define_method :"join_#{association_name}" do |**options|
|
|
15
44
|
return self if (@__mobility_table_joined || []).include?(table_name)
|
|
16
45
|
(@__mobility_table_joined ||= []) << table_name
|
|
@@ -21,6 +50,10 @@ module Mobility
|
|
|
21
50
|
on(t[foreign_key].eq(m[:id]).
|
|
22
51
|
and(t[:locale].eq(Mobility.locale))).join_sources)
|
|
23
52
|
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def define_query_methods(association_name, translation_class, **_)
|
|
56
|
+
attributes_extractor = @attributes_extractor
|
|
24
57
|
|
|
25
58
|
# Note that Mobility will try to use inner/outer joins appropriate to the query,
|
|
26
59
|
# so for example:
|
|
@@ -59,32 +92,6 @@ module Mobility
|
|
|
59
92
|
super(opts, *rest)
|
|
60
93
|
end
|
|
61
94
|
end
|
|
62
|
-
|
|
63
|
-
attributes.each do |attribute|
|
|
64
|
-
define_method :"find_by_#{attribute}" do |value|
|
|
65
|
-
find_by(attribute.to_sym => value)
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def extended(relation)
|
|
71
|
-
super
|
|
72
|
-
association_name = @association_name
|
|
73
|
-
attributes_extractor = @attributes_extractor
|
|
74
|
-
translation_class = @translation_class
|
|
75
|
-
|
|
76
|
-
mod = Module.new do
|
|
77
|
-
define_method :not do |opts, *rest|
|
|
78
|
-
if i18n_keys = attributes_extractor.call(opts)
|
|
79
|
-
opts = opts.with_indifferent_access
|
|
80
|
-
i18n_keys.each { |attr| opts["#{translation_class.table_name}.#{attr}"] = opts.delete(attr) }
|
|
81
|
-
super(opts, *rest).send("join_#{association_name}")
|
|
82
|
-
else
|
|
83
|
-
super(opts, *rest)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
relation.model.mobility_where_chain.prepend(mod)
|
|
88
95
|
end
|
|
89
96
|
end
|
|
90
97
|
end
|
|
@@ -13,9 +13,14 @@ defaults to an instance of +I18n::Locale::Fallbacks+, but can be configured
|
|
|
13
13
|
If a hash is passed to the +fallbacks+ option, a new fallbacks instance will be
|
|
14
14
|
created for the model with the hash defining additional fallbacks.
|
|
15
15
|
|
|
16
|
-
In addition, fallbacks can be disabled when reading by passing
|
|
17
|
-
false
|
|
18
|
-
of the translated attribute, including a possible +nil+ value.
|
|
16
|
+
In addition, fallbacks can be disabled when reading by passing <tt>fallback:
|
|
17
|
+
false</tt> to the reader method. This can be useful to determine the actual
|
|
18
|
+
value of the translated attribute, including a possible +nil+ value. You can
|
|
19
|
+
also pass a locale or array of locales to the +fallback+ option to use that
|
|
20
|
+
locale or locales that read, e.g. <tt>fallback: :fr</tt> would fetch the French
|
|
21
|
+
translation if the value in the current locale was +nil+, whereas <tt>fallback:
|
|
22
|
+
[:fr, :es]</tt> would try French, then Spanish if the value in the current
|
|
23
|
+
locale was +nil+.
|
|
19
24
|
|
|
20
25
|
@see https://github.com/svenfuchs/i18n/wiki/Fallbacks I18n Fallbacks
|
|
21
26
|
|
|
@@ -52,28 +57,37 @@ of the translated attribute, including a possible +nil+ value.
|
|
|
52
57
|
post.title
|
|
53
58
|
#=> "bar"
|
|
54
59
|
|
|
55
|
-
@example
|
|
60
|
+
@example Passing fallback option when reading value
|
|
56
61
|
class Post
|
|
57
62
|
translates :title, fallbacks: true
|
|
58
63
|
end
|
|
59
64
|
|
|
60
65
|
I18n.default_locale = :en
|
|
61
66
|
Mobility.locale = :en
|
|
62
|
-
post = Post.new(title: "
|
|
67
|
+
post = Post.new(title: "Mobility")
|
|
68
|
+
Mobility.with_locale(:fr) { post.title = "Mobilité" }
|
|
63
69
|
|
|
64
70
|
Mobility.locale = :ja
|
|
65
71
|
post.title
|
|
66
|
-
#=> "
|
|
67
|
-
post.title(
|
|
72
|
+
#=> "Mobility"
|
|
73
|
+
post.title(fallback: false)
|
|
68
74
|
#=> nil
|
|
75
|
+
post.title(fallback: :fr)
|
|
76
|
+
#=> "Mobilité"
|
|
69
77
|
=end
|
|
70
78
|
module Fallbacks
|
|
71
79
|
# @!group Backend Accessors
|
|
72
80
|
# @!macro backend_reader
|
|
73
|
-
# @
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
# @param [Boolean,Symbol,Array] fallback
|
|
82
|
+
# +false+ to disable fallbacks on lookup, or a locale or array of
|
|
83
|
+
# locales to set fallback(s) for this lookup.
|
|
84
|
+
def read(locale, fallback: nil, **_)
|
|
85
|
+
if !options[:fallbacks].nil?
|
|
86
|
+
warn "You passed an option with key 'fallbacks', which will be
|
|
87
|
+
ignored. Did you mean 'fallback'?"
|
|
88
|
+
end
|
|
89
|
+
return super if fallback == false
|
|
90
|
+
(fallback ? [locale, *fallback] : fallbacks[locale]).detect do |locale|
|
|
77
91
|
value = super(locale)
|
|
78
92
|
break value if value.present?
|
|
79
93
|
end
|
|
@@ -41,6 +41,20 @@ class.
|
|
|
41
41
|
module KeyValue
|
|
42
42
|
include OrmDelegator
|
|
43
43
|
|
|
44
|
+
def self.included(backend)
|
|
45
|
+
backend.extend ClassMethods
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
module ClassMethods
|
|
49
|
+
# @!group Backend Configuration
|
|
50
|
+
# @option options [Symbol,String] type (:text) Column type to use
|
|
51
|
+
# @raise [ArgumentError] if type is not either :text or :string
|
|
52
|
+
def configure!(options)
|
|
53
|
+
options[:type] = (options[:type] || :text).to_sym
|
|
54
|
+
raise ArgumentError, "type must be one of: [text, string]" unless [:text, :string].include?(options[:type])
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
44
58
|
# Simple cache to memoize translations as a hash so they can be fetched
|
|
45
59
|
# quickly.
|
|
46
60
|
class TranslationsCache
|
|
@@ -9,7 +9,7 @@ Implements the {Mobility::Backend::Column} backend for Sequel models.
|
|
|
9
9
|
=end
|
|
10
10
|
class Sequel::Column
|
|
11
11
|
include Backend
|
|
12
|
-
include
|
|
12
|
+
include Backend::Column
|
|
13
13
|
|
|
14
14
|
autoload :QueryMethods, 'mobility/backend/sequel/column/query_methods'
|
|
15
15
|
|
|
@@ -11,12 +11,13 @@ Automatically includes dirty plugin in model class when enabled.
|
|
|
11
11
|
module Sequel::Dirty
|
|
12
12
|
# @!group Backend Accessors
|
|
13
13
|
# @!macro backend_writer
|
|
14
|
+
# @param [Hash] options
|
|
14
15
|
def write(locale, value, **options)
|
|
15
16
|
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale).to_sym
|
|
16
17
|
if model.column_changes.has_key?(locale_accessor) && model.initial_values[locale_accessor] == value
|
|
17
18
|
super
|
|
18
19
|
[model.changed_columns, model.initial_values].each { |h| h.delete(locale_accessor) }
|
|
19
|
-
elsif read(locale, options.merge(
|
|
20
|
+
elsif read(locale, options.merge(fallback: false)) != value
|
|
20
21
|
model.will_change_column(locale_accessor)
|
|
21
22
|
super
|
|
22
23
|
end
|
|
@@ -11,6 +11,7 @@ Implements the {Mobility::Backend::KeyValue} backend for Sequel models.
|
|
|
11
11
|
=end
|
|
12
12
|
class Sequel::KeyValue
|
|
13
13
|
include Backend
|
|
14
|
+
include Backend::KeyValue
|
|
14
15
|
|
|
15
16
|
autoload :QueryMethods, 'mobility/backend/sequel/key_value/query_methods'
|
|
16
17
|
|
|
@@ -42,20 +43,16 @@ Implements the {Mobility::Backend::KeyValue} backend for Sequel models.
|
|
|
42
43
|
# @!endgroup
|
|
43
44
|
|
|
44
45
|
# @!group Backend Configuration
|
|
45
|
-
# @option options [Symbol] type (:text) Column type to use
|
|
46
|
+
# @option options [Symbol,String] type (:text) Column type to use
|
|
46
47
|
# @option options [Symbol] associaiton_name (:mobility_text_translations) Name of association method
|
|
47
48
|
# @option options [Symbol] class_name ({Mobility::Sequel::TextTranslation}) Translation class
|
|
48
49
|
# @raise [CacheRequired] if cache is disabled
|
|
49
50
|
# @raise [ArgumentError] if type is not either :text or :string
|
|
50
51
|
def self.configure!(options)
|
|
52
|
+
super
|
|
51
53
|
raise CacheRequired, "Cache required for Sequel::KeyValue backend" if options[:cache] == false
|
|
52
|
-
options[:type]
|
|
53
|
-
|
|
54
|
-
when :text, :string
|
|
55
|
-
options[:class_name] ||= Mobility::Sequel.const_get("#{type.capitalize}Translation")
|
|
56
|
-
else
|
|
57
|
-
raise ArgumentError, "type must be one of: [text, string]"
|
|
58
|
-
end
|
|
54
|
+
type = options[:type]
|
|
55
|
+
options[:class_name] ||= Mobility::Sequel.const_get("#{type.capitalize}Translation")
|
|
59
56
|
options[:class_name] = options[:class_name].constantize if options[:class_name].is_a?(String)
|
|
60
57
|
options[:association_name] ||= options[:class_name].table_name.to_sym
|
|
61
58
|
%i[type association_name].each { |key| options[key] = options[key].to_sym }
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
module Mobility
|
|
2
2
|
module Backend
|
|
3
3
|
class Sequel::KeyValue::QueryMethods < Sequel::QueryMethods
|
|
4
|
-
def initialize(attributes, **
|
|
4
|
+
def initialize(attributes, association_name: nil, class_name: nil, **_)
|
|
5
5
|
super
|
|
6
|
-
attributes_extractor = @attributes_extractor
|
|
7
|
-
association_name, translations_class = options[:association_name], options[:class_name]
|
|
8
6
|
|
|
7
|
+
define_join_method(association_name, class_name)
|
|
8
|
+
define_query_methods(association_name)
|
|
9
|
+
|
|
10
|
+
attributes.each do |attribute|
|
|
11
|
+
define_method :"first_by_#{attribute}" do |value|
|
|
12
|
+
where(attribute => value).select_all(model.table_name).first
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def define_join_method(association_name, translation_class)
|
|
9
20
|
define_method :"join_#{association_name}" do |*attributes, **options|
|
|
10
21
|
attributes.inject(self) do |relation, attribute|
|
|
11
22
|
join_type = options[:outer_join] ? :left_outer : :inner
|
|
12
23
|
relation.join_table(join_type,
|
|
13
|
-
|
|
24
|
+
translation_class.table_name,
|
|
14
25
|
{
|
|
15
26
|
key: attribute.to_s,
|
|
16
27
|
locale: Mobility.locale.to_s,
|
|
@@ -20,9 +31,14 @@ module Mobility
|
|
|
20
31
|
table_alias: "#{attribute}_#{association_name}")
|
|
21
32
|
end
|
|
22
33
|
end
|
|
34
|
+
end
|
|
23
35
|
|
|
36
|
+
def define_query_methods(association_name)
|
|
24
37
|
# TODO: find a better way to do this that doesn't involve overriding
|
|
25
38
|
# a private method...
|
|
39
|
+
#
|
|
40
|
+
attributes_extractor = @attributes_extractor
|
|
41
|
+
|
|
26
42
|
define_method :_filter_or_exclude do |invert, clause, *cond, &block|
|
|
27
43
|
if i18n_keys = attributes_extractor.call(cond.first)
|
|
28
44
|
cond = cond.first.dup
|
|
@@ -37,11 +53,6 @@ module Mobility
|
|
|
37
53
|
end
|
|
38
54
|
private :_filter_or_exclude
|
|
39
55
|
|
|
40
|
-
attributes.each do |attribute|
|
|
41
|
-
define_method :"first_by_#{attribute}" do |value|
|
|
42
|
-
where(attribute => value).select_all(model.table_name).first
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
56
|
end
|
|
46
57
|
end
|
|
47
58
|
end
|
|
@@ -60,8 +60,8 @@ Sequel serialization plugin.
|
|
|
60
60
|
plugin :serialization
|
|
61
61
|
plugin :serialization_modification_detection
|
|
62
62
|
|
|
63
|
-
attributes.each do |
|
|
64
|
-
attribute =
|
|
63
|
+
attributes.each do |attribute_|
|
|
64
|
+
attribute = attribute_.to_sym
|
|
65
65
|
self.serialization_map[attribute] = Serialized.serializer_for(format)
|
|
66
66
|
self.deserialization_map[attribute] = Serialized.deserializer_for(format)
|
|
67
67
|
end
|
|
@@ -87,13 +87,13 @@ Sequel serialization plugin.
|
|
|
87
87
|
# Returns deserialized column value
|
|
88
88
|
# @return [Hash]
|
|
89
89
|
def translations
|
|
90
|
-
|
|
91
|
-
if model.deserialized_values.has_key?(
|
|
92
|
-
model.deserialized_values[
|
|
90
|
+
attribute_ = attribute.to_sym
|
|
91
|
+
if model.deserialized_values.has_key?(attribute_)
|
|
92
|
+
model.deserialized_values[attribute_]
|
|
93
93
|
elsif model.frozen?
|
|
94
|
-
deserialize_value(
|
|
94
|
+
deserialize_value(attribute_, serialized_value)
|
|
95
95
|
else
|
|
96
|
-
model.deserialized_values[
|
|
96
|
+
model.deserialized_values[attribute_] = deserialize_value(attribute_, serialized_value)
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
module Mobility
|
|
2
2
|
module Backend
|
|
3
3
|
class Sequel::Table::QueryMethods < Sequel::QueryMethods
|
|
4
|
-
def initialize(attributes, **options)
|
|
4
|
+
def initialize(attributes, association_name: nil, model_class: nil, subclass_name: nil, **options)
|
|
5
5
|
super
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
translation_class = model_class.const_get(subclass_name)
|
|
7
|
+
|
|
8
|
+
define_join_method(association_name, translation_class, **options)
|
|
9
|
+
define_query_methods(association_name, translation_class, **options)
|
|
10
|
+
|
|
11
|
+
attributes.each do |attribute|
|
|
12
|
+
define_method :"first_by_#{attribute}" do |value|
|
|
13
|
+
where(attribute => value).select_all(model.table_name).first
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
13
17
|
|
|
18
|
+
def define_join_method(association_name, translation_class, table_name: nil, foreign_key: nil, **_)
|
|
14
19
|
define_method :"join_#{association_name}" do |**options|
|
|
15
20
|
return self if (@__mobility_table_joined || []).include?(table_name)
|
|
16
21
|
(@__mobility_table_joined ||= []) << table_name
|
|
@@ -22,6 +27,10 @@ module Mobility
|
|
|
22
27
|
foreign_key => ::Sequel[model.table_name][:id]
|
|
23
28
|
})
|
|
24
29
|
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def define_query_methods(association_name, translation_class, **_)
|
|
33
|
+
attributes_extractor = @attributes_extractor
|
|
25
34
|
|
|
26
35
|
# See note in AR Table QueryMethods class about limitations of
|
|
27
36
|
# query methods on translated attributes when searching on nil values.
|
|
@@ -36,12 +45,6 @@ module Mobility
|
|
|
36
45
|
super(invert, clause, *cond, &block)
|
|
37
46
|
end
|
|
38
47
|
end
|
|
39
|
-
|
|
40
|
-
attributes.each do |attribute|
|
|
41
|
-
define_method :"first_by_#{attribute}" do |value|
|
|
42
|
-
where(attribute => value).select_all(model.table_name).first
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
48
|
end
|
|
46
49
|
end
|
|
47
50
|
end
|
data/lib/mobility/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mobility
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Salzberg
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-03-
|
|
11
|
+
date: 2017-03-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: request_store
|
|
@@ -137,9 +137,9 @@ files:
|
|
|
137
137
|
- LICENSE.txt
|
|
138
138
|
- README.md
|
|
139
139
|
- Rakefile
|
|
140
|
-
- lib/generators/mobility/install_generator.rb
|
|
141
|
-
- lib/generators/mobility/templates/create_string_translations.rb
|
|
142
|
-
- lib/generators/mobility/templates/create_text_translations.rb
|
|
140
|
+
- lib/generators/rails/mobility/install_generator.rb
|
|
141
|
+
- lib/generators/rails/mobility/templates/create_string_translations.rb
|
|
142
|
+
- lib/generators/rails/mobility/templates/create_text_translations.rb
|
|
143
143
|
- lib/mobility.rb
|
|
144
144
|
- lib/mobility/active_model.rb
|
|
145
145
|
- lib/mobility/active_model/attribute_methods.rb
|
|
@@ -203,6 +203,7 @@ files:
|
|
|
203
203
|
- lib/mobility/fallthrough_accessors.rb
|
|
204
204
|
- lib/mobility/instance_methods.rb
|
|
205
205
|
- lib/mobility/orm.rb
|
|
206
|
+
- lib/mobility/rails.rb
|
|
206
207
|
- lib/mobility/sequel.rb
|
|
207
208
|
- lib/mobility/sequel/backend_resetter.rb
|
|
208
209
|
- lib/mobility/sequel/column_changes.rb
|