hooktstudios-globalize3 0.2.0.beta8
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.
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.textile +205 -0
- data/Rakefile +22 -0
- data/lib/globalize.rb +52 -0
- data/lib/globalize/active_record.rb +12 -0
- data/lib/globalize/active_record/act_macro.rb +56 -0
- data/lib/globalize/active_record/adapter.rb +101 -0
- data/lib/globalize/active_record/attributes.rb +27 -0
- data/lib/globalize/active_record/class_methods.rb +156 -0
- data/lib/globalize/active_record/exceptions.rb +19 -0
- data/lib/globalize/active_record/instance_methods.rb +175 -0
- data/lib/globalize/active_record/migration.rb +161 -0
- data/lib/globalize/active_record/translation.rb +41 -0
- data/lib/globalize/versioning.rb +5 -0
- data/lib/globalize/versioning/paper_trail.rb +41 -0
- data/lib/globalize3.rb +1 -0
- data/lib/globalize3/version.rb +3 -0
- data/lib/i18n/missing_translations_log_handler.rb +41 -0
- data/lib/i18n/missing_translations_raise_handler.rb +25 -0
- data/lib/patches/active_record/query_method.rb +35 -0
- data/lib/patches/active_record/xml_attribute_serializer.rb +13 -0
- metadata +160 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
# Helper class for storing values per locale. Used by Globalize::Adapter
|
2
|
+
# to stash and cache attribute values.
|
3
|
+
|
4
|
+
module Globalize
|
5
|
+
module ActiveRecord
|
6
|
+
class Attributes < Hash # TODO: Think about using HashWithIndifferentAccess ?
|
7
|
+
def [](locale)
|
8
|
+
locale = locale.to_sym
|
9
|
+
self[locale] = {} unless has_key?(locale)
|
10
|
+
self.fetch(locale)
|
11
|
+
end
|
12
|
+
|
13
|
+
def contains?(locale, name)
|
14
|
+
self[locale].has_key?(name.to_s)
|
15
|
+
end
|
16
|
+
|
17
|
+
def read(locale, name)
|
18
|
+
self[locale][name.to_s]
|
19
|
+
end
|
20
|
+
|
21
|
+
def write(locale, name, value)
|
22
|
+
#raise 'z' if value.nil? # TODO
|
23
|
+
self[locale][name.to_s] = value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module Globalize
|
2
|
+
module ActiveRecord
|
3
|
+
module ClassMethods
|
4
|
+
delegate :translated_locales, :set_translations_table_name, :to => :translation_class
|
5
|
+
|
6
|
+
def with_locales(*locales)
|
7
|
+
scoped.merge(translation_class.with_locales(*locales))
|
8
|
+
end
|
9
|
+
|
10
|
+
def with_translations(*locales)
|
11
|
+
locales = translated_locales if locales.empty?
|
12
|
+
includes(:translations).with_locales(locales).with_required_attributes
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_required_attributes
|
16
|
+
required_translated_attributes.inject(scoped) do |scope, name|
|
17
|
+
scope.where("#{translated_column_name(name)} IS NOT NULL")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def with_translated_attribute(name, value, locales = nil)
|
22
|
+
locales ||= Globalize.fallbacks
|
23
|
+
with_translations.where(
|
24
|
+
translated_column_name(name) => value,
|
25
|
+
translated_column_name(:locale) => Array(locales).map(&:to_s)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def translated?(name)
|
30
|
+
translated_attribute_names.include?(name.to_sym)
|
31
|
+
end
|
32
|
+
|
33
|
+
def required_attributes
|
34
|
+
validators.map { |v| v.attributes if v.is_a?(ActiveModel::Validations::PresenceValidator) }.flatten
|
35
|
+
end
|
36
|
+
|
37
|
+
def required_translated_attributes
|
38
|
+
translated_attribute_names & required_attributes
|
39
|
+
end
|
40
|
+
|
41
|
+
def translation_class
|
42
|
+
@translation_class ||= begin
|
43
|
+
klass = self.const_get(:Translation) rescue nil
|
44
|
+
if klass.nil? || klass.class_name != (self.class_name + "Translation")
|
45
|
+
klass = self.const_set(:Translation, Class.new(Globalize::ActiveRecord::Translation))
|
46
|
+
end
|
47
|
+
|
48
|
+
klass.belongs_to name.underscore.gsub('/', '_')
|
49
|
+
klass
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def translations_table_name
|
54
|
+
translation_class.table_name
|
55
|
+
end
|
56
|
+
|
57
|
+
def translated_column_name(name)
|
58
|
+
"#{translation_class.table_name}.#{name}"
|
59
|
+
end
|
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
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def supported_on_missing?(method_id)
|
72
|
+
return super unless RUBY_VERSION < '1.9' || respond_to?(:translated_attribute_names)
|
73
|
+
match = ::ActiveRecord::DynamicFinderMatch.match(method_id) || ::ActiveRecord::DynamicScopeMatch.match(method_id)
|
74
|
+
return false if match.nil?
|
75
|
+
|
76
|
+
attribute_names = match.attribute_names.map(&:to_sym)
|
77
|
+
translated_attributes = attribute_names & translated_attribute_names
|
78
|
+
return false if translated_attributes.empty?
|
79
|
+
|
80
|
+
untranslated_attributes = attribute_names - translated_attributes
|
81
|
+
return false if untranslated_attributes.any?{|unt| ! respond_to?(:"scoped_by_#{unt}")}
|
82
|
+
return [match, attribute_names, translated_attributes, untranslated_attributes]
|
83
|
+
end
|
84
|
+
|
85
|
+
def method_missing(method_id, *arguments, &block)
|
86
|
+
match, attribute_names, translated_attributes, untranslated_attributes = supported_on_missing?(method_id)
|
87
|
+
return super unless match
|
88
|
+
|
89
|
+
scope = scoped
|
90
|
+
|
91
|
+
translated_attributes.each do |attr|
|
92
|
+
scope = scope.with_translated_attribute(attr, arguments[attribute_names.index(attr)])
|
93
|
+
end
|
94
|
+
|
95
|
+
untranslated_attributes.each do |unt|
|
96
|
+
index = attribute_names.index(unt)
|
97
|
+
raise StandarError unless index
|
98
|
+
scope = scope.send(:"scoped_by_#{unt}", arguments[index])
|
99
|
+
end
|
100
|
+
|
101
|
+
if match.is_a?(::ActiveRecord::DynamicFinderMatch)
|
102
|
+
if match.instantiator? and scope.blank?
|
103
|
+
return scope.find_or_instantiator_by_attributes match, attribute_names, *arguments, &block
|
104
|
+
end
|
105
|
+
|
106
|
+
return scope.send(match.finder).tap do |found|
|
107
|
+
found.is_a?(Array) ? found.map { |f| f.translations.reload } : found.translations.reload unless found.nil?
|
108
|
+
end
|
109
|
+
end
|
110
|
+
return scope
|
111
|
+
end
|
112
|
+
|
113
|
+
def find_or_instantiator_by_attributes(match, attributes, *args)
|
114
|
+
options = args.size > 1 && args.last(2).all?{ |a| a.is_a?(Hash) } ? args.extract_options! : {}
|
115
|
+
protected_attributes_for_create, unprotected_attributes_for_create = {}, {}
|
116
|
+
args.each_with_index do |arg, i|
|
117
|
+
if arg.is_a?(Hash)
|
118
|
+
protected_attributes_for_create = args[i].with_indifferent_access
|
119
|
+
else
|
120
|
+
unprotected_attributes_for_create[attributes[i]] = args[i]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
record = if ::ActiveRecord::VERSION::STRING < "3.1.0"
|
125
|
+
class_name.constantize.new do |r|
|
126
|
+
r.send(:attributes=, protected_attributes_for_create, true) unless protected_attributes_for_create.empty?
|
127
|
+
r.send(:attributes=, unprotected_attributes_for_create, false) unless unprotected_attributes_for_create.empty?
|
128
|
+
end
|
129
|
+
else
|
130
|
+
class_name.constantize.new(protected_attributes_for_create, options) do |r|
|
131
|
+
r.assign_attributes(unprotected_attributes_for_create, :without_protection => true)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
yield(record) if block_given?
|
135
|
+
record.send(match.bang? ? :save! : :save) if match.instantiator.eql?(:create)
|
136
|
+
|
137
|
+
record
|
138
|
+
end
|
139
|
+
|
140
|
+
protected
|
141
|
+
|
142
|
+
def translated_attr_accessor(name)
|
143
|
+
define_method(:"#{name}=") do |value|
|
144
|
+
write_attribute(name, value)
|
145
|
+
end
|
146
|
+
define_method(name) do |*args|
|
147
|
+
read_attribute(name, {:locale => args.first})
|
148
|
+
end
|
149
|
+
alias_method :"#{name}_before_type_cast", name
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Globalize
|
2
|
+
module ActiveRecord
|
3
|
+
module Exceptions
|
4
|
+
class MigrationError < StandardError; end
|
5
|
+
|
6
|
+
class BadFieldName < MigrationError
|
7
|
+
def initialize(field)
|
8
|
+
super("Missing translated field #{field.inspect}")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class BadFieldType < MigrationError
|
13
|
+
def initialize(name, type)
|
14
|
+
super("Bad field type for field #{name.inspect} (#{type.inspect}), should be :string or :text")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
module Globalize
|
2
|
+
module ActiveRecord
|
3
|
+
module InstanceMethods
|
4
|
+
delegate :translated_locales, :to => :translations
|
5
|
+
|
6
|
+
def globalize
|
7
|
+
@globalize ||= Adapter.new(self)
|
8
|
+
end
|
9
|
+
|
10
|
+
def attributes
|
11
|
+
super.merge(translated_attributes)
|
12
|
+
end
|
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
|
37
|
+
end
|
38
|
+
|
39
|
+
def write_attribute(name, value, options = {})
|
40
|
+
# raise 'y' if value.nil? # TODO.
|
41
|
+
|
42
|
+
if translated?(name)
|
43
|
+
# Deprecate old use of locale
|
44
|
+
unless options.is_a?(Hash)
|
45
|
+
warn "[DEPRECATION] passing 'locale' as #{options.inspect} is deprecated. Please use {:locale => #{options.inspect}} instead."
|
46
|
+
options = {:locale => options}
|
47
|
+
end
|
48
|
+
options = {:locale => nil}.merge(options)
|
49
|
+
attribute_will_change! name.to_s
|
50
|
+
the_locale = options[:locale] || Globalize.locale
|
51
|
+
self.translations.reject!{|t| t.new_record? && t.locale != the_locale}
|
52
|
+
globalize.write(the_locale, name, value)
|
53
|
+
else
|
54
|
+
super(name, value)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def read_attribute(name, options = {})
|
59
|
+
# Deprecate old use of locale
|
60
|
+
unless options.is_a?(Hash)
|
61
|
+
warn "[DEPRECATION] passing 'locale' as #{options.inspect} is deprecated. Please use {:locale => #{options.inspect}} instead."
|
62
|
+
options = {:locale => options}
|
63
|
+
end
|
64
|
+
|
65
|
+
options = {:translated => true, :locale => nil}.merge(options)
|
66
|
+
if self.class.translated?(name) and options[:translated]
|
67
|
+
globalize.fetch(options[:locale] || Globalize.locale, name)
|
68
|
+
else
|
69
|
+
super(name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def attribute_names
|
74
|
+
translated_attribute_names.map(&:to_s) + super
|
75
|
+
end
|
76
|
+
|
77
|
+
def translated?(name)
|
78
|
+
self.class.translated?(name)
|
79
|
+
end
|
80
|
+
|
81
|
+
def translated_attributes
|
82
|
+
translated_attribute_names.inject({}) do |attributes, name|
|
83
|
+
attributes.merge(name.to_s => translation.send(name))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# This method is basically the method built into Rails
|
88
|
+
# but we have to pass {:translated => false}
|
89
|
+
def untranslated_attributes
|
90
|
+
attrs = {}
|
91
|
+
attribute_names.each do |name|
|
92
|
+
attrs[name] = read_attribute(name, {:translated => false})
|
93
|
+
end
|
94
|
+
attrs
|
95
|
+
end
|
96
|
+
|
97
|
+
def set_translations(options)
|
98
|
+
options.keys.each do |locale|
|
99
|
+
translation = translation_for(locale) ||
|
100
|
+
translations.build(:locale => locale.to_s)
|
101
|
+
translation.update_attributes!(options[locale])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def reload(options = nil)
|
106
|
+
translated_attribute_names.each { |name| @attributes.delete(name.to_s) }
|
107
|
+
globalize.reset
|
108
|
+
super(options)
|
109
|
+
end
|
110
|
+
|
111
|
+
def clone
|
112
|
+
obj = super
|
113
|
+
return obj unless respond_to?(:translated_attribute_names)
|
114
|
+
|
115
|
+
obj.instance_variable_set(:@translations, nil) if new_record? # Reset the collection because of rails bug: http://pastie.org/1521874
|
116
|
+
obj.instance_variable_set(:@globalize, nil )
|
117
|
+
each_locale_and_translated_attribute do |locale, name|
|
118
|
+
obj.globalize.write(locale, name, globalize.fetch(locale, name) )
|
119
|
+
end
|
120
|
+
|
121
|
+
return obj
|
122
|
+
end
|
123
|
+
|
124
|
+
def translation
|
125
|
+
translation_for(::Globalize.locale)
|
126
|
+
end
|
127
|
+
|
128
|
+
def translation_for(locale)
|
129
|
+
@translation_caches ||= {}
|
130
|
+
unless @translation_caches[locale]
|
131
|
+
# Fetch translations from database as those in the translation collection may be incomplete
|
132
|
+
_translation = translations.detect{|t| t.locale.to_s == locale.to_s}
|
133
|
+
_translation ||= translations.with_locale(locale).first
|
134
|
+
_translation ||= translations.build(:locale => locale)
|
135
|
+
@translation_caches[locale] = _translation
|
136
|
+
end
|
137
|
+
@translation_caches[locale]
|
138
|
+
end
|
139
|
+
|
140
|
+
def rollback
|
141
|
+
@translation_caches[::Globalize.locale] = translation.previous_version
|
142
|
+
end
|
143
|
+
|
144
|
+
protected
|
145
|
+
|
146
|
+
def each_locale_and_translated_attribute
|
147
|
+
used_locales.each do |locale|
|
148
|
+
translated_attribute_names.each do |name|
|
149
|
+
yield locale, name
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def used_locales
|
155
|
+
locales = globalize.stash.keys.concat(globalize.stash.keys).concat(translations.translated_locales)
|
156
|
+
locales.uniq!
|
157
|
+
locales
|
158
|
+
end
|
159
|
+
|
160
|
+
def save_translations!
|
161
|
+
globalize.save_translations!
|
162
|
+
@translation_caches = {}
|
163
|
+
end
|
164
|
+
|
165
|
+
def with_given_locale(attributes, &block)
|
166
|
+
attributes.symbolize_keys! if attributes.respond_to?(:symbolize_keys!)
|
167
|
+
if locale = attributes.try(:delete, :locale)
|
168
|
+
Globalize.with_locale(locale, &block)
|
169
|
+
else
|
170
|
+
yield
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
module Globalize
|
4
|
+
module ActiveRecord
|
5
|
+
module Migration
|
6
|
+
attr_reader :globalize_migrator
|
7
|
+
|
8
|
+
def globalize_migrator
|
9
|
+
@globalize_migrator ||= Migrator.new(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
delegate :create_translation_table!, :drop_translation_table!,
|
13
|
+
:translation_index_name, :to => :globalize_migrator
|
14
|
+
|
15
|
+
class Migrator
|
16
|
+
include Globalize::ActiveRecord::Exceptions
|
17
|
+
|
18
|
+
attr_reader :model, :fields
|
19
|
+
delegate :translated_attribute_names, :connection, :table_name,
|
20
|
+
:table_name_prefix, :translations_table_name, :columns, :to => :model
|
21
|
+
|
22
|
+
def initialize(model)
|
23
|
+
@model = model
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_translation_table!(fields = {}, options = {})
|
27
|
+
@fields = fields
|
28
|
+
complete_translated_fields
|
29
|
+
validate_translated_fields
|
30
|
+
|
31
|
+
create_translation_table
|
32
|
+
move_data_to_translation_table if options[:migrate_data]
|
33
|
+
remove_source_columns if options[:remove_source_columns]
|
34
|
+
create_translations_index
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove_source_columns
|
38
|
+
translated_attribute_names.each do |attribute|
|
39
|
+
connection.remove_column(table_name, attribute)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def drop_translation_table!(options = {})
|
44
|
+
move_data_to_model_table if options[:migrate_data]
|
45
|
+
drop_translations_index
|
46
|
+
drop_translation_table
|
47
|
+
end
|
48
|
+
|
49
|
+
def complete_translated_fields
|
50
|
+
translated_attribute_names.each do |name|
|
51
|
+
fields[name] = column_type(name) unless fields[name]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_translation_table
|
56
|
+
connection.create_table(translations_table_name) do |t|
|
57
|
+
t.references table_name.sub(/^#{table_name_prefix}/, '').singularize
|
58
|
+
t.string :locale
|
59
|
+
fields.each { |name, type| t.column name, type }
|
60
|
+
t.timestamps
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_translations_index
|
65
|
+
connection.add_index(
|
66
|
+
translations_table_name,
|
67
|
+
"#{table_name.sub(/^#{table_name_prefix}/, "").singularize}_id",
|
68
|
+
:name => translation_index_name
|
69
|
+
)
|
70
|
+
# index for select('DISTINCT locale') call in translation.rb
|
71
|
+
connection.add_index(
|
72
|
+
translations_table_name,
|
73
|
+
:locale
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
def drop_translation_table
|
78
|
+
connection.drop_table(translations_table_name)
|
79
|
+
end
|
80
|
+
|
81
|
+
def drop_translations_index
|
82
|
+
connection.remove_index(translations_table_name, :name => translation_index_name)
|
83
|
+
end
|
84
|
+
|
85
|
+
def move_data_to_translation_table
|
86
|
+
# this refactored version might be a good idea,
|
87
|
+
# but only if made into a code that doesn't break tests
|
88
|
+
# model.find_each do |record|
|
89
|
+
# translation = record.translations.build(:locale => I18n.default_locale)
|
90
|
+
# translated_attribute_names.each do |attribute|
|
91
|
+
# translation[attribute] = record[attribute]
|
92
|
+
# end
|
93
|
+
# translation.save!
|
94
|
+
# end
|
95
|
+
|
96
|
+
# Find all of the existing untranslated attributes for this model.
|
97
|
+
all_model_fields = @model.all
|
98
|
+
model_attributes = all_model_fields.map(&:untranslated_attributes)
|
99
|
+
all_model_fields.each do |model_record|
|
100
|
+
# Assign the attributes back to the model which will enable globalize3 to translate them.
|
101
|
+
model_record.attributes = model_attributes.detect{|a| a['id'] == model_record.id}
|
102
|
+
model_record.save!
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def move_data_to_model_table
|
107
|
+
add_missing_columns
|
108
|
+
|
109
|
+
# Find all of the translated attributes for all records in the model.
|
110
|
+
all_translated_attributes = @model.all.collect{|m| m.attributes}
|
111
|
+
all_translated_attributes.each do |translated_record|
|
112
|
+
# Create a hash containing the translated column names and their values.
|
113
|
+
translated_attribute_names.inject(fields_to_update={}) do |f, name|
|
114
|
+
f.update({name.to_sym => translated_record[name.to_s]})
|
115
|
+
end
|
116
|
+
|
117
|
+
# Now, update the actual model's record with the hash.
|
118
|
+
@model.update_all(fields_to_update, {:id => translated_record['id']})
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def validate_translated_fields
|
123
|
+
fields.each do |name, type|
|
124
|
+
raise BadFieldName.new(name) unless valid_field_name?(name)
|
125
|
+
raise BadFieldType.new(name, type) unless valid_field_type?(name, type)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def column_type(name)
|
130
|
+
columns.detect { |c| c.name == name.to_s }.try(:type)
|
131
|
+
end
|
132
|
+
|
133
|
+
def valid_field_name?(name)
|
134
|
+
translated_attribute_names.include?(name)
|
135
|
+
end
|
136
|
+
|
137
|
+
def valid_field_type?(name, type)
|
138
|
+
!translated_attribute_names.include?(name) || [:string, :text].include?(type)
|
139
|
+
end
|
140
|
+
|
141
|
+
def translation_index_name
|
142
|
+
# FIXME what's the max size of an index name?
|
143
|
+
index_name = "index_#{translations_table_name}_on_#{table_name.singularize}_id"
|
144
|
+
index_name.size < 50 ? index_name : "index_#{Digest::SHA1.hexdigest(index_name)}"
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def add_missing_columns
|
151
|
+
translated_attribute_names.map(&:to_s).each do |attribute|
|
152
|
+
unless model.column_names.include?(attribute)
|
153
|
+
connection.add_column(table_name, attribute, model::Translation.columns_hash[attribute].type)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|