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.
@@ -19,7 +19,6 @@ module Globalize
19
19
  end
20
20
 
21
21
  def write(locale, name, value)
22
- #raise 'z' if value.nil? # TODO
23
22
  self[locale][name.to_s] = value
24
23
  end
25
24
  end
@@ -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
- scoped.merge(translation_class.with_locales(*locales))
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(scoped) do |scope, name|
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
- if RUBY_VERSION < '1.9'
62
- def respond_to?(method_id, *args, &block)
63
- supported_on_missing?(method_id) || super
64
- end
65
- else
66
- def respond_to_missing?(method_id, include_private = false)
67
- supported_on_missing?(method_id) || super
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 RUBY_VERSION < '1.9' || respond_to?(:translated_attribute_names)
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 = scoped
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? and scope.blank?
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? && ::ActiveRecord::VERSION::STRING >= "3.1.0"
110
+ match_finder_method << "!" if match.bang?
107
111
  return scope.send(match_finder_method).tap do |found|
108
- found.is_a?(Array) ? found.map { |f| f.translations.reload } : found.translations.reload unless found.nil?
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.size > 1 && args.last(2).all?{ |a| a.is_a?(Hash) } ? args.extract_options! : {}
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 = if ::ActiveRecord::VERSION::STRING < "3.1.0"
126
- new do |r|
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
- private
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 self.included(base)
15
- # Maintain Rails 3.0.x compatibility while adding Rails 3.1.x compatibility
16
- if base.method_defined?(:assign_attributes)
17
- base.class_eval %{
18
- def assign_attributes(attributes, options = {})
19
- with_given_locale(attributes) { super }
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
- if translated?(name)
41
- # Deprecate old use of locale
42
- unless options.is_a?(Hash)
43
- warn "[DEPRECATION] passing 'locale' as #{options.inspect} is deprecated. Please use {:locale => #{options.inspect}} instead."
44
- options = {:locale => options}
45
- end
46
- options = {:locale => Globalize.locale}.merge(options)
47
-
48
- # Dirty tracking, paraphrased from
49
- # ActiveRecord::AttributeMethods::Dirty#write_attribute.
50
- name_str = name.to_s
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
- super(name, value)
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
- if self.class.translated?(name) and options[:translated]
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
- def translated?(name)
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
- attributes.merge(name.to_s => translation.send(name))
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
- attribute_names.each do |name|
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 column_for_attribute name
172
- translated_attribute_names.include?(name) ? globalize.send(:column_for_attribute, name) : super
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 create(*)
184
- I18n.with_locale(read_attribute(:locale) || I18n.default_locale) do
185
- super
186
- end
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.update_all(fields_to_update, {:id => translated_record['id']})
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
@@ -2,7 +2,6 @@ module Globalize
2
2
  module ActiveRecord
3
3
  class Translation < ::ActiveRecord::Base
4
4
 
5
- attr_accessible :locale
6
5
  validates :locale, :presence => true
7
6
 
8
7
  class << self
@@ -0,0 +1,5 @@
1
+ module Globalize
2
+ module Versioning
3
+ autoload :PaperTrail, 'globalize/versioning/paper_trail'
4
+ end
5
+ 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