globalize 3.1.0 → 4.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|