mobility 0.8.7 → 0.8.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -4
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +36 -0
- data/Gemfile +49 -14
- data/Gemfile.lock +39 -103
- data/Guardfile +70 -0
- data/README.md +2 -2
- data/Rakefile +6 -4
- data/lib/mobility.rb +4 -2
- data/lib/mobility/active_record/translation.rb +1 -1
- data/lib/mobility/arel/visitor.rb +2 -2
- data/lib/mobility/plugins/active_model/dirty.rb +265 -44
- data/lib/mobility/plugins/active_record/dirty.rb +52 -98
- data/lib/mobility/plugins/active_record/query.rb +5 -3
- data/lib/mobility/plugins/dirty.rb +1 -1
- data/lib/mobility/plugins/fallthrough_accessors.rb +8 -4
- data/lib/mobility/plugins/sequel/dirty.rb +17 -15
- data/lib/mobility/version.rb +1 -1
- metadata +27 -28
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd73c4e94757a4138786f7ebfeb2ac7bbdbcb219030af3319043232b696d70c2
|
4
|
+
data.tar.gz: c05a86a128d80fb859b531c25745474a561f92bf1c610a6d41250c4995f8b0a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cfcddf59bc7a203fd00508bbcb32c8e59658eded31cbf637fb5fe9e9ccfd4cde3b59f762113b1f32c1427d5e2fecfa67e9c91d6c9d8b58c05928cf90356370be
|
7
|
+
data.tar.gz: 887fbb7bb02fa80fc421b45f8f434972c4d163e11e0d6d5dc2618f94e7f86307feb2fc4801c988fd86d19735edb863519b60addacaebebb49d2cb27490af0210
|
checksums.yaml.gz.sig
CHANGED
@@ -1,4 +1,2 @@
|
|
1
|
-
��
|
2
|
-
|
3
|
-
Җ���=i<�P #�T5l��p%���ٯ���s7�گ���R@$��{<t
|
4
|
-
�T�:�+�9�u$�&��GEB a)���*eqQ[gz��6�F̮�uZ�A��� 7���o,��l͗C���0��O�^ y2�WM��{�j�`�ٳ���c�9��B/����N���Ni�\_$�^A:�gF����<a�wh��,\�'��0ʹ(JW�Z!�`UZ�#Eo��pFC�u0�B�d��&�*.���{|5(|J�'=&y]3?Ҥ�ye{^�|�m��&�+���O���z�g��U3����|�'m��Ajd��<st2���9��l\fp��R
|
1
|
+
>0��R(������p��*�χ-�s����d��������\ذ~m(���@�@U^����*��Z���k�r+4A"�R���6'��D�If��7ɣ��ta\�.���cۆ��i3Ê�Yxh��S U�s$y���dޣ��l���hH�f>͐�9.������h���F(|��A7��z�1���5~;c��dWw�J �K�ηp#�?)Eo�ʉ�"Y��`x����:��q7.G �b�c8*ꊢ�c����g�b$��q����sx���p
|
2
|
+
�MPm#��[a*���&������ë�aC]=X1J�Q!�S1ףev��v�7�p ���wn\�*�ל��$�k�
|
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,42 @@
|
|
2
2
|
|
3
3
|
## 0.8
|
4
4
|
|
5
|
+
### 0.8.13 (May 27, 2020)
|
6
|
+
|
7
|
+
* Fix fallthrough accessor method_missing not passing all options to super
|
8
|
+
([#364](https://github.com/shioyama/mobility/pull/364),
|
9
|
+
[#384](https://github.com/shioyama/mobility/pull/384),
|
10
|
+
[#377](https://github.com/shioyama/mobility/pull/377), thanks
|
11
|
+
[doits](https://github.com/doits)!)
|
12
|
+
|
13
|
+
### 0.8.12 (May 15, 2020)
|
14
|
+
|
15
|
+
(yanked)
|
16
|
+
|
17
|
+
### 0.8.11 (May 14, 2020)
|
18
|
+
* Handle select with block
|
19
|
+
([#359](https://github.com/shioyama/mobility/pull/359), thanks
|
20
|
+
[dlcmh](https://github.com/dlcmh)!)
|
21
|
+
|
22
|
+
### 0.8.10 (February 11, 2020)
|
23
|
+
* Enforce case_sensitive comparison for Rails 6.1
|
24
|
+
([#333](https://github.com/shioyama/mobility/pull/333), thanks [morozRed](https://github.com/morozRed)!)
|
25
|
+
|
26
|
+
### 0.8.9 (October 25, 2019)
|
27
|
+
* Fix Dirty plugin to work with Rails 6
|
28
|
+
([#343](https://github.com/shioyama/mobility/pull/343),
|
29
|
+
[#348](https://github.com/shioyama/mobility/pull/348),
|
30
|
+
[#352](https://github.com/shioyama/mobility/pull/352) on master branch, plus
|
31
|
+
[#351](https://github.com/shioyama/mobility/pull/351) to sync to 0-8-stable
|
32
|
+
branch). Summary of changes
|
33
|
+
[here](https://github.com/shioyama/mobility/pull/347#issuecomment-544742401).
|
34
|
+
|
35
|
+
### 0.8.8 (September 18, 2019)
|
36
|
+
* Accept any number of arguments to `Arel::Visitors::Visitor#visit`
|
37
|
+
([#339](https://github.com/shioyama/mobility/pull/339)). (Thanks to
|
38
|
+
[fauno](https://github.com/fauno) for [uncovering the
|
39
|
+
issue](https://github.com/shioyama/mobility/issues/334#issuecomment-526281737).)
|
40
|
+
|
5
41
|
### 0.8.7 (November 30, 2018)
|
6
42
|
* Handle case when attribute name passed to has_attribute is not a string
|
7
43
|
([#309](https://github.com/shioyama/mobility/pull/309)).
|
data/Gemfile
CHANGED
@@ -3,35 +3,70 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in mobility.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
+
orm, orm_version = ENV['ORM'], ENV['ORM_VERSION']
|
7
|
+
|
6
8
|
group :development, :test do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
case orm
|
10
|
+
when 'active_record'
|
11
|
+
orm_version ||= '6.0'
|
12
|
+
case orm_version
|
13
|
+
when '4.2'
|
11
14
|
gem 'activerecord', '>= 4.2.6', '< 5.0'
|
12
|
-
|
15
|
+
when '5.0'
|
16
|
+
gem 'activerecord', '>= 5.0', '< 5.1'
|
17
|
+
when '5.1'
|
13
18
|
gem 'activerecord', '>= 5.1', '< 5.2'
|
14
|
-
|
15
|
-
gem 'activerecord', '>= 5.2.0
|
19
|
+
when '5.2'
|
20
|
+
gem 'activerecord', '>= 5.2.0', '< 5.3'
|
16
21
|
gem 'railties', '>= 5.2.0.rc2', '< 5.3'
|
22
|
+
when '6.0'
|
23
|
+
gem 'activerecord', '>= 6.0.0', '< 6.1'
|
24
|
+
when '6.1'
|
25
|
+
git 'https://github.com/rails/rails.git' do
|
26
|
+
gem 'activerecord'
|
27
|
+
gem 'activesupport'
|
28
|
+
end
|
29
|
+
else
|
30
|
+
raise ArgumentError, 'Invalid ActiveRecord version'
|
17
31
|
end
|
32
|
+
|
18
33
|
gem "generator_spec", '~> 0.9.4'
|
19
|
-
|
20
|
-
|
34
|
+
when 'sequel'
|
35
|
+
orm_version ||= '5'
|
36
|
+
case orm_version
|
37
|
+
when '4'
|
21
38
|
gem 'sequel', '>= 4.46.0', '< 5.0'
|
22
|
-
|
39
|
+
when '5'
|
23
40
|
gem 'sequel', '>= 5.0.0', '< 6.0.0'
|
41
|
+
else
|
42
|
+
raise ArgumentError, 'Invalid Sequel version'
|
24
43
|
end
|
44
|
+
when nil, ''
|
45
|
+
else
|
46
|
+
raise ArgumentError, "Invalid ORM: #{orm}"
|
25
47
|
end
|
26
48
|
|
27
|
-
gem 'allocation_stats' if ENV['
|
49
|
+
gem 'allocation_stats' if ENV['FEATURE'] == 'performance'
|
28
50
|
|
29
51
|
platforms :ruby do
|
30
52
|
gem 'guard-rspec'
|
31
53
|
gem 'pry-byebug'
|
32
|
-
|
33
|
-
|
34
|
-
|
54
|
+
case ENV['DB']
|
55
|
+
when 'sqlite3'
|
56
|
+
if orm == 'active_record' && orm_version < '5.2'
|
57
|
+
gem 'sqlite3', '~> 1.3.13'
|
58
|
+
else
|
59
|
+
gem 'sqlite3', '~> 1.4.1'
|
60
|
+
end
|
61
|
+
when 'mysql'
|
62
|
+
gem 'mysql2'
|
63
|
+
when 'postgres'
|
64
|
+
if orm == 'active_record' && orm_version < '5.0'
|
65
|
+
gem 'pg', '< 1.0'
|
66
|
+
else
|
67
|
+
gem 'pg'
|
68
|
+
end
|
69
|
+
end
|
35
70
|
end
|
36
71
|
end
|
37
72
|
|
data/Gemfile.lock
CHANGED
@@ -8,46 +8,15 @@ PATH
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
|
12
|
-
|
13
|
-
activesupport (= 5.1.6.1)
|
14
|
-
rack (~> 2.0)
|
15
|
-
rack-test (>= 0.6.3)
|
16
|
-
rails-dom-testing (~> 2.0)
|
17
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
18
|
-
actionview (5.1.6.1)
|
19
|
-
activesupport (= 5.1.6.1)
|
20
|
-
builder (~> 3.1)
|
21
|
-
erubi (~> 1.4)
|
22
|
-
rails-dom-testing (~> 2.0)
|
23
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
24
|
-
activemodel (5.1.6.1)
|
25
|
-
activesupport (= 5.1.6.1)
|
26
|
-
activerecord (5.1.6.1)
|
27
|
-
activemodel (= 5.1.6.1)
|
28
|
-
activesupport (= 5.1.6.1)
|
29
|
-
arel (~> 8.0)
|
30
|
-
activesupport (5.1.6.1)
|
31
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
32
|
-
i18n (>= 0.7, < 2)
|
33
|
-
minitest (~> 5.1)
|
34
|
-
tzinfo (~> 1.1)
|
35
|
-
arel (8.0.0)
|
36
|
-
benchmark-ips (2.7.2)
|
37
|
-
builder (3.2.3)
|
38
|
-
byebug (10.0.2)
|
11
|
+
benchmark-ips (2.8.2)
|
12
|
+
byebug (11.1.3)
|
39
13
|
coderay (1.1.2)
|
40
|
-
concurrent-ruby (1.1.
|
41
|
-
|
42
|
-
database_cleaner (1.7.0)
|
14
|
+
concurrent-ruby (1.1.6)
|
15
|
+
database_cleaner (1.8.5)
|
43
16
|
diff-lcs (1.3)
|
44
|
-
|
45
|
-
ffi (1.9.25)
|
17
|
+
ffi (1.12.2)
|
46
18
|
formatador (0.2.5)
|
47
|
-
|
48
|
-
activesupport (>= 3.0.0)
|
49
|
-
railties (>= 3.0.0)
|
50
|
-
guard (2.15.0)
|
19
|
+
guard (2.16.2)
|
51
20
|
formatador (>= 0.2.4)
|
52
21
|
listen (>= 2.7, < 4.0)
|
53
22
|
lumberjack (>= 1.0.12, < 2.0)
|
@@ -61,92 +30,59 @@ GEM
|
|
61
30
|
guard (~> 2.1)
|
62
31
|
guard-compat (~> 1.1)
|
63
32
|
rspec (>= 2.99.0, < 4.0)
|
64
|
-
i18n (1.
|
33
|
+
i18n (1.8.2)
|
65
34
|
concurrent-ruby (~> 1.0)
|
66
|
-
listen (3.1
|
67
|
-
rb-fsevent (~> 0.
|
68
|
-
rb-inotify (~> 0.9, >= 0.9.
|
69
|
-
|
70
|
-
|
71
|
-
crass (~> 1.0.2)
|
72
|
-
nokogiri (>= 1.5.9)
|
73
|
-
lumberjack (1.0.13)
|
74
|
-
method_source (0.9.2)
|
75
|
-
mini_portile2 (2.3.0)
|
76
|
-
minitest (5.11.3)
|
77
|
-
mysql2 (0.4.10)
|
35
|
+
listen (3.2.1)
|
36
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
37
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
38
|
+
lumberjack (1.2.4)
|
39
|
+
method_source (1.0.0)
|
78
40
|
nenv (0.3.0)
|
79
|
-
|
80
|
-
mini_portile2 (~> 2.3.0)
|
81
|
-
notiffany (0.1.1)
|
41
|
+
notiffany (0.1.3)
|
82
42
|
nenv (~> 0.1)
|
83
43
|
shellany (~> 0.0)
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
nokogiri (>= 1.6)
|
97
|
-
rails-html-sanitizer (1.0.4)
|
98
|
-
loofah (~> 2.2, >= 2.2.2)
|
99
|
-
railties (5.1.6.1)
|
100
|
-
actionpack (= 5.1.6.1)
|
101
|
-
activesupport (= 5.1.6.1)
|
102
|
-
method_source
|
103
|
-
rake (>= 0.8.7)
|
104
|
-
thor (>= 0.18.1, < 2.0)
|
105
|
-
rake (12.3.1)
|
106
|
-
rb-fsevent (0.10.3)
|
107
|
-
rb-inotify (0.9.10)
|
108
|
-
ffi (>= 0.5.0, < 2)
|
109
|
-
request_store (1.4.1)
|
44
|
+
pry (0.13.1)
|
45
|
+
coderay (~> 1.1)
|
46
|
+
method_source (~> 1.0)
|
47
|
+
pry-byebug (3.9.0)
|
48
|
+
byebug (~> 11.0)
|
49
|
+
pry (~> 0.13.0)
|
50
|
+
rack (2.2.2)
|
51
|
+
rake (12.3.3)
|
52
|
+
rb-fsevent (0.10.4)
|
53
|
+
rb-inotify (0.10.1)
|
54
|
+
ffi (~> 1.0)
|
55
|
+
request_store (1.5.0)
|
110
56
|
rack (>= 1.4)
|
111
|
-
rspec (3.
|
112
|
-
rspec-core (~> 3.
|
113
|
-
rspec-expectations (~> 3.
|
114
|
-
rspec-mocks (~> 3.
|
115
|
-
rspec-core (3.
|
116
|
-
rspec-support (~> 3.
|
117
|
-
rspec-expectations (3.
|
57
|
+
rspec (3.9.0)
|
58
|
+
rspec-core (~> 3.9.0)
|
59
|
+
rspec-expectations (~> 3.9.0)
|
60
|
+
rspec-mocks (~> 3.9.0)
|
61
|
+
rspec-core (3.9.2)
|
62
|
+
rspec-support (~> 3.9.3)
|
63
|
+
rspec-expectations (3.9.2)
|
118
64
|
diff-lcs (>= 1.2.0, < 2.0)
|
119
|
-
rspec-support (~> 3.
|
120
|
-
rspec-mocks (3.
|
65
|
+
rspec-support (~> 3.9.0)
|
66
|
+
rspec-mocks (3.9.1)
|
121
67
|
diff-lcs (>= 1.2.0, < 2.0)
|
122
|
-
rspec-support (~> 3.
|
123
|
-
rspec-support (3.
|
124
|
-
ruby_dep (1.5.0)
|
68
|
+
rspec-support (~> 3.9.0)
|
69
|
+
rspec-support (3.9.3)
|
125
70
|
shellany (0.0.1)
|
126
|
-
|
127
|
-
|
128
|
-
thread_safe (0.3.6)
|
129
|
-
tzinfo (1.2.5)
|
130
|
-
thread_safe (~> 0.1)
|
131
|
-
yard (0.9.16)
|
71
|
+
thor (1.0.1)
|
72
|
+
yard (0.9.25)
|
132
73
|
|
133
74
|
PLATFORMS
|
134
75
|
ruby
|
135
76
|
|
136
77
|
DEPENDENCIES
|
137
|
-
activerecord (>= 5.1, < 5.2)
|
138
78
|
benchmark-ips
|
139
79
|
database_cleaner (~> 1.5, >= 1.5.3)
|
140
|
-
generator_spec (~> 0.9.4)
|
141
80
|
guard-rspec
|
142
81
|
mobility!
|
143
|
-
mysql2 (~> 0.4.9)
|
144
|
-
pg (< 1.0)
|
145
82
|
pry-byebug
|
146
83
|
rake (~> 12, >= 12.2.1)
|
147
84
|
rspec (~> 3.0)
|
148
|
-
sqlite3
|
149
85
|
yard (~> 0.9.0)
|
150
86
|
|
151
87
|
BUNDLED WITH
|
152
|
-
1.
|
88
|
+
2.1.4
|
data/Guardfile
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec features) \
|
6
|
+
# .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
7
|
+
|
8
|
+
## Note: if you are using the `directories` clause above and you are not
|
9
|
+
## watching the project directory ('.'), then you will want to move
|
10
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
11
|
+
#
|
12
|
+
# $ mkdir config
|
13
|
+
# $ mv Guardfile config/
|
14
|
+
# $ ln -s config/Guardfile .
|
15
|
+
#
|
16
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
17
|
+
|
18
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
19
|
+
# rspec may be run, below are examples of the most common uses.
|
20
|
+
# * bundler: 'bundle exec rspec'
|
21
|
+
# * bundler binstubs: 'bin/rspec'
|
22
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
23
|
+
# installed the spring binstubs per the docs)
|
24
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
25
|
+
# * 'just' rspec: 'rspec'
|
26
|
+
|
27
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
28
|
+
require "guard/rspec/dsl"
|
29
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
30
|
+
|
31
|
+
# Feel free to open issues for suggestions and improvements
|
32
|
+
|
33
|
+
# RSpec files
|
34
|
+
rspec = dsl.rspec
|
35
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
36
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
37
|
+
watch(rspec.spec_files)
|
38
|
+
|
39
|
+
# Ruby files
|
40
|
+
ruby = dsl.ruby
|
41
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
42
|
+
|
43
|
+
# Rails files
|
44
|
+
rails = dsl.rails(view_extensions: %w(erb haml slim))
|
45
|
+
dsl.watch_spec_files_for(rails.app_files)
|
46
|
+
dsl.watch_spec_files_for(rails.views)
|
47
|
+
|
48
|
+
watch(rails.controllers) do |m|
|
49
|
+
[
|
50
|
+
rspec.spec.call("routing/#{m[1]}_routing"),
|
51
|
+
rspec.spec.call("controllers/#{m[1]}_controller"),
|
52
|
+
rspec.spec.call("acceptance/#{m[1]}")
|
53
|
+
]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Rails config changes
|
57
|
+
watch(rails.spec_helper) { rspec.spec_dir }
|
58
|
+
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
|
59
|
+
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
|
60
|
+
|
61
|
+
# Capybara features specs
|
62
|
+
watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") }
|
63
|
+
watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") }
|
64
|
+
|
65
|
+
# Turnip features and steps
|
66
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
67
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
|
68
|
+
Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
|
69
|
+
end
|
70
|
+
end
|
data/README.md
CHANGED
@@ -51,7 +51,7 @@ Installation
|
|
51
51
|
Add this line to your application's Gemfile:
|
52
52
|
|
53
53
|
```ruby
|
54
|
-
gem 'mobility', '~> 0.8.
|
54
|
+
gem 'mobility', '~> 0.8.13'
|
55
55
|
```
|
56
56
|
|
57
57
|
Mobility is cryptographically signed. To be sure the gem you install hasn't
|
@@ -68,7 +68,7 @@ installation of unsigned dependencies.
|
|
68
68
|
### ActiveRecord (Rails)
|
69
69
|
|
70
70
|
Requirements:
|
71
|
-
- ActiveRecord >= 5.0
|
71
|
+
- ActiveRecord >= 5.0 (including 6.0)
|
72
72
|
|
73
73
|
(Support for most backends and features is also supported with
|
74
74
|
ActiveRecord/Rails 4.2, but there are some tests still failing. To see exactly
|
data/Rakefile
CHANGED
@@ -2,7 +2,9 @@ require "bundler/gem_tasks"
|
|
2
2
|
require "rspec/core/rake_task"
|
3
3
|
require "yaml"
|
4
4
|
|
5
|
-
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
6
|
+
task.rspec_opts = '-f p'
|
7
|
+
end
|
6
8
|
|
7
9
|
task :default => :spec
|
8
10
|
|
@@ -18,7 +20,7 @@ namespace :db do
|
|
18
20
|
desc "Create the database"
|
19
21
|
task create: :setup do
|
20
22
|
commands = {
|
21
|
-
"mysql" => "mysql -u #{config['username']} -e 'create database #{config["database"]} default character set #{config["encoding"]} default collate #{config["collation"]};' >/dev/null",
|
23
|
+
"mysql" => "mysql -h #{config['host']} -P #{config['port']} -u #{config['username']} --password=#{config['password']} -e 'create database #{config["database"]} default character set #{config["encoding"]} default collate #{config["collation"]};' >/dev/null",
|
22
24
|
"postgres" => "psql -c 'create database #{config['database']};' -U #{config['username']} >/dev/null"
|
23
25
|
}
|
24
26
|
%x{#{commands[driver] || true}}
|
@@ -28,7 +30,7 @@ namespace :db do
|
|
28
30
|
desc "Drop the database"
|
29
31
|
task drop: :setup do
|
30
32
|
commands = {
|
31
|
-
"mysql" => "mysql -u #{config['username']} -e 'drop database #{config["database"]};' >/dev/null",
|
33
|
+
"mysql" => "mysql -h #{config['host']} -P #{config['port']} -u #{config['username']} --password=#{config['password']} -e 'drop database #{config["database"]};' >/dev/null",
|
32
34
|
"postgres" => "psql -c 'drop database #{config['database']};' -U #{config['username']} >/dev/null"
|
33
35
|
}
|
34
36
|
%x{#{commands[driver] || true}}
|
@@ -42,8 +44,8 @@ namespace :db do
|
|
42
44
|
|
43
45
|
require orm
|
44
46
|
require "database"
|
45
|
-
require "#{orm}/schema"
|
46
47
|
DB = Mobility::Test::Database.connect(orm)
|
48
|
+
require "#{orm}/schema"
|
47
49
|
Mobility::Test::Schema.up
|
48
50
|
end
|
49
51
|
|
data/lib/mobility.rb
CHANGED
@@ -69,8 +69,10 @@ module Mobility
|
|
69
69
|
require "sequel"
|
70
70
|
raise VersionNotSupportedError, "Mobility is only compatible with Sequel 4.0 and greater" if ::Sequel::MAJOR < 4
|
71
71
|
require "sequel/plugins/mobility"
|
72
|
-
|
73
|
-
|
72
|
+
unless defined?(ActiveSupport::Inflector)
|
73
|
+
# TODO: avoid automatically including the inflector extension
|
74
|
+
require "sequel/extensions/inflector"
|
75
|
+
end
|
74
76
|
require "sequel/plugins/dirty"
|
75
77
|
require "mobility/sequel"
|
76
78
|
Loaded::Sequel = true
|
@@ -6,7 +6,7 @@ module Mobility
|
|
6
6
|
|
7
7
|
belongs_to :translatable, polymorphic: true, touch: true
|
8
8
|
|
9
|
-
validates :key, presence: true, uniqueness: { scope: [:translatable_id, :translatable_type, :locale] }
|
9
|
+
validates :key, presence: true, uniqueness: { scope: [:translatable_id, :translatable_type, :locale], case_sensitive: true }
|
10
10
|
validates :translatable, presence: true
|
11
11
|
validates :locale, presence: true
|
12
12
|
end
|
@@ -17,81 +17,302 @@ following methods:
|
|
17
17
|
- +title_previous_change+
|
18
18
|
- +restore_title!+
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
The following methods are also patched to work with translated attributes:
|
21
|
+
- +changed_attributes+
|
22
|
+
- +changes+
|
23
|
+
- +changed+
|
24
|
+
- +changed?+
|
25
|
+
- +previous_changes+
|
26
|
+
- +clear_attribute_changes+
|
27
|
+
- +restore_attributes+
|
28
|
+
|
29
|
+
In addition, the following ActiveModel attribute handler methods are also
|
30
|
+
patched to work with translated attributes:
|
31
|
+
- +attribute_changed?+
|
32
|
+
- +attribute_previously_changed?+
|
33
|
+
- +attribute_was+
|
34
|
+
|
35
|
+
(When using these methods, you must pass the attribute name along with its
|
36
|
+
locale suffix, so +title_en+, +title_pt_br+, etc.)
|
37
|
+
|
38
|
+
Other methods are also included for ActiveRecord models, see documentation on
|
39
|
+
the ActiveRecord dirty plugin for more information.
|
22
40
|
|
23
41
|
@see http://api.rubyonrails.org/classes/ActiveModel/Dirty.html Rails documentation for Active Model Dirty module
|
24
42
|
|
25
43
|
=end
|
26
44
|
module Dirty
|
27
|
-
# @!group Backend Accessors
|
28
|
-
# @!macro backend_writer
|
29
|
-
# @param [Hash] options
|
30
|
-
def write(locale, value, options = {})
|
31
|
-
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale)
|
32
|
-
if model.changed_attributes.has_key?(locale_accessor) && model.changed_attributes[locale_accessor] == value
|
33
|
-
model.send(:attributes_changed_by_setter).except!(locale_accessor)
|
34
|
-
elsif read(locale, options.merge(locale: true)) != value
|
35
|
-
model.send(:mobility_changed_attributes) << locale_accessor
|
36
|
-
model.send(:attribute_will_change!, locale_accessor)
|
37
|
-
end
|
38
|
-
super
|
39
|
-
end
|
40
|
-
# @!endgroup
|
41
|
-
|
42
45
|
# Builds module which adds suffix/prefix methods for translated
|
43
46
|
# attributes so they act like normal dirty-tracked attributes.
|
44
47
|
class MethodsBuilder < Module
|
48
|
+
delegate :dirty_class, :handler_methods_module, :method_patterns, to: :class
|
49
|
+
|
45
50
|
def initialize(*attribute_names)
|
51
|
+
define_dirty_methods(attribute_names)
|
52
|
+
end
|
53
|
+
|
54
|
+
def included(model_class)
|
55
|
+
model_class.include InstanceMethods
|
56
|
+
model_class.include handler_methods_module
|
57
|
+
|
58
|
+
# In earlier versions of Rails, these methods are private
|
59
|
+
%i[clear_attribute_changes clear_changes_information changes_applied].each do |method_name|
|
60
|
+
if dirty_class.private_instance_methods.include?(method_name)
|
61
|
+
model_class.class_eval { private method_name }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def append_locale(attr_name)
|
67
|
+
Mobility.normalize_locale_accessor(attr_name)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def define_dirty_methods(attribute_names)
|
73
|
+
m = self
|
74
|
+
|
46
75
|
attribute_names.each do |name|
|
47
|
-
|
48
|
-
define_method
|
49
|
-
|
76
|
+
method_patterns.each do |pattern|
|
77
|
+
define_method(pattern % name) do |*args|
|
78
|
+
mutations_from_mobility.send(pattern % 'attribute', m.append_locale(name), *args)
|
50
79
|
end
|
51
80
|
end
|
52
81
|
|
53
82
|
define_method "restore_#{name}!" do
|
54
|
-
locale_accessor =
|
55
|
-
if attribute_changed?(locale_accessor)
|
56
|
-
__send__("#{name}=",
|
83
|
+
locale_accessor = m.append_locale(name)
|
84
|
+
if mutations_from_mobility.attribute_changed?(locale_accessor)
|
85
|
+
__send__("#{name}=", mutations_from_mobility.attribute_was(locale_accessor))
|
86
|
+
mutations_from_mobility.restore_attribute!(locale_accessor)
|
57
87
|
end
|
58
88
|
end
|
59
89
|
end
|
60
90
|
|
91
|
+
# This private method override is necessary to make
|
92
|
+
# +restore_attributes+ (which is public) work with translated
|
93
|
+
# attributes.
|
61
94
|
define_method :restore_attribute! do |attr|
|
62
95
|
attribute_names.include?(attr.to_s) ? send("restore_#{attr}!") : super(attr)
|
63
96
|
end
|
64
97
|
private :restore_attribute!
|
65
98
|
end
|
66
99
|
|
67
|
-
|
68
|
-
|
100
|
+
class << self
|
101
|
+
def handler_methods_module
|
102
|
+
@handler_methods_module ||= (AttributeHandlerMethods.new.tap do |mod|
|
103
|
+
public_method_patterns.each do |pattern|
|
104
|
+
method_name = pattern % 'attribute'
|
105
|
+
|
106
|
+
mod.module_eval <<-EOM, __FILE__, __LINE__ + 1
|
107
|
+
def #{method_name}(attr_name, *rest)
|
108
|
+
if (mutations_from_mobility.attribute_changed?(attr_name) ||
|
109
|
+
mutations_from_mobility.attribute_previously_changed?(attr_name))
|
110
|
+
mutations_from_mobility.send(#{method_name.inspect}, attr_name, *rest)
|
111
|
+
else
|
112
|
+
super
|
113
|
+
end
|
114
|
+
end
|
115
|
+
EOM
|
116
|
+
end
|
117
|
+
end)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Get method suffixes. Creating an object just to get the list of
|
121
|
+
# suffixes is simplest given they change from Rails version to version.
|
122
|
+
def method_patterns
|
123
|
+
@method_patterns ||=
|
124
|
+
(dirty_class.attribute_method_matchers.map { |p| "#{p.prefix}%s#{p.suffix}" } - excluded_method_patterns)
|
125
|
+
end
|
126
|
+
|
127
|
+
def public_method_patterns
|
128
|
+
@public_method_patterns ||= method_patterns.select do |p|
|
129
|
+
!dirty_class.private_instance_methods.include?(:"#{p % 'attribute'}")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def dirty_class
|
134
|
+
@dirty_class ||= Class.new { include ::ActiveModel::Dirty }
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def excluded_method_patterns
|
140
|
+
['%s', 'restore_%s!']
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
module InstanceMethods
|
146
|
+
def changed_attributes
|
147
|
+
super.merge(mutations_from_mobility.changed_attributes)
|
148
|
+
end
|
149
|
+
|
150
|
+
def changes_applied
|
151
|
+
super
|
152
|
+
mutations_from_mobility.finalize_changes
|
153
|
+
end
|
154
|
+
|
155
|
+
def changes
|
156
|
+
super.merge(mutations_from_mobility.changes)
|
157
|
+
end
|
158
|
+
|
159
|
+
def changed
|
160
|
+
# uniq is required for Rails < 6.0
|
161
|
+
(super + mutations_from_mobility.changed).uniq
|
162
|
+
end
|
163
|
+
|
164
|
+
def changed?
|
165
|
+
super || mutations_from_mobility.changed?
|
166
|
+
end
|
167
|
+
|
168
|
+
def previous_changes
|
169
|
+
super.merge(mutations_from_mobility.previous_changes)
|
170
|
+
end
|
171
|
+
|
172
|
+
def clear_changes_information
|
173
|
+
@mutations_from_mobility = nil
|
174
|
+
super
|
175
|
+
end
|
176
|
+
|
177
|
+
def clear_attribute_changes(attr_names)
|
178
|
+
attr_names.each { |attr_name| mutations_from_mobility.restore_attribute!(attr_name) }
|
179
|
+
super
|
69
180
|
end
|
70
181
|
|
71
182
|
private
|
72
183
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
184
|
+
def mutations_from_mobility
|
185
|
+
@mutations_from_mobility ||= MobilityMutationTracker.new(self)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Give the module builder a name so it's easier to see in the model's ancestors
|
190
|
+
class AttributeHandlerMethods < Module; end
|
191
|
+
|
192
|
+
class MobilityMutationTracker
|
193
|
+
OPTION_NOT_GIVEN = Object.new
|
194
|
+
|
195
|
+
attr_reader :previous_changes
|
196
|
+
|
197
|
+
def initialize(model)
|
198
|
+
@model = model
|
199
|
+
@current_changes = {}.with_indifferent_access
|
200
|
+
@previous_changes = {}.with_indifferent_access
|
201
|
+
end
|
202
|
+
|
203
|
+
def finalize_changes
|
204
|
+
@previous_changes = changes
|
205
|
+
@current_changes = {}.with_indifferent_access
|
206
|
+
end
|
207
|
+
|
208
|
+
def changed
|
209
|
+
attr_names.select { |attr_name| attribute_changed?(attr_name) }
|
210
|
+
end
|
211
|
+
|
212
|
+
def changed_attributes
|
213
|
+
attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
|
214
|
+
if attribute_changed?(attr_name)
|
215
|
+
result[attr_name] = attribute_was(attr_name)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def changes
|
221
|
+
attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
|
222
|
+
if change = attribute_change(attr_name)
|
223
|
+
result.merge!(attr_name => change)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def changed?
|
229
|
+
attr_names.any? { |attr| attribute_changed?(attr) }
|
230
|
+
end
|
231
|
+
|
232
|
+
def attribute_change(attr_name)
|
233
|
+
if attribute_changed?(attr_name)
|
234
|
+
[attribute_was(attr_name), fetch_value(attr_name)]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def attribute_previous_change(attr_name)
|
239
|
+
previous_changes[attr_name]
|
240
|
+
end
|
90
241
|
|
91
|
-
|
92
|
-
|
242
|
+
def attribute_previously_was(attr_name)
|
243
|
+
if attribute_previously_changed?(attr_name)
|
244
|
+
# Calling +first+ here fetches the value before change from the
|
245
|
+
# hash.
|
246
|
+
previous_changes[attr_name].first
|
93
247
|
end
|
94
248
|
end
|
249
|
+
|
250
|
+
def attribute_changed?(attr_name, from: OPTION_NOT_GIVEN, to: OPTION_NOT_GIVEN)
|
251
|
+
current_changes.include?(attr_name) &&
|
252
|
+
(OPTION_NOT_GIVEN == from || attribute_was(attr_name) == from) &&
|
253
|
+
(OPTION_NOT_GIVEN == to || fetch_value(attr_name) == to)
|
254
|
+
end
|
255
|
+
|
256
|
+
def attribute_previously_changed?(attr_name)
|
257
|
+
previous_changes.include?(attr_name)
|
258
|
+
end
|
259
|
+
|
260
|
+
def attribute_was(attr_name)
|
261
|
+
if attribute_changed?(attr_name)
|
262
|
+
current_changes[attr_name]
|
263
|
+
else
|
264
|
+
fetch_value(attr_name)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def attribute_will_change!(attr_name)
|
269
|
+
current_changes[attr_name] = fetch_value(attr_name) unless current_changes.include?(attr_name)
|
270
|
+
end
|
271
|
+
|
272
|
+
def restore_attribute!(attr_name)
|
273
|
+
current_changes.delete(attr_name)
|
274
|
+
end
|
275
|
+
|
276
|
+
# These are for ActiveRecord, but we'll define them here.
|
277
|
+
alias_method :saved_change_to_attribute?, :attribute_previously_changed?
|
278
|
+
alias_method :saved_change_to_attribute, :attribute_previous_change
|
279
|
+
alias_method :attribute_before_last_save, :attribute_previously_was
|
280
|
+
alias_method :will_save_change_to_attribute?, :attribute_changed?
|
281
|
+
alias_method :attribute_change_to_be_saved, :attribute_change
|
282
|
+
alias_method :attribute_in_database, :attribute_was
|
283
|
+
|
284
|
+
private
|
285
|
+
attr_reader :model, :current_changes
|
286
|
+
|
287
|
+
def attr_names
|
288
|
+
current_changes.keys
|
289
|
+
end
|
290
|
+
|
291
|
+
def fetch_value(attr_name)
|
292
|
+
model.__send__(attr_name)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
module BackendMethods
|
297
|
+
# @!group Backend Accessors
|
298
|
+
# @!macro backend_writer
|
299
|
+
# @param [Hash] options
|
300
|
+
def write(locale, value, options = {})
|
301
|
+
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale)
|
302
|
+
if model.changed_attributes.has_key?(locale_accessor) && model.changed_attributes[locale_accessor] == value
|
303
|
+
mutations_from_mobility.restore_attribute!(locale_accessor)
|
304
|
+
elsif read(locale, options.merge(locale: true)) != value
|
305
|
+
mutations_from_mobility.attribute_will_change!(locale_accessor)
|
306
|
+
end
|
307
|
+
super
|
308
|
+
end
|
309
|
+
# @!endgroup
|
310
|
+
|
311
|
+
private
|
312
|
+
|
313
|
+
def mutations_from_mobility
|
314
|
+
model.send(:mutations_from_mobility)
|
315
|
+
end
|
95
316
|
end
|
96
317
|
end
|
97
318
|
end
|
@@ -12,7 +12,6 @@ details on usage.
|
|
12
12
|
In addition to methods added by {Mobility::Plugins::ActiveModel::Dirty}, the
|
13
13
|
AR::Dirty plugin adds support for the following persistence-specific methods
|
14
14
|
(for a model with a translated attribute +title+):
|
15
|
-
- +saved_changes+
|
16
15
|
- +saved_change_to_title?+
|
17
16
|
- +saved_change_to_title+
|
18
17
|
- +title_before_last_save+
|
@@ -20,128 +19,83 @@ AR::Dirty plugin adds support for the following persistence-specific methods
|
|
20
19
|
- +title_change_to_be_saved+
|
21
20
|
- +title_in_database+
|
22
21
|
|
22
|
+
The following methods are also patched to include translated attribute changes:
|
23
|
+
- +saved_changes+
|
24
|
+
- +has_changes_to_save?+
|
25
|
+
- +changes_to_save+
|
26
|
+
- +changed_attribute_names_to_save+
|
27
|
+
- +attributes_in_database+
|
28
|
+
|
29
|
+
In addition, the following ActiveModel attribute handler methods are also
|
30
|
+
patched to work with translated attributes:
|
31
|
+
- +saved_change_to_attribute?+
|
32
|
+
- +saved_change_to_attribute+
|
33
|
+
- +attribute_before_last_save+
|
34
|
+
- +will_save_change_to_attribute?+
|
35
|
+
- +attribute_change_to_be_saved+
|
36
|
+
- +attribute_in_database+
|
37
|
+
|
38
|
+
(When using these methods, you must pass the attribute name along with its
|
39
|
+
locale suffix, so +title_en+, +title_pt_br+, etc.)
|
40
|
+
|
23
41
|
=end
|
24
42
|
module Dirty
|
25
|
-
include ActiveModel::Dirty
|
26
|
-
|
27
|
-
# Builds module which patches a few AR methods to handle changes to
|
28
|
-
# translated attributes just like normal attributes.
|
29
43
|
class MethodsBuilder < ActiveModel::Dirty::MethodsBuilder
|
30
|
-
def initialize(*attribute_names)
|
31
|
-
super
|
32
|
-
@attribute_names = attribute_names
|
33
|
-
define_method_overrides if ::ActiveRecord::VERSION::STRING < '5.2'
|
34
|
-
define_attribute_methods if ::ActiveRecord::VERSION::STRING >= '5.1'
|
35
|
-
end
|
36
|
-
|
37
|
-
# Overrides +ActiveRecord::AttributeMethods::ClassMethods#has_attribute+ (in AR 5.1) and
|
38
|
-
# +ActiveModel::AttributeMethods#_read_attribute+ (in AR >= 5.2) to
|
39
|
-
# ensure that fallthrough attribute methods are treated like "real"
|
40
|
-
# attribute methods.
|
41
|
-
#
|
42
|
-
# @note Patching +has_attribute?+ is necessary in AR 5.1 due to this commit[https://github.com/rails/rails/commit/4fed08fa787a316fa51f14baca9eae11913f5050].
|
43
44
|
# @param [Attributes] attributes
|
44
45
|
def included(model_class)
|
45
46
|
super
|
46
47
|
|
47
|
-
|
48
|
-
names = @attribute_names
|
49
|
-
method_name_regex = /\A(#{names.join('|')})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
50
|
-
has_attribute = Module.new do
|
51
|
-
define_method :has_attribute? do |attr_name|
|
52
|
-
super(attr_name) || (String === attr_name && !!method_name_regex.match(attr_name))
|
53
|
-
end
|
54
|
-
end
|
55
|
-
model_class.extend has_attribute
|
56
|
-
elsif ::ActiveRecord::VERSION::STRING >= '5.2'
|
57
|
-
model_class.include ReadAttribute
|
58
|
-
end
|
48
|
+
model_class.include InstanceMethods
|
59
49
|
end
|
60
50
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
51
|
+
class << self
|
52
|
+
def dirty_class
|
53
|
+
@dirty_class ||= (Class.new do
|
54
|
+
# In earlier versions of Rails, these are needed to avoid an
|
55
|
+
# exception when including the AR Dirty module outside of an
|
56
|
+
# AR::Base class. Eventually we should be able to drop them.
|
57
|
+
def self.after_create; end
|
58
|
+
def self.after_update; end
|
59
|
+
|
60
|
+
include ::ActiveRecord::AttributeMethods::Dirty
|
61
|
+
end)
|
71
62
|
end
|
63
|
+
end
|
64
|
+
end
|
72
65
|
|
73
|
-
|
74
|
-
|
75
|
-
|
66
|
+
module InstanceMethods
|
67
|
+
if ::ActiveRecord::VERSION::STRING >= '5.1' # define patterns added in 5.1
|
68
|
+
def saved_changes
|
69
|
+
super.merge(mutations_from_mobility.previous_changes)
|
76
70
|
end
|
77
71
|
|
78
|
-
|
79
|
-
|
72
|
+
def changes_to_save
|
73
|
+
super.merge(mutations_from_mobility.changes)
|
80
74
|
end
|
81
|
-
end
|
82
75
|
|
83
|
-
|
84
|
-
|
85
|
-
define_method :saved_changes do
|
86
|
-
(@previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new).merge(super())
|
76
|
+
def changed_attribute_names_to_save
|
77
|
+
super + mutations_from_mobility.changed
|
87
78
|
end
|
88
79
|
|
89
|
-
|
90
|
-
|
91
|
-
previous_changes.include?(Mobility.normalize_locale_accessor(name))
|
92
|
-
end
|
93
|
-
|
94
|
-
define_method :"saved_change_to_#{name}" do
|
95
|
-
previous_changes[Mobility.normalize_locale_accessor(name)]
|
96
|
-
end
|
97
|
-
|
98
|
-
define_method :"#{name}_before_last_save" do
|
99
|
-
previous_changes[Mobility.normalize_locale_accessor(name)].first
|
100
|
-
end
|
101
|
-
|
102
|
-
alias_method :"will_save_change_to_#{name}?", :"#{name}_changed?"
|
103
|
-
alias_method :"#{name}_change_to_be_saved", :"#{name}_change"
|
104
|
-
alias_method :"#{name}_in_database", :"#{name}_was"
|
80
|
+
def attributes_in_database
|
81
|
+
super.merge(mutations_from_mobility.changed_attributes)
|
105
82
|
end
|
106
|
-
end
|
107
83
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
#
|
112
|
-
# For background on why this is necessary, see:
|
113
|
-
# https://github.com/shioyama/mobility/issues/115
|
114
|
-
module ReadAttribute
|
115
|
-
# @note We first check if attributes has the key +attr+ to avoid
|
116
|
-
# doing any extra work in case this is a "normal"
|
117
|
-
# (non-translated) attribute.
|
118
|
-
def _read_attribute(attr, *args)
|
119
|
-
if @attributes.key?(attr)
|
120
|
-
super
|
121
|
-
else
|
122
|
-
mobility_changed_attributes.include?(attr) ? __send__(attr) : super
|
84
|
+
if ::ActiveRecord::VERSION::STRING >= '6.0'
|
85
|
+
def has_changes_to_save?
|
86
|
+
super || mutations_from_mobility.changed?
|
123
87
|
end
|
124
88
|
end
|
89
|
+
end
|
125
90
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
# be cases where @attributes has been set, but there are *other*
|
130
|
-
# changes on virtual translated attributes which need to also be
|
131
|
-
# assigned. In this case, we use the presence of such changed
|
132
|
-
# virtual attributes as an alternative trigger to set this variable.
|
133
|
-
#
|
134
|
-
# See:
|
135
|
-
# - https://github.com/rails/rails/commit/e126078a0e013acfe0a397a8dad33b2c9de78732
|
136
|
-
# - https://github.com/shioyama/mobility/pull/166
|
137
|
-
def changes_applied
|
138
|
-
if defined?(@attributes) && mobility_changed_attributes.any?
|
139
|
-
@previously_changed = changes
|
140
|
-
end
|
141
|
-
super
|
91
|
+
def reload(*)
|
92
|
+
super.tap do
|
93
|
+
@mutations_from_mobility = nil
|
142
94
|
end
|
143
95
|
end
|
144
96
|
end
|
97
|
+
|
98
|
+
BackendMethods = ActiveModel::Dirty::BackendMethods
|
145
99
|
end
|
146
100
|
end
|
147
101
|
end
|
@@ -139,8 +139,10 @@ enabled for any one attribute on the model.
|
|
139
139
|
|
140
140
|
if ::ActiveRecord::VERSION::STRING >= '5.0'
|
141
141
|
%w[pluck group select].each do |method_name|
|
142
|
-
define_method method_name do |*attrs|
|
143
|
-
return super(*attrs)
|
142
|
+
define_method method_name do |*attrs, &block|
|
143
|
+
return super(*attrs, &block) if (method_name == 'select' && block.present?)
|
144
|
+
|
145
|
+
return super(*attrs, &block) unless attrs.any?(&@klass.method(:mobility_attribute?))
|
144
146
|
|
145
147
|
keys = attrs.dup
|
146
148
|
|
@@ -154,7 +156,7 @@ enabled for any one attribute on the model.
|
|
154
156
|
@klass.mobility_backend_class(key).apply_scope(query, backend_node(key))
|
155
157
|
end
|
156
158
|
|
157
|
-
base.public_send(method_name, *keys)
|
159
|
+
base.public_send(method_name, *keys, &block)
|
158
160
|
end
|
159
161
|
end
|
160
162
|
end
|
@@ -50,7 +50,7 @@ details.
|
|
50
50
|
else
|
51
51
|
raise ArgumentError, "#{model_class} does not support Dirty module."
|
52
52
|
end
|
53
|
-
backend_class.include dirty_module
|
53
|
+
backend_class.include dirty_module.const_get(:BackendMethods)
|
54
54
|
model_class.include dirty_module.const_get(:MethodsBuilder).new(*attribute_names)
|
55
55
|
end
|
56
56
|
end
|
@@ -46,14 +46,18 @@ model class is generated.
|
|
46
46
|
def initialize(*attributes)
|
47
47
|
method_name_regex = /\A(#{attributes.join('|')})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
48
48
|
|
49
|
-
define_method :method_missing do |method_name, *
|
49
|
+
define_method :method_missing do |method_name, *args, &block|
|
50
50
|
if method_name =~ method_name_regex
|
51
|
-
|
51
|
+
attribute_method = "#{$1}#{$4}"
|
52
52
|
locale, suffix = $2.split('_')
|
53
53
|
locale = "#{locale}-#{suffix.upcase}" if suffix
|
54
|
-
|
54
|
+
if $4 == '=' # writer
|
55
|
+
public_send(attribute_method, args[0], **(args[1] || {}), locale: locale.to_sym)
|
56
|
+
else # reader
|
57
|
+
public_send(attribute_method, **(args[0] || {}), locale: locale.to_sym)
|
58
|
+
end
|
55
59
|
else
|
56
|
-
super(method_name, *
|
60
|
+
super(method_name, *args, &block)
|
57
61
|
end
|
58
62
|
end
|
59
63
|
|
@@ -13,21 +13,6 @@ Automatically includes dirty plugin in model class when enabled.
|
|
13
13
|
=end
|
14
14
|
module Sequel
|
15
15
|
module Dirty
|
16
|
-
# @!group Backend Accessors
|
17
|
-
# @!macro backend_writer
|
18
|
-
# @param [Hash] options
|
19
|
-
def write(locale, value, options = {})
|
20
|
-
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale).to_sym
|
21
|
-
if model.column_changes.has_key?(locale_accessor) && model.initial_values[locale_accessor] == value
|
22
|
-
super
|
23
|
-
[model.changed_columns, model.initial_values].each { |h| h.delete(locale_accessor) }
|
24
|
-
elsif read(locale, options.merge(fallback: false)) != value
|
25
|
-
model.will_change_column(locale_accessor)
|
26
|
-
super
|
27
|
-
end
|
28
|
-
end
|
29
|
-
# @!endgroup
|
30
|
-
|
31
16
|
# Builds module which overrides dirty methods to handle translated as
|
32
17
|
# well as normal (untranslated) attributes.
|
33
18
|
class MethodsBuilder < Module
|
@@ -53,6 +38,23 @@ Automatically includes dirty plugin in model class when enabled.
|
|
53
38
|
model_class.plugin :dirty
|
54
39
|
end
|
55
40
|
end
|
41
|
+
|
42
|
+
module BackendMethods
|
43
|
+
# @!group Backend Accessors
|
44
|
+
# @!macro backend_writer
|
45
|
+
# @param [Hash] options
|
46
|
+
def write(locale, value, options = {})
|
47
|
+
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale).to_sym
|
48
|
+
if model.column_changes.has_key?(locale_accessor) && model.initial_values[locale_accessor] == value
|
49
|
+
super
|
50
|
+
[model.changed_columns, model.initial_values].each { |h| h.delete(locale_accessor) }
|
51
|
+
elsif read(locale, options.merge(fallback: false)) != value
|
52
|
+
model.will_change_column(locale_accessor)
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
# @!endgroup
|
57
|
+
end
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
data/lib/mobility/version.rb
CHANGED
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: 0.8.
|
4
|
+
version: 0.8.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Salzberg
|
@@ -10,32 +10,31 @@ bindir: exe
|
|
10
10
|
cert_chain:
|
11
11
|
- |
|
12
12
|
-----BEGIN CERTIFICATE-----
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
2DiDkec/SK4qJBMlNYPo/PTZuh5m1jROtf/hyS0VXJmm+uWc
|
13
|
+
MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhjaHJp
|
14
|
+
cy9EQz1kZWppbXN0YS9EQz1jb20wHhcNMjAwMjExMDEwMjM1WhcNMjEwMjEwMDEw
|
15
|
+
MjM1WjAjMSEwHwYDVQQDDBhjaHJpcy9EQz1kZWppbXN0YS9EQz1jb20wggGiMA0G
|
16
|
+
CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC99crJF+gE4WQnN7S4xdacGpZWg7hZ
|
17
|
+
UlXPXM1vX4HVaw8essO6eNGafYqKRQKf3WDW4uM6kqPd4OZTfahGhocVtVScJYGi
|
18
|
+
5SRuw9rrJeFlojUkCSqy47on7t858OebbD28eo71sZLTclGmza6UpjiLZqy0AL4P
|
19
|
+
9dkK2j9pQJ3jYTNYteq7P6A109ExSGWbaRvkAKU+vTMJsK5MW2bWullsOGHrZiPW
|
20
|
+
7PXAaU33X29ddLu/zj/4qe83GVvnrprjw5RRgoQgP0Umw8zKG50XB7nS3TAUiaRz
|
21
|
+
oD+eKgOIeZpPRwemINf0VsP1L+/FnUS6BkzVCOV9MWhUbrkdxCHLrSB8JL4ooXXR
|
22
|
+
N/J4KlR5xpv6b+z+i2lScfkrH7r9RF4ZtpiDQzyCxvuIZOQTzUneUSzMIk9BaEN2
|
23
|
+
5S19cDUjW5fi75npJ+YnrUN83Ta3sa/Pp4dnUqiBK7WHBDnHMN6j7iASoAjKVTgM
|
24
|
+
8F/xjk4qgxA7vjv2obj2zv65CknnQprLCpMCAwEAAaN3MHUwCQYDVR0TBAIwADAL
|
25
|
+
BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFOO4919GTuKTQA2Klo2QO3jGlbJTMB0GA1Ud
|
26
|
+
EQQWMBSBEmNocmlzQGRlamltc3RhLmNvbTAdBgNVHRIEFjAUgRJjaHJpc0BkZWpp
|
27
|
+
bXN0YS5jb20wDQYJKoZIhvcNAQELBQADggGBADfIFBldH77wyUv2RZ1kwvuvRvpL
|
28
|
+
RNFdQlCbuVSn3abRAmc9rIsh80syhjWjYnml3guf+g2tYB1rU3NeTFRVupdvcUWJ
|
29
|
+
T6mITUeDHpNoxF6KAp3zSsdoBoEHdOBNH7Jpxp+L3a2LZ0k6fW12xEafmymOD3fp
|
30
|
+
BmIrE2Vr9aUec2Sk4fbKEYqsxhmXx+o8kKU7tnxVYMv4cX5X3yo45FA7Rh2JQuub
|
31
|
+
MBT+NALoYFaSTHWIr/4tAolWVt8NNGUKEokaFjjf5gAGM6piq6ohTHl5dCtcEPX1
|
32
|
+
klHOa2pIFwuUAWoVCpZa9XzRV5qz+mUrU70DF9dX6Cotv/sKOIxiGvQLnwzlSQWH
|
33
|
+
iXMqkM6Y5FSwViOQy4U2egDDSTB5a16iAnN7/qzqex6SYTsQdSmyc0mWCb9rkIoF
|
34
|
+
gSQml7TqcC6dZRsZRwYqzD9kUwdAJoCqno2CBUKs2l0yQAjFT36lRrVJznb7uWwa
|
35
|
+
xpPFnsrtyaZW6Dty8TSG3qzmeGpmpIotA8x1VA==
|
37
36
|
-----END CERTIFICATE-----
|
38
|
-
date:
|
37
|
+
date: 2020-05-27 00:00:00.000000000 Z
|
39
38
|
dependencies:
|
40
39
|
- !ruby/object:Gem::Dependency
|
41
40
|
name: request_store
|
@@ -151,6 +150,7 @@ files:
|
|
151
150
|
- CONTRIBUTING.md
|
152
151
|
- Gemfile
|
153
152
|
- Gemfile.lock
|
153
|
+
- Guardfile
|
154
154
|
- ISSUE_TEMPLATE.md
|
155
155
|
- LICENSE.txt
|
156
156
|
- README.md
|
@@ -273,8 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
273
273
|
- !ruby/object:Gem::Version
|
274
274
|
version: '0'
|
275
275
|
requirements: []
|
276
|
-
|
277
|
-
rubygems_version: 2.7.6
|
276
|
+
rubygems_version: 3.0.3
|
278
277
|
signing_key:
|
279
278
|
specification_version: 4
|
280
279
|
summary: Pluggable Ruby translation framework
|
metadata.gz.sig
CHANGED
Binary file
|