mobility 1.2.9 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mobility might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a2836c1681d1832331e807e58fa61956426ddc3cc730c15e6b3d6ebac2fce40
4
- data.tar.gz: 61c798b73769f7d73bb5a3a97b3a1a27ac8884a186df89aeb5ceef0ecb92b692
3
+ metadata.gz: e29c8ed1c4b5ff644843c06c90fa46ce9fa9dd951a64dfb40b2ff33961483edd
4
+ data.tar.gz: '0708f6107d1ac5a80fd99c7d7d098e6915c10ad457cf962fdcc8510bced56f58'
5
5
  SHA512:
6
- metadata.gz: e8693fb2b5d997a1d7029413aee5c5f064eeafbef6f8a10ad2c947bd545fff72e238f6d57ebaae8761d5948e036446d310f7ce9da3c047a7577818919dfd7908
7
- data.tar.gz: e980cc7d53a32c517c04994105540fd9635aae5899d35cecb1544a36ef052619adb0647b58ec666902402e8ad642c85aa576f0301d3708211e83b5f3d0e6d95b
6
+ metadata.gz: 87975b6d967a5944c5cc5f1b0bc154eeff73437fd3a0bde826195236e070533cfc2ffbaa1188a3791d8bfb439179005210712a9a91894a9212881113b74a1910
7
+ data.tar.gz: d77ff76539f6f847ded56cada8746cd64a2398ddd2fe1fd33758f129ba737e996e083797e7dabe0769f9e41ab06f73b50b2f56635f8e9d5ab2e23f9c787408fa
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,61 @@
1
1
  # Mobility Changelog
2
2
 
