globalize 3.1.0 → 4.0.0.alpha.1
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 +7 -0
- data/Gemfile +8 -4
- data/Gemfile.lock +74 -241
- data/lib/globalize.rb +2 -5
- data/lib/globalize/active_record.rb +1 -1
- data/lib/globalize/active_record/act_macro.rb +10 -10
- data/lib/globalize/active_record/adapter.rb +14 -30
- data/lib/globalize/active_record/attributes.rb +0 -1
- data/lib/globalize/active_record/class_methods.rb +23 -52
- data/lib/globalize/active_record/instance_methods.rb +42 -74
- data/lib/globalize/active_record/migration.rb +2 -2
- data/lib/globalize/active_record/relation.rb +63 -0
- data/lib/globalize/active_record/translation.rb +0 -1
- data/lib/globalize/versioning.rb +5 -0
- data/lib/globalize/versioning/paper_trail.rb +39 -0
- data/lib/patches/active_record/relation.rb +20 -0
- metadata +56 -126
- data/CHANGELOG.md +0 -73
- data/CONTRIBUTING.md +0 -37
- data/lib/globalize/active_record/query_methods.rb +0 -13
- data/lib/globalize/version.rb +0 -3
- data/lib/patches/i18n/interpolate.rb +0 -37
@@ -4,16 +4,16 @@ module Globalize
|
|
4
4
|
delegate :translated_locales, :set_translations_table_name, :to => :translation_class
|
5
5
|
|
6
6
|
def with_locales(*locales)
|
7
|
-
|
7
|
+
all.merge translation_class.with_locales(*locales)
|
8
8
|
end
|
9
9
|
|
10
10
|
def with_translations(*locales)
|
11
11
|
locales = translated_locales if locales.empty?
|
12
|
-
includes(:translations).with_locales(locales).with_required_attributes
|
12
|
+
includes(:translations).with_locales(locales).with_required_attributes.references(:translations)
|
13
13
|
end
|
14
14
|
|
15
15
|
def with_required_attributes
|
16
|
-
required_translated_attributes.inject(
|
16
|
+
required_translated_attributes.inject(all) do |scope, name|
|
17
17
|
scope.where("#{translated_column_name(name)} IS NOT NULL")
|
18
18
|
end
|
19
19
|
end
|
@@ -58,18 +58,22 @@ module Globalize
|
|
58
58
|
"#{translation_class.table_name}.#{name}"
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
61
|
+
def relation
|
62
|
+
relation = Relation.new(self, arel_table)
|
63
|
+
|
64
|
+
if finder_needs_type_condition?
|
65
|
+
relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
|
66
|
+
else
|
67
|
+
relation
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
def respond_to_missing?(method_id, include_private = false)
|
72
|
+
supported_on_missing?(method_id) || super
|
73
|
+
end
|
74
|
+
|
71
75
|
def supported_on_missing?(method_id)
|
72
|
-
return super unless
|
76
|
+
return super unless respond_to?(:translated_attribute_names)
|
73
77
|
match = defined?(::ActiveRecord::DynamicFinderMatch) && (::ActiveRecord::DynamicFinderMatch.match(method_id) || ::ActiveRecord::DynamicScopeMatch.match(method_id))
|
74
78
|
return false if match.nil?
|
75
79
|
|
@@ -86,7 +90,7 @@ module Globalize
|
|
86
90
|
match, attribute_names, translated_attributes, untranslated_attributes = supported_on_missing?(method_id)
|
87
91
|
return super unless match
|
88
92
|
|
89
|
-
scope =
|
93
|
+
scope = all
|
90
94
|
|
91
95
|
translated_attributes.each do |attr|
|
92
96
|
scope = scope.with_translated_attribute(attr, arguments[attribute_names.index(attr)])
|
@@ -99,20 +103,20 @@ module Globalize
|
|
99
103
|
end
|
100
104
|
|
101
105
|
if defined?(::ActiveRecord::DynamicFinderMatch) && match.is_a?(::ActiveRecord::DynamicFinderMatch)
|
102
|
-
if match.instantiator?
|
106
|
+
if match.instantiator? && scope.blank?
|
103
107
|
return scope.find_or_instantiator_by_attributes match, attribute_names, *arguments, &block
|
104
108
|
end
|
105
109
|
match_finder_method = match.finder.to_s
|
106
|
-
match_finder_method << "!" if match.bang?
|
110
|
+
match_finder_method << "!" if match.bang?
|
107
111
|
return scope.send(match_finder_method).tap do |found|
|
108
|
-
found
|
112
|
+
Array(found).map { |f| f.translations.reload } unless found.nil?
|
109
113
|
end
|
110
114
|
end
|
111
115
|
return scope
|
112
116
|
end
|
113
117
|
|
114
118
|
def find_or_instantiator_by_attributes(match, attributes, *args)
|
115
|
-
options = args.
|
119
|
+
options = args.many? && args.last(2).all?{ |a| a.is_a?(Hash) } ? args.extract_options! : {}
|
116
120
|
protected_attributes_for_create, unprotected_attributes_for_create = {}, {}
|
117
121
|
args.each_with_index do |arg, i|
|
118
122
|
if arg.is_a?(Hash)
|
@@ -122,15 +126,8 @@ module Globalize
|
|
122
126
|
end
|
123
127
|
end
|
124
128
|
|
125
|
-
record =
|
126
|
-
|
127
|
-
r.send(:attributes=, protected_attributes_for_create, true) unless protected_attributes_for_create.empty?
|
128
|
-
r.send(:attributes=, unprotected_attributes_for_create, false) unless unprotected_attributes_for_create.empty?
|
129
|
-
end
|
130
|
-
else
|
131
|
-
new(protected_attributes_for_create, options) do |r|
|
132
|
-
r.assign_attributes(unprotected_attributes_for_create, :without_protection => true)
|
133
|
-
end
|
129
|
+
record = new(protected_attributes_for_create, options) do |r|
|
130
|
+
r.assign_attributes(unprotected_attributes_for_create)
|
134
131
|
end
|
135
132
|
yield(record) if block_given?
|
136
133
|
record.send(match.bang? ? :save! : :save) if match.instantiator.eql?(:create)
|
@@ -138,33 +135,7 @@ module Globalize
|
|
138
135
|
record
|
139
136
|
end
|
140
137
|
|
141
|
-
|
142
|
-
|
143
|
-
# Override the default relation method in order to return a subclass
|
144
|
-
# of ActiveRecord::Relation with custom where_values_hash method,
|
145
|
-
# for use in find_or_create_by_instantiator (Rails version >= 3.2.1)
|
146
|
-
if ::ActiveRecord::VERSION::STRING >= "3.2.1"
|
147
|
-
def relation
|
148
|
-
relation = globalize_relation_class.new(self, arel_table)
|
149
|
-
|
150
|
-
if finder_needs_type_condition?
|
151
|
-
relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
|
152
|
-
else
|
153
|
-
relation
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
# Use pattern defined in FriendlyId 4.x to avoid conflict with any other
|
158
|
-
# gems (such as FriendlyId) which override relation method.
|
159
|
-
def globalize_relation_class
|
160
|
-
@globalize_relation_class ||= Class.new(relation_without_globalize.class).tap do |klass|
|
161
|
-
klass.send :include, QueryMethods
|
162
|
-
const_set('GlobalizeActiveRecordRelation', klass)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
protected
|
138
|
+
protected
|
168
139
|
|
169
140
|
def translated_attr_accessor(name)
|
170
141
|
define_method(:"#{name}=") do |value|
|
@@ -11,69 +11,43 @@ module Globalize
|
|
11
11
|
super.merge(translated_attributes)
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
-
}
|
22
|
-
else
|
23
|
-
base.class_eval %{
|
24
|
-
def attributes=(attributes, *args)
|
25
|
-
with_given_locale(attributes) { super }
|
26
|
-
end
|
27
|
-
|
28
|
-
def update_attributes!(attributes, *args)
|
29
|
-
with_given_locale(attributes) { super }
|
30
|
-
end
|
31
|
-
|
32
|
-
def update_attributes(attributes, *args)
|
33
|
-
with_given_locale(attributes) { super }
|
34
|
-
end
|
35
|
-
}
|
36
|
-
end
|
14
|
+
def attributes=(attributes, *args)
|
15
|
+
with_given_locale(attributes) { super }
|
16
|
+
end
|
17
|
+
|
18
|
+
def assign_attributes(attributes, *args)
|
19
|
+
with_given_locale(attributes) { super }
|
37
20
|
end
|
38
21
|
|
39
22
|
def write_attribute(name, value, options = {})
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
#
|
49
|
-
|
50
|
-
name_str
|
51
|
-
if attribute_changed?(name_str)
|
52
|
-
# If there's already a change, delete it if this undoes the change.
|
53
|
-
old = changed_attributes[name_str]
|
54
|
-
changed_attributes.delete(name_str) if value == old
|
55
|
-
else
|
56
|
-
# If there's not a change yet, record it.
|
57
|
-
old = globalize.fetch(options[:locale], name)
|
58
|
-
old = old.clone if old.duplicable?
|
59
|
-
changed_attributes[name_str] = old if value != old
|
60
|
-
end
|
61
|
-
|
62
|
-
globalize.write(options[:locale], name, value)
|
23
|
+
return super(name, value) unless translated?(name)
|
24
|
+
|
25
|
+
options = {:locale => Globalize.locale}.merge(options)
|
26
|
+
|
27
|
+
# Dirty tracking, paraphrased from
|
28
|
+
# ActiveRecord::AttributeMethods::Dirty#write_attribute.
|
29
|
+
name_str = name.to_s
|
30
|
+
if attribute_changed?(name_str)
|
31
|
+
# If there's already a change, delete it if this undoes the change.
|
32
|
+
old = changed_attributes[name_str]
|
33
|
+
changed_attributes.delete(name_str) if value == old
|
63
34
|
else
|
64
|
-
|
35
|
+
# If there's not a change yet, record it.
|
36
|
+
old = globalize.fetch(options[:locale], name)
|
37
|
+
old = old.dup if old.duplicable?
|
38
|
+
changed_attributes[name_str] = old if value != old
|
65
39
|
end
|
40
|
+
|
41
|
+
globalize.write(options[:locale], name, value)
|
66
42
|
end
|
67
43
|
|
68
44
|
def read_attribute(name, options = {})
|
69
|
-
# Deprecate old use of locale
|
70
|
-
unless options.is_a?(Hash)
|
71
|
-
warn "[DEPRECATION] passing 'locale' as #{options.inspect} is deprecated. Please use {:locale => #{options.inspect}} instead."
|
72
|
-
options = {:locale => options}
|
73
|
-
end
|
74
|
-
|
75
45
|
options = {:translated => true, :locale => nil}.merge(options)
|
76
|
-
|
46
|
+
return super(name) unless options[:translated]
|
47
|
+
|
48
|
+
if name == :locale
|
49
|
+
self.try(:locale).presence || self.translation.locale
|
50
|
+
elsif self.class.translated?(name)
|
77
51
|
if (value = globalize.fetch(options[:locale] || Globalize.locale, name))
|
78
52
|
value
|
79
53
|
else
|
@@ -88,24 +62,24 @@ module Globalize
|
|
88
62
|
translated_attribute_names.map(&:to_s) + super
|
89
63
|
end
|
90
64
|
|
91
|
-
|
92
|
-
self.class.translated?(name)
|
93
|
-
end
|
65
|
+
delegate :translated?, :to => :class
|
94
66
|
|
95
67
|
def translated_attributes
|
96
68
|
translated_attribute_names.inject({}) do |attributes, name|
|
97
|
-
|
69
|
+
if self.respond_to?(name) && Globalize.locale == I18n.default_locale
|
70
|
+
attributes.merge(name.to_s => self.send(name))
|
71
|
+
else
|
72
|
+
attributes.merge(name.to_s => translation.send(name))
|
73
|
+
end
|
98
74
|
end
|
99
75
|
end
|
100
76
|
|
101
77
|
# This method is basically the method built into Rails
|
102
78
|
# but we have to pass {:translated => false}
|
103
79
|
def untranslated_attributes
|
104
|
-
attrs
|
105
|
-
|
106
|
-
attrs[name] = read_attribute(name, {:translated => false})
|
80
|
+
attribute_names.inject({}) do |attrs, name|
|
81
|
+
attrs[name] = read_attribute(name, {:translated => false}); attrs
|
107
82
|
end
|
108
|
-
attrs
|
109
83
|
end
|
110
84
|
|
111
85
|
def set_translations(options)
|
@@ -168,22 +142,16 @@ module Globalize
|
|
168
142
|
translation_caches[::Globalize.locale] = translation.previous_version
|
169
143
|
end
|
170
144
|
|
171
|
-
def
|
172
|
-
|
173
|
-
end
|
174
|
-
|
175
|
-
private
|
176
|
-
|
177
|
-
def update(*)
|
178
|
-
I18n.with_locale(read_attribute(:locale) || I18n.default_locale) do
|
145
|
+
def save(*)
|
146
|
+
Globalize.with_locale(read_attribute(:locale) || I18n.default_locale) do
|
179
147
|
super
|
180
148
|
end
|
181
149
|
end
|
182
150
|
|
183
|
-
def
|
184
|
-
|
185
|
-
|
186
|
-
|
151
|
+
def column_for_attribute name
|
152
|
+
return super if translated_attribute_names.exclude?(name)
|
153
|
+
|
154
|
+
globalize.send(:column_for_attribute, name)
|
187
155
|
end
|
188
156
|
|
189
157
|
protected
|
@@ -68,7 +68,7 @@ module Globalize
|
|
68
68
|
|
69
69
|
def create_translation_table
|
70
70
|
connection.create_table(translations_table_name) do |t|
|
71
|
-
t.references table_name.sub(/^#{table_name_prefix}/, '').singularize
|
71
|
+
t.references table_name.sub(/^#{table_name_prefix}/, '').singularize, :null => false
|
72
72
|
t.string :locale, :null => false
|
73
73
|
t.timestamps
|
74
74
|
end
|
@@ -130,7 +130,7 @@ module Globalize
|
|
130
130
|
end
|
131
131
|
|
132
132
|
# Now, update the actual model's record with the hash.
|
133
|
-
@model.
|
133
|
+
@model.where(:id => translated_record['id']).update_all(fields_to_update)
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Globalize
|
2
|
+
module ActiveRecord
|
3
|
+
class Relation < ::ActiveRecord::Relation
|
4
|
+
|
5
|
+
attr_accessor :translations_reload_needed
|
6
|
+
|
7
|
+
class WhereChain < ::ActiveRecord::QueryMethods::WhereChain
|
8
|
+
def not(*args)
|
9
|
+
if @scope.parse_translated_conditions!(*args)
|
10
|
+
@scope.translations_reload_needed = true
|
11
|
+
@scope.with_translations_in_this_locale.where.not(*args)
|
12
|
+
else
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def where(opts = :chain, *rest)
|
19
|
+
if opts == :chain
|
20
|
+
WhereChain.new(spawn)
|
21
|
+
elsif parse_translated_conditions!(opts, *rest)
|
22
|
+
self.translations_reload_needed = true
|
23
|
+
super.with_translations_in_this_locale
|
24
|
+
else
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def exists?(conditions = :none)
|
30
|
+
if parse_translated_conditions!(conditions)
|
31
|
+
with_translations_in_this_locale.exists?(conditions)
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
%w[ first last take ].each do |method_name|
|
38
|
+
eval <<-END_RUBY
|
39
|
+
def #{method_name}
|
40
|
+
super.tap do |f|
|
41
|
+
if translations_reload_needed
|
42
|
+
f.translations.reload
|
43
|
+
translations_reload_needed = false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
END_RUBY
|
48
|
+
end
|
49
|
+
|
50
|
+
def with_translations_in_this_locale
|
51
|
+
with_translations(Globalize.locale)
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_translated_conditions!(opts, *rest)
|
55
|
+
if opts.is_a?(Hash) && (keys = opts.symbolize_keys.keys & translated_attribute_names).present?
|
56
|
+
keys.each do |key|
|
57
|
+
opts[translated_column_name(key)] = opts.delete(key) || opts.delete(key.to_s)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'paper_trail'
|
2
|
+
|
3
|
+
module Globalize
|
4
|
+
module Versioning
|
5
|
+
module PaperTrail
|
6
|
+
# At present this isn't used but we may use something similar in paper trail
|
7
|
+
# shortly, so leaving it around to reference easily.
|
8
|
+
#def versioned_columns
|
9
|
+
#super + self.class.translated_attribute_names
|
10
|
+
#end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::Base.class_eval do
|
16
|
+
class << self
|
17
|
+
def has_paper_trail_with_globalize(*args)
|
18
|
+
has_paper_trail_without_globalize(*args)
|
19
|
+
include Globalize::Versioning::PaperTrail
|
20
|
+
end
|
21
|
+
alias_method_chain :has_paper_trail, :globalize
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
PaperTrail::Version.class_eval do
|
26
|
+
|
27
|
+
before_save do |version|
|
28
|
+
version.locale = Globalize.locale.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.for_this_locale
|
32
|
+
where :locale => Globalize.locale.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
def sibling_versions_with_locales
|
36
|
+
sibling_versions_without_locales.for_this_locale
|
37
|
+
end
|
38
|
+
alias_method_chain :sibling_versions, :locales
|
39
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Relation
|
3
|
+
if ::ActiveRecord::VERSION::STRING >= "3.2.1"
|
4
|
+
def where_values_hash
|
5
|
+
_translations_table_name = klass.respond_to?(:translations_table_name) ? klass.translations_table_name : nil
|
6
|
+
|
7
|
+
equalities = with_default_scope.where_values.grep(Arel::Nodes::Equality).find_all { |node|
|
8
|
+
[table_name, _translations_table_name].compact.include? node.left.relation.name
|
9
|
+
}
|
10
|
+
|
11
|
+
binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
|
12
|
+
|
13
|
+
Hash[equalities.map { |where|
|
14
|
+
name = where.left.name
|
15
|
+
[name, binds.fetch(name.to_s) { where.right } ]
|
16
|
+
}].with_indifferent_access
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|