3
+ ## 1.3
4
+
5
+ ### 1.3.1
6
+
7
+ - Use classify to generate table name
8
+ ([#634](https://github.com/shioyama/mobility/pull/634)), thanks
9
+ [divanburger](https://github.com/divanburger)!
10
+ - Fix select + count in ActiveRecord
11
+ 8 ([#659](https://github.com/shioyama/mobility/pull/659))
12
+
13
+ ### 1.3.0
14
+
15
+ - Only support ActiveRecord >= 7.0
16
+ - Allow `I18n.available_locales` to contain Strings
17
+ ([#612](https://github.com/shioyama/mobility/pull/612))
18
+ - Update CI config, add support for Rails 8
19
+ ([#653](https://github.com/shioyama/mobility/pull/653)), thanks
20
+ [d-rodriguez](https://github.com/n-rodriguez)!
21
+ - Fix broken count statements in Active Record 8.0
22
+ ([#655](https://github.com/shioyama/mobility/pull/655)), thanks
23
+ [jukra](https://github.com/jukra)!
24
+
25
+ ### 1.3.0.rc3
26
+
27
+ - Don't try to load generators if Rails is loaded but AR is not
28
+ ([#627](https://github.com/shioyama/mobility/pull/627)), thanks
29
+ [flop](https://github.com/flop)!
30
+ - Allow compound foreign keys
31
+ ([#632](https://github.com/shioyama/mobility/pull/632)), thanks
32
+ [mival](https://github.com/mival)!
33
+ - Fix active model `*_previously_changed?` and active record
34
+ `will_save_change_to_*?` and `saved_change_to_*?` dirty methods to accept
35
+ kwargs ([#639](https://github.com/shioyama/mobility/pull/639)) thanks
36
+ [doits](https://github.com/doits)!
37
+
38
+ ### 1.3.0.rc2
39
+
40
+ - Pass `coder` as keyword argument to `serialize` (ActiveRecord version > 7.1)
41
+ ([#617](https://github.com/shioyama/mobility/pull/617))
42
+
43
+ ### 1.3.0.rc1
44
+
45
+ This version includes potentially breaking chnages for jsonb and hstore
46
+ backends. See PRs below for details.
47
+
48
+ - Fix ActiveRecord JSONB blank values
49
+ ([#536](https://github.com/shioyama/mobility/pull/536))
50
+ - Support primary keys other then :id on model classes
51
+ ([#542](https://github.com/shioyama/mobility/pull/542))
52
+ - Clean up and refactor container backend
53
+ ([#543](https://github.com/shioyama/mobility/pull/543)),
54
+ thanks [doits](https://github.com/doits)!
55
+ - Update fallthrough_accessor regex to allow for ISO 639-2 codes
56
+ ([#580](https://github.com/shioyama/mobility/pull/580))
57
+ thanks [phil-allcock](https://github.com/phil-allcock)!
58
+
3
59
  ## 1.2
4
60
 
5
61
  ### 1.2.9
@@ -11,7 +67,8 @@
11
67
  - Fix issues with subclassing, such as when using AR STI,
12
68
  fixes [#566](https://github.com/shioyama/mobility/issues/566)
13
69
  ([#568](https://github.com/shioyama/mobility/pull/568))
14
- - Handle attribute_method_matchers rename (part of #560)
70
+ - Handle `attribute_method_matchers` rename (part of
71
+ [#560](https://github.com/shioyama/mobility/pull/560))
15
72
 
16
73
  ### 1.2.7
17
74
  - Do not query same attribute more than once, fixes
data/Gemfile CHANGED
@@ -10,7 +10,7 @@ group :development, :test do
10
10
  when 'active_record'
11
11
  orm_version ||= '7.0'
12
12
  case orm_version
13
- when '4.2', '5.0', '5.1', '5.2', '6.0', '6.1', '7.0'
13
+ when '6.1', '7.0', '7.1', '7.2', '8.0'
14
14
  gem 'activerecord', "~> #{orm_version}.0"
15
15
  when 'edge'
16
16
  git 'https://github.com/rails/rails.git', branch: 'main' do
@@ -45,19 +45,15 @@ group :development, :test do
45
45
  gem 'pry-byebug'
46
46
  case ENV['DB']
47
47
  when 'sqlite3'
48
- if orm == 'active_record' && orm_version < '5.2'
49
- gem 'sqlite3', '~> 1.3.13'
48
+ if orm == 'active_record' && orm_version >= '8.0'
49
+ gem 'sqlite3', '>= 2.1.0'
50
50
  else
51
- gem 'sqlite3', '~> 1.4.1'
51
+ gem 'sqlite3', '~> 1.5.0'
52
52
  end
53
53
  when 'mysql'
54
54
  gem 'mysql2'
55
55
  when 'postgres'
56
- if orm == 'active_record' && orm_version < '5.0'
57
- gem 'pg', '< 1.0'
58
- else
59
- gem 'pg'
60
- end
56
+ gem 'pg'
61
57
  end
62
58
  end
63
59
  end
data/Gemfile.lock CHANGED
@@ -1,32 +1,46 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mobility (1.2.8)
4
+ mobility (1.3.0)
5
5
  i18n (>= 0.6.10, < 2)
6
6
  request_store (~> 1.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (7.0.3)
12
- activesupport (= 7.0.3)
13
- activerecord (7.0.3)
14
- activemodel (= 7.0.3)
15
- activesupport (= 7.0.3)
16
- activesupport (7.0.3)
17
- concurrent-ruby (~> 1.0, >= 1.0.2)
11
+ activemodel (8.0.0)
12
+ activesupport (= 8.0.0)
13
+ activerecord (8.0.0)
14
+ activemodel (= 8.0.0)
15
+ activesupport (= 8.0.0)
16
+ timeout (>= 0.4.0)
17
+ activesupport (8.0.0)
18
+ base64
19
+ benchmark (>= 0.3)
20
+ bigdecimal
21
+ concurrent-ruby (~> 1.0, >= 1.3.1)
22
+ connection_pool (>= 2.2.5)
23
+ drb
18
24
  i18n (>= 1.6, < 2)
25
+ logger (>= 1.4.2)
19
26
  minitest (>= 5.1)
20
- tzinfo (~> 2.0)
21
- benchmark-ips (2.10.0)
27
+ securerandom (>= 0.3)
28
+ tzinfo (~> 2.0, >= 2.0.5)
29
+ uri (>= 0.13.1)
30
+ base64 (0.2.0)
31
+ benchmark (0.4.0)
32
+ benchmark-ips (2.14.0)
33
+ bigdecimal (3.1.8)
22
34
  byebug (11.1.3)
23
35
  coderay (1.1.3)
24
- concurrent-ruby (1.1.10)
36
+ concurrent-ruby (1.3.4)
37
+ connection_pool (2.4.1)
25
38
  database_cleaner (1.99.0)
26
- diff-lcs (1.5.0)
27
- ffi (1.15.5)
39
+ diff-lcs (1.5.1)
40
+ drb (2.2.1)
41
+ ffi (1.17.0-x86_64-linux-gnu)
28
42
  formatador (1.1.0)
29
- guard (2.18.0)
43
+ guard (2.19.0)
30
44
  formatador (>= 0.2.4)
31
45
  listen (>= 2.7, < 4.0)
32
46
  lumberjack (>= 1.0.12, < 2.0)
@@ -40,67 +54,69 @@ GEM
40
54
  guard (~> 2.1)
41
55
  guard-compat (~> 1.1)
42
56
  rspec (>= 2.99.0, < 4.0)
43
- i18n (1.10.0)
57
+ i18n (1.14.6)
44
58
  concurrent-ruby (~> 1.0)
45
- listen (3.7.1)
59
+ listen (3.9.0)
46
60
  rb-fsevent (~> 0.10, >= 0.10.3)
47
61
  rb-inotify (~> 0.9, >= 0.9.10)
48
- lumberjack (1.2.8)
49
- method_source (1.0.0)
50
- minitest (5.16.1)
62
+ logger (1.6.1)
63
+ lumberjack (1.2.10)
64
+ method_source (1.1.0)
65
+ minitest (5.25.2)
51
66
  nenv (0.3.0)
52
67
  notiffany (0.1.3)
53
68
  nenv (~> 0.1)
54
69
  shellany (~> 0.0)
55
- pg (1.3.5)
56
- pry (0.13.1)
70
+ pry (0.14.2)
57
71
  coderay (~> 1.1)
58
72
  method_source (~> 1.0)
59
- pry-byebug (3.9.0)
73
+ pry-byebug (3.10.1)
60
74
  byebug (~> 11.0)
61
- pry (~> 0.13.0)
62
- rack (2.2.3.1)
75
+ pry (>= 0.13, < 0.15)
76
+ rack (2.2.7)
63
77
  rake (12.3.3)
64
- rb-fsevent (0.11.1)
65
- rb-inotify (0.10.1)
78
+ rb-fsevent (0.11.2)
79
+ rb-inotify (0.11.1)
66
80
  ffi (~> 1.0)
67
- request_store (1.5.1)
81
+ request_store (1.7.0)
68
82
  rack (>= 1.4)
69
- rspec (3.11.0)
70
- rspec-core (~> 3.11.0)
71
- rspec-expectations (~> 3.11.0)
72
- rspec-mocks (~> 3.11.0)
73
- rspec-core (3.11.0)
74
- rspec-support (~> 3.11.0)
75
- rspec-expectations (3.11.0)
83
+ rspec (3.13.0)
84
+ rspec-core (~> 3.13.0)
85
+ rspec-expectations (~> 3.13.0)
86
+ rspec-mocks (~> 3.13.0)
87
+ rspec-core (3.13.2)
88
+ rspec-support (~> 3.13.0)
89
+ rspec-expectations (3.13.3)
76
90
  diff-lcs (>= 1.2.0, < 2.0)
77
- rspec-support (~> 3.11.0)
78
- rspec-mocks (3.11.1)
91
+ rspec-support (~> 3.13.0)
92
+ rspec-mocks (3.13.2)
79
93
  diff-lcs (>= 1.2.0, < 2.0)
80
- rspec-support (~> 3.11.0)
81
- rspec-support (3.11.0)
94
+ rspec-support (~> 3.13.0)
95
+ rspec-support (3.13.1)
96
+ securerandom (0.3.2)
82
97
  shellany (0.0.1)
83
- thor (1.2.1)
84
- tzinfo (2.0.4)
98
+ sqlite3 (2.3.1-x86_64-linux-gnu)
99
+ thor (1.3.2)
100
+ timeout (0.4.2)
101
+ tzinfo (2.0.6)
85
102
  concurrent-ruby (~> 1.0)
86
- webrick (1.7.0)
87
- yard (0.9.28)
88
- webrick (~> 1.7.0)
103
+ uri (1.0.2)
104
+ yard (0.9.37)
89
105
 
90
106
  PLATFORMS
91
- ruby
107
+ x86_64-linux
92
108
 
93
109
  DEPENDENCIES
94
- activerecord (~> 7.0.0)
110
+ activerecord (~> 8.0.0)
95
111
  benchmark-ips
96
112
  database_cleaner (~> 1.5, >= 1.5.3)
97
113
  guard-rspec
98
114
  mobility!
99
- pg
100
115
  pry-byebug
101
116
  rake (~> 12, >= 12.2.1)
102
117
  rspec (~> 3.0)
118
+ sqlite3 (>= 2.1.0)
103
119
  yard (~> 0.9.0)
104
120
 
105
121
  BUNDLED WITH
106
- 2.1.4
122
+ 2.4.10
data/README.md CHANGED
@@ -4,7 +4,6 @@ Mobility
4
4
  [![Gem Version](https://badge.fury.io/rb/mobility.svg)][gem]
5
5
  [![Build Status](https://github.com/shioyama/mobility/workflows/CI/badge.svg)][actions]
6
6
  [![Code Climate](https://api.codeclimate.com/v1/badges/72200f2b00c339ec4537/maintainability.svg)][codeclimate]
7
- [![Gitter Chat](https://badges.gitter.im/mobility-ruby/mobility.svg)](https://gitter.im/mobility-ruby/mobility)
8
7
 
9
8
  [gem]: https://rubygems.org/gems/mobility
10
9
  [actions]: https://github.com/shioyama/mobility/actions
@@ -55,17 +54,13 @@ Installation
55
54
  Add this line to your application's Gemfile:
56
55
 
57
56
  ```ruby
58
- gem 'mobility', '~> 1.2.9'
57
+ gem 'mobility', '~> 1.3.1'
59
58
  ```
60
59
 
61
60
  ### ActiveRecord (Rails)
62
61
 
63
62
  Requirements:
64
- - ActiveRecord >= 5.0 (including 6.x)
65
-
66
- (Support for most backends and features is also supported with
67
- ActiveRecord/Rails 4.2, but there are some tests still failing. To see exactly
68
- what might not work, check pending specs in Rails 4.2 builds.)
63
+ - ActiveRecord >= 7.0
69
64
 
70
65
  To translate attributes on a model, extend `Mobility`, then call `translates`
71
66
  passing in one or more attributes as well as a hash of options (see below).
@@ -1027,6 +1022,7 @@ Integrations
1027
1022
  * [mobility-actiontext](https://github.com/sedubois/mobility-actiontext): Translate
1028
1023
  Rails [Action Text](https://guides.rubyonrails.org/action_text_overview.html) rich text
1029
1024
  with Mobility.
1025
+ * [mobility_typed](https://github.com/GeorgeGorbanev/mobility_typed): Add type checking to Rails models accessors.
1030
1026
 
1031
1027
  Tutorials
1032
1028
  ---------
@@ -22,7 +22,11 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
22
22
  # @param [Hash] options
23
23
  # @return [String,Integer,Boolean] Value of translation
24
24
  def read(locale, _ = nil)
25
- model_translations(locale)[attribute]
25
+ locale_translations = model_translations(locale)
26
+
27
+ return unless locale_translations
28
+
29
+ locale_translations[attribute.to_s]
26
30
  end
27
31
 
28
32
  # @note Translation may be a string, integer, boolean, hash or array
@@ -33,7 +37,7 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
33
37
  # @return [String,Integer,Boolean] Updated value
34
38
  def write(locale, value, _ = nil)
35
39
  set_attribute_translation(locale, value)
36
- model_translations(locale)[attribute]
40
+ read(locale)
37
41
  end
38
42
  # @!endgroup
39
43
 
@@ -42,8 +46,7 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
42
46
  # @option options [Symbol] column_name (:translations) Name of column on which to store translations
43
47
  # @raise [InvalidColumnType] if the type of the container column is not json or jsonb
44
48
  def configure(options)
45
- options[:column_name] ||= :translations
46
- options[:column_name] = options[:column_name].to_sym
49
+ options[:column_name] = options[:column_name]&.to_sym || :translations
47
50
  end
48
51
  # @!endgroup
49
52
 
@@ -78,61 +81,31 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
78
81
 
79
82
  # @!macro backend_iterator
80
83
  def each_locale
81
- model[column_name].each do |l, v|
82
- yield l.to_sym if v.present?
83
- end
84
- end
85
-
86
- setup do |_attributes, options|
87
- store options[:column_name], coder: Coder
88
-
89
- # Fix for duping depth-2 jsonb column in AR < 5.0
90
- if ::ActiveRecord::VERSION::STRING < '5.0'
91
- column_name = options[:column_name]
92
- module_name = "MobilityArContainer#{column_name.to_s.camelcase}"
93
- unless const_defined?(module_name)
94
- dupable = Module.new do
95
- class_eval <<-EOM, __FILE__, __LINE__ + 1
96
- def initialize_dup(source)
97
- super
98
- self.#{column_name} = source.#{column_name}.deep_dup
99
- end
100
- EOM
101
- end
102
- include const_set(module_name, dupable)
103
- end
84
+ model[column_name].each_key do |l|
85
+ yield l.to_sym
104
86
  end
105
87
  end
106
88
 
107
89
  private
108
90
 
109
91
  def model_translations(locale)
110
- model[column_name][locale] ||= {}
92
+ model[column_name][locale.to_s]
111
93
  end
112
94
 
113
95
  def set_attribute_translation(locale, value)
114
- translations = model[column_name] || {}
115
- translations[locale.to_s] ||= {}
116
- translations[locale.to_s][attribute] = value
117
- model[column_name] = translations
118
- end
96
+ locale_translations = model_translations(locale)
119
97
 
120
- class Coder
121
- def self.dump(obj)
122
- if obj.is_a? ::Hash
123
- obj.inject({}) do |translations, (locale, value)|
124
- value.each do |k, v|
125
- (translations[locale] ||= {})[k] = v if v.present?
126
- end
127
- translations
128
- end
98
+ if locale_translations
99
+ if value.nil?
100
+ locale_translations.delete(attribute.to_s)
101
+
102
+ # delete empty locale hash if last attribute was just deleted
103
+ model[column_name].delete(locale.to_s) if locale_translations.empty?
129
104
  else
130
- raise ArgumentError, "Attribute is supposed to be a Hash, but was a #{obj.class}. -- #{obj.inspect}"
105
+ locale_translations[attribute.to_s] = value
131
106
  end
132
- end
133
-
134
- def self.load(obj)
135
- obj
107
+ elsif !value.nil?
108
+ model[column_name][locale.to_s] = { attribute.to_s => value }
136
109
  end
137
110
  end
138
111
 
@@ -138,7 +138,7 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
138
138
  on(t[key_column].eq(key).
139
139
  and(t[:locale].eq(locale).
140
140
  and(t[:"#{belongs_to}_type"].eq(model_class.base_class.name).
141
- and(t[:"#{belongs_to}_id"].eq(m[:id]))))).join_sources)
141
+ and(t[:"#{belongs_to}_id"].eq(m[model_class.primary_key] || m[:id]))))).join_sources)
142
142
  end
143
143
 
144
144
  def already_joined?(relation, name, locale, join_type)
@@ -15,34 +15,25 @@ Internal class used by ActiveRecord backends backed by a Postgres data type
15
15
  include ActiveRecord
16
16
  include HashValued
17
17
 
18
- # @!macro backend_iterator
19
- def each_locale
20
- super { |l| yield l.to_sym }
18
+ def read(locale, _options = nil)
19
+ translations[locale.to_s]
21
20
  end
22
21
 
23
- def translations
24
- model.read_attribute(column_name)
22
+ def write(locale, value, _options = nil)
23
+ if value.nil?
24
+ translations.delete(locale.to_s)
25
+ else
26
+ translations[locale.to_s] = value
27
+ end
25
28
  end
26
29
 
27
- setup do |attributes, options = {}|
28
- attributes.each { |attribute| store (options[:column_affix] % attribute), coder: Coder }
30
+ # @!macro backend_iterator
31
+ def each_locale
32
+ super { |l| yield l.to_sym }
29
33
  end
30
34
 
31
- class Coder
32
- def self.dump(obj)
33
- if obj.is_a? ::Hash
34
- obj.inject({}) do |translations, (locale, value)|
35
- translations[locale] = value unless value.nil?
36
- translations
37
- end
38
- else
39
- raise ArgumentError, "Attribute is supposed to be a Hash, but was a #{obj.class}. -- #{obj.inspect}"
40
- end
41
- end
42
-
43
- def self.load(obj)
44
- obj
45
- end
35
+ def translations
36
+ model[column_name]
46
37
  end
47
38
  end
48
39
  private_constant :PgHash
@@ -51,7 +51,13 @@ Implements {Mobility::Backends::Serialized} backend for ActiveRecord models.
51
51
 
52
52
  setup do |attributes, options|
53
53
  coder = { yaml: YAMLCoder, json: JSONCoder }[options[:format]]
54
- attributes.each { |attribute| serialize (options[:column_affix] % attribute), coder }
54
+ attributes.each do |attribute|
55
+ if (::ActiveRecord::VERSION::STRING >= "7.1")
56
+ serialize (options[:column_affix] % attribute), coder: coder
57
+ else
58
+ serialize (options[:column_affix] % attribute), coder
59
+ end
60
+ end
55
61
  end
56
62
 
57
63
  # @!group Cache Methods
@@ -102,14 +102,20 @@ columns to that table.
102
102
  def configure(options)
103
103
  table_name = model_class.table_name
104
104
  options[:table_name] ||= "#{table_name.singularize}_translations"
105
- options[:foreign_key] ||= table_name.downcase.singularize.camelize.foreign_key
105
+ options[:foreign_key] ||= table_name.classify.foreign_key
106
106
  if (association_name = options[:association_name]).present?
107
107
  options[:subclass_name] ||= association_name.to_s.singularize.camelize.freeze
108
108
  else
109
109
  options[:association_name] = :translations
110
110
  options[:subclass_name] ||= :Translation
111
111
  end
112
- %i[foreign_key association_name subclass_name table_name].each { |key| options[key] = options[key].to_sym }
112
+ %i[foreign_key association_name subclass_name table_name].each { |key|
113
+ if options[key].is_a?(Enumerable)
114
+ options[key] = options[key].map!(&:to_sym)
115
+ else
116
+ options[key] = options[key].to_sym
117
+ end
118
+ }
113
119
  end
114
120
  # @!endgroup
115
121
 
@@ -145,7 +151,7 @@ columns to that table.
145
151
  m = model_class.arel_table
146
152
  t = model_class.const_get(subclass_name).arel_table.alias(table_alias(locale))
147
153
  relation.joins(m.join(t, join_type).
148
- on(t[foreign_key].eq(m[:id]).
154
+ on(t[foreign_key].eq(m[model_class.primary_key] || m[:id]).
149
155
  and(t[:locale].eq(locale))).join_sources)
150
156
  end
151
157
 
@@ -119,6 +119,14 @@ the ActiveRecord dirty plugin for more information.
119
119
  class HandlerMethodsBuilder < Module
120
120
  attr_reader :klass
121
121
 
122
+ PATTERNS_WITH_KWARGS =
123
+ %w[
124
+ %s_changed?
125
+ %s_previously_changed?
126
+ will_save_change_to_%s?
127
+ saved_change_to_%s?
128
+ ].freeze
129
+
122
130
  # @param [Class] klass Dirty class to mimic
123
131
  def initialize(klass)
124
132
  @klass = klass
@@ -135,7 +143,7 @@ the ActiveRecord dirty plugin for more information.
135
143
  public_patterns.each do |pattern|
136
144
  method_name = pattern % 'attribute'
137
145
 
138
- kwargs = pattern == '%s_changed?' ? ', **kwargs' : ''
146
+ kwargs = PATTERNS_WITH_KWARGS.include?(pattern) ? ', **kwargs' : ''
139
147
  module_eval <<-EOM, __FILE__, __LINE__ + 1
140
148
  def #{method_name}(attr_name, *rest#{kwargs})
141
149
  if (mutations_from_mobility.attribute_changed?(attr_name) ||
@@ -298,8 +306,10 @@ the ActiveRecord dirty plugin for more information.
298
306
  (OPTION_NOT_GIVEN == to || fetch_value(attr_name) == to)
299
307
  end
300
308
 
301
- def attribute_previously_changed?(attr_name)
302
- previous_changes.include?(attr_name)
309
+ def attribute_previously_changed?(attr_name, from: OPTION_NOT_GIVEN, to: OPTION_NOT_GIVEN)
310
+ previous_changes.include?(attr_name) &&
311
+ (OPTION_NOT_GIVEN == from || attribute_previous_change(attr_name).first == from) &&
312
+ (OPTION_NOT_GIVEN == to || attribute_previous_change(attr_name).second == to)
303
313
  end
304
314
 
305
315
  def attribute_was(attr_name)
@@ -79,28 +79,24 @@ locale suffix, so +title_en+, +title_pt_br+, etc.)
79
79
  )
80
80
 
81
81
  module InstanceMethods
82
- if ::ActiveRecord::VERSION::STRING >= '5.1' # define patterns added in 5.1
83
- def saved_changes
84
- super.merge(mutations_from_mobility.previous_changes)
85
- end
82
+ def saved_changes
83
+ super.merge(mutations_from_mobility.previous_changes)
84
+ end
86
85
 
87
- def changes_to_save
88
- super.merge(mutations_from_mobility.changes)
89
- end
86
+ def changes_to_save
87
+ super.merge(mutations_from_mobility.changes)
88
+ end
90
89
 
91
- def changed_attribute_names_to_save
92
- super + mutations_from_mobility.changed
93
- end
90
+ def changed_attribute_names_to_save
91
+ super + mutations_from_mobility.changed
92
+ end
94
93
 
95
- def attributes_in_database
96
- super.merge(mutations_from_mobility.changed_attributes)
97
- end
94
+ def attributes_in_database
95
+ super.merge(mutations_from_mobility.changed_attributes)
96
+ end
98
97
 
99
- if ::ActiveRecord::VERSION::STRING >= '6.0'
100
- def has_changes_to_save?
101
- super || mutations_from_mobility.changed?
102
- end
103
- end
98
+ def has_changes_to_save?
99
+ super || mutations_from_mobility.changed?
104
100
  end
105
101
 
106
102
  def reload(*)
@@ -21,6 +21,9 @@ enabled for any one attribute on the model.
21
21
 
22
22
  requires :query, include: false
23
23
 
24
+ ATTRIBUTE_ALIAS_PREFIX = "__mobility_"
25
+ ATTRIBUTE_ALIAS = "#{ATTRIBUTE_ALIAS_PREFIX}%s_%s__"
26
+
24
27
  included_hook do |klass, backend_class|
25
28
  plugin = self
26
29
  if options[:query]
@@ -39,7 +42,7 @@ enabled for any one attribute on the model.
39
42
 
40
43
  class << self
41
44
  def attribute_alias(attribute, locale = Mobility.locale)
42
- "__mobility_%s_%s__" % [attribute, ::Mobility.normalize_locale(locale)]
45
+ ATTRIBUTE_ALIAS % [attribute, ::Mobility.normalize_locale(locale)]
43
46
  end
44
47
 
45
48
  def build_query(klass, locale = Mobility.locale, &block)
@@ -137,19 +140,19 @@ enabled for any one attribute on the model.
137
140
  end
138
141
 
139
142
  def order(opts, *rest)
140
- return super unless @klass.respond_to?(:mobility_attribute?)
143
+ return super unless klass.respond_to?(:mobility_attribute?)
141
144
 
142
145
  case opts
143
146
  when Symbol, String
144
- @klass.mobility_attribute?(opts) ? order({ opts => :asc }, *rest) : super
147
+ klass.mobility_attribute?(opts) ? order({ opts => :asc }, *rest) : super
145
148
  when ::Hash
146
- i18n_keys, keys = opts.keys.partition(&@klass.method(:mobility_attribute?))
149
+ i18n_keys, keys = opts.keys.partition(&klass.method(:mobility_attribute?))
147
150
  return super if i18n_keys.empty?
148
151
 
149
152
  base = keys.empty? ? self : super(opts.slice(keys))
150
153
 
151
154
  i18n_keys.inject(base) do |query, key|
152
- backend_class = @klass.mobility_backend_class(key)
155
+ backend_class = klass.mobility_backend_class(key)
153
156
  dir, node = opts[key], backend_node(key)
154
157
  backend_class.apply_scope(query, node).order(node.send(dir.downcase))
155
158
  end
@@ -158,28 +161,47 @@ enabled for any one attribute on the model.
158
161
  end
159
162
  end
160
163
 
161
- if ::ActiveRecord::VERSION::STRING >= '5.0'
162
- %w[pluck group select].each do |method_name|
163
- define_method method_name do |*attrs, &block|
164
- return super(*attrs, &block) if (method_name == 'select' && block.present?)
164
+ %w[pluck group select].each do |method_name|
165
+ define_method method_name do |*attrs, &block|
166
+ return super(*attrs, &block) if (method_name == 'select' && block.present?)
165
167
 
166
- return super(*attrs, &block) unless @klass.respond_to?(:mobility_attribute?)
168
+ return super(*attrs, &block) unless klass.respond_to?(:mobility_attribute?)
167
169
 
168
- return super(*attrs, &block) unless attrs.any?(&@klass.method(:mobility_attribute?))
170
+ return super(*attrs, &block) unless attrs.any?(&klass.method(:mobility_attribute?))
169
171
 
170
- keys = attrs.dup
172
+ keys = attrs.dup
171
173
 
172
- base = keys.each_with_index.inject(self) do |query, (key, index)|
173
- next query unless @klass.mobility_attribute?(key)
174
- keys[index] = backend_node(key)
175
- if method_name == "select"
176
- keys[index] = keys[index]
177
- .as(::Mobility::Plugins::ActiveRecord::Query.attribute_alias(key.to_s))
178
- end
179
- @klass.mobility_backend_class(key).apply_scope(query, backend_node(key))
174
+ base = keys.each_with_index.inject(self) do |query, (key, index)|
175
+ next query unless klass.mobility_attribute?(key)
176
+ keys[index] = backend_node(key)
177
+ if method_name == "select"
178
+ keys[index] = keys[index]
179
+ .as(::Mobility::Plugins::ActiveRecord::Query.attribute_alias(key.to_s))
180
180
  end
181
+ klass.mobility_backend_class(key).apply_scope(query, backend_node(key))
182
+ end
183
+
184
+ base.public_send(method_name, *keys, &block)
185
+ end
186
+ end
181
187
 
182
- base.public_send(method_name, *keys, &block)
188
+ if ::ActiveRecord::VERSION::MAJOR >= 8
189
+ # Fix for https://github.com/shioyama/mobility/pull/654#issuecomment-2503479112
190
+ # TODO: Make this better
191
+ def select_for_count
192
+ return super unless klass.respond_to?(:mobility_attribute?)
193
+
194
+ if select_values.any? { |value| value.right.start_with?(ATTRIBUTE_ALIAS_PREFIX) }
195
+ filtered_select_values = select_values.map do |value|
196
+ value.right.start_with?(ATTRIBUTE_ALIAS_PREFIX) ? value.left : value
197
+ end
198
+
199
+ # Copied from lib/active_record/relation/calculations.rb
200
+ with_connection do |conn|
201
+ arel_columns(filtered_select_values).map { |column| conn.visitor.compile(column) }.join(", ")
202
+ end
203
+ else
204
+ super
183
205
  end
184
206
  end
185
207
  end
@@ -189,7 +211,7 @@ enabled for any one attribute on the model.
189
211
  # @param [Symbol] locale Locale
190
212
  # @return [Arel::Node] Arel node for this attribute in given locale
191
213
  def backend_node(name, locale = Mobility.locale)
192
- @klass.mobility_backend_class(name)[name, locale]
214
+ klass.mobility_backend_class(name)[name, locale]
193
215
  end
194
216
 
195
217
  class WhereChain < ::ActiveRecord::QueryMethods::WhereChain
@@ -26,17 +26,6 @@ module Mobility
26
26
  end)
27
27
  end
28
28
 
29
- # Needed for AR 4.2, can be removed when support is deprecated
30
- if ::ActiveRecord::VERSION::STRING < '5.0'
31
- [JsonbDashDoubleArrow, HstoreDashArrow].each do |klass|
32
- klass.class_eval do
33
- def quoted_node other
34
- other && super
35
- end
36
- end
37
- end
38
- end
39
-
40
29
  class Jsonb < JsonbDashDoubleArrow
41
30
  def to_dash_arrow
42
31
  JsonbDashArrow.new left, right
@@ -45,7 +45,7 @@ Defines:
45
45
  klass.extend ClassMethods
46
46
 
47
47
  if backend
48
- @backend_class = backend.build_subclass(klass, backend_options)
48
+ @backend_class = backend.build_subclass(klass, **backend_options)
49
49
 
50
50
  backend_class.setup_model(klass, names)
51
51
 
@@ -36,7 +36,7 @@ model class is generated.
36
36
  private
37
37
 
38
38
  def define_fallthrough_accessors(*names)
39
- method_name_regex = /\A(#{names.join('|')})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
39
+ method_name_regex = /\A(#{names.join('|')})_([a-z]{2,3}(_[a-z]{2})?)(=?|\??)\z/.freeze
40
40
 
41
41
  define_method :method_missing do |method_name, *args, &block|
42
42
  if method_name =~ method_name_regex
@@ -7,8 +7,8 @@ module Mobility
7
7
 
8
8
  module VERSION
9
9
  MAJOR = 1
10
- MINOR = 2
11
- TINY = 9
10
+ MINOR = 3
11
+ TINY = 1
12
12
  PRE = nil
13
13
 
14
14
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
data/lib/mobility.rb CHANGED
@@ -90,7 +90,7 @@ module Mobility
90
90
  CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
91
91
  private_constant :CALL_COMPILABLE_REGEXP
92
92
 
93
- require "rails/generators/mobility/generators" if defined?(Rails)
93
+ require "rails/generators/mobility/generators" if defined?(Rails) && defined?(ActiveRecord)
94
94
 
95
95
  class << self
96
96
  def extended(model_class)
@@ -228,9 +228,9 @@ module Mobility
228
228
  # methods (in LocaleAccessors) than is really necessary.
229
229
  def available_locales
230
230
  if defined?(Rails) && Rails.respond_to?(:application) && Rails.application
231
- Rails.application.config.i18n.available_locales&.map(&:to_sym) || I18n.available_locales
231
+ Rails.application.config.i18n.available_locales&.map(&:to_sym) || I18n.available_locales.map(&:to_sym)
232
232
  else
233
- I18n.available_locales
233
+ I18n.available_locales.map(&:to_sym)
234
234
  end
235
235
  end
236
236
 
@@ -58,6 +58,19 @@ Mobility.configure do
58
58
  # Or uncomment this line to include but disable by default, and only enable
59
59
  # per model by passing +dirty: true+ to +translates+.
60
60
  # dirty false
61
+
62
+ # Column Fallback
63
+ #
64
+ # Uncomment line below to fallback to original column. You can pass
65
+ # +column_fallback: true+ to +translates+ to return original column on
66
+ # default locale, or pass +column_fallback: [:en, :de]+ to +translates+
67
+ # to return original column for those locales or pass
68
+ # +column_fallback: ->(locale) { ... }+ to +translates to evaluate which
69
+ # locales to return original column for.
70
+ # column_fallback
71
+ #
72
+ # Or uncomment this line to enable column fallback with a global default.
73
+ # column_fallback true
61
74
 
62
75
  # Fallbacks
63
76
  #
@@ -65,7 +78,7 @@ Mobility.configure do
65
78
  # fallbacks
66
79
  #
67
80
  # Or uncomment this line to enable fallbacks with a global default.
68
- # fallbacks { :pt => :en }
81
+ # fallbacks(pt: :en)
69
82
 
70
83
  # Presence
71
84
  #
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mobility
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.9
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Salzberg
@@ -10,31 +10,32 @@ bindir: exe
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhjaHJp
14
- cy9EQz1kZWppbWF0YS9EQz1jb20wHhcNMjIwMzAyMDMyMTA5WhcNMjMwMzAyMDMy
15
- MTA5WjAjMSEwHwYDVQQDDBhjaHJpcy9EQz1kZWppbWF0YS9EQz1jb20wggGiMA0G
16
- CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDURCKbt5oY0sCp4kYK1u5SLzVHg6Q1
17
- 2LejeQvUGpR3gulWqrq/507XRxE/9FSpLfgo3cGGYio1/gg2Yp7pBI4ZNEz8d2Vg
18
- 6caWLHYtHYF0/jlo177UspEF1bt3lCCmaA/ZyQpvoLi76Jf6VCBjepMqhLjeBSsA
19
- xUqSdgNT8lzduOzdYk/GWf2Trvyz72IN6rY7hSwJ/U4R2DusRNTbKC55iyu0MyqI
20
- Nks33les0xQERucqes1YzSEnpott/GUQ/fFWV1Qx7M1hMnqbQIm493BueR6X95a2
21
- B7/aqY7LUVVmn9p65NMBJhbbP/pbAcLYV0C+y1Jy9NaVQTpWmJXVKBpYwlAzOJOQ
22
- +b/7MBzT5Zzudkq9OlA5rZJB0hFo/Bm38MOCTSTk1/RT+zmoOyb4bx/h400L4ZUt
23
- bRGON33BZ99gPiYdGfd3Pc/7FooteJASjKIO4Hman2ELRIdu6Bq+fIkTdJBcruS/
24
- XL6xoRitCG7CX0IqmMKuLiKA/J0amAikHGsCAwEAAaN3MHUwCQYDVR0TBAIwADAL
25
- BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFMNUGAhS68egZT6DOfJwrfIdCtT/MB0GA1Ud
26
- EQQWMBSBEmNocmlzQGRlamltYXRhLmNvbTAdBgNVHRIEFjAUgRJjaHJpc0BkZWpp
27
- bWF0YS5jb20wDQYJKoZIhvcNAQELBQADggGBAHJPxoU7brN6goci9iclRYUq1Prs
28
- 51E87VRywUDysHpaHJoGRTqRJsQxi5aGZ9pIbiXGj9WJKKnrhiv5cM5fWtAsz564
29
- Ro+Zyx6UVt/2z9rcfYrnXtmC9wh+5/0UqAeoan9RiSd8lscQZ9pEY0E3cmzJRHSU
30
- t8kwB2ipVkFO17mdTVgc3C2ZbWRq80eTzkELDBb+8xO0Cskyh4sGMTOKfHs2RWcJ
31
- 217Qeg0F9w0RcqwnORe5zmPihY9zswCPh0IUaJa1pNY+MLTff9LE/qTl3WVTgrif
32
- HsSSnstQYPSLJ3hSP/cu1aOmdXlJiim//XlDQ9DNp4KWje3UW3DMRdTwjW5wPmUq
33
- VA9Ij7DUPaZzUpy1NZEigf1GshvslOnvN5bgol1YFR46jpfZVlgt0K5XBQVNvp/A
34
- QHgocnSksU5GOM+G2UhjVycbTamd+bCxjWAZTEDZNafFt5CmnfK1D1UTIblR/ci9
35
- fUDdW+GhxhobB8N1mtDRlhELoxLLjx7mSvJ3Wg==
13
+ MIIEcDCCAtigAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MQ4wDAYDVQQDDAVjaHJp
14
+ czEYMBYGCgmSJomT8ixkARkWCGRlamltYXRhMRMwEQYKCZImiZPyLGQBGRYDY29t
15
+ MB4XDTI0MDMzMTA4NTQyOFoXDTI1MDMzMTA4NTQyOFowPzEOMAwGA1UEAwwFY2hy
16
+ aXMxGDAWBgoJkiaJk/IsZAEZFghkZWppbWF0YTETMBEGCgmSJomT8ixkARkWA2Nv
17
+ bTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBANdI2sGYV1Dg+eFvs/t8
18
+ feflYB2ZHFMYZV5dB6a62L0f9I5pndIwc9qbo4HivzVICCz2yOP/v2Yxyi4UkucM
19
+ dGgFEAxpBlgNzrE2vrqPJHqMN9001O0vS3jvyKwNZ0WmPO26Sf75ky1QrjPRmHEV
20
+ rn15+bQGu5sRMxIj5TyRgtNmy9ORJBP+hEiGD09icRvn/FG6o0/NIRyLXnX2tuOu
21
+ VBD64XQU3mhxxJtp2+F0Hb0E1nmUttaWsuATMlnRJ8Ksli9kfoxFAa87Cm/LrK2l
22
+ WCar8Nc6kw6Rixq97MAZCplEXtg6KnenXzMJLvZFBRSZM6RGj1Q9IX8EpP6HoG/u
23
+ WYU/rXe4YZxKy0idDBLbBfjTRKJYQu7q6bgHNTWER7Dc6cACjMhunhfgnvr4Rzu9
24
+ F4UNHixNagaLq+3ng19oJJcxE/9BHVOjhZWzLRn0z122KuQJVBXiLipU4r1YIUnj
25
+ E0m0QDb4DrYmL1Omp+vVNKBbXnj9AW8J8I9v0Lc/5QsK8wIDAQABo3cwdTAJBgNV
26
+ HRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUJ5UzoaDdOqk4a8OQ95no0vg3
27
+ ROcwHQYDVR0RBBYwFIESY2hyaXNAZGVqaW1hdGEuY29tMB0GA1UdEgQWMBSBEmNo
28
+ cmlzQGRlamltYXRhLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAmx0ugOC2yOTQTetP
29
+ H8akUD7tRMeEki8Ba2F/+YP0x6cnsEBcKnp0CO5pMVY+6MssLgHh1IXDQlmKuPOW
30
+ oht9yh6CWgzufzi+XApY1k/TYWAjxOMZAMdvd7iHo7igRK5pPbSaP5uubQfaLn7X
31
+ ge1VLOBAn9XlSOvFZiYZ7Nk8zEvYrvLbQGVtcfceZK4BHC4M3pKsV+m7euWMYguz
32
+ ctOqZgbvGDwFvsH302xC53hld7AaFLBep6XaQZSRleVqgIEKZwlG0cX8UwG482Xt
33
+ WJSXNylIIbzRndVjbVdGVhhcyjnswfu1qJpl+0YlbAdHJVsd8Ux8TOXEPFMv5wz9
34
+ wXhTYFvkOuleWf/45E5f8BtT1iqsH2w3P2Cfy+yOo2aReAVSeR12YDCuV0q6RjTD
35
+ 3I5AfnFAG4/1IwhadqwF5cl3jOUa7n3mS2OJl3tRCGuPvwAA9MV10hmwbQTXMrNK
36
+ tD9kfT9eseUE4mfPnIaHOs4FiIoHniA7zdtjB7GIQ4cEpB6o
36
37
  -----END CERTIFICATE-----
37
- date: 2022-06-24 00:00:00.000000000 Z
38
+ date: 2024-12-01 00:00:00.000000000 Z
38
39
  dependencies:
39
40
  - !ruby/object:Gem::Dependency
40
41
  name: request_store
@@ -254,11 +255,11 @@ metadata:
254
255
  rubygems_mfa_required: 'true'
255
256
  post_install_message: |2
256
257
 
257
- Warning: Mobility v1.0 includes backwards-incompatible changes (mostly around configuration).
258
+ Warning: Mobility v1.3.x includes potentially backwards-incompatible changes
259
+ for jsonb/hstore backends.
258
260
 
259
- If you are upgrading from an earlier version, please see:
260
- - https://github.com/shioyama/mobility/releases/tag/v1.0.0
261
- - https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-v1.0
261
+ Please see:
262
+ - https://github.com/shioyama/mobility/issues/535
262
263
  rdoc_options: []
263
264
  require_paths:
264
265
  - lib
@@ -273,7 +274,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
273
274
  - !ruby/object:Gem::Version
274
275
  version: '0'
275
276
  requirements: []
276
- rubygems_version: 3.1.2
277
+ rubygems_version: 3.4.6
277
278
  signing_key:
278
279
  specification_version: 4
279
280
  summary: Pluggable Ruby translation framework
metadata.gz.sig CHANGED
Binary file