has_localization_table 0.3.13 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/lib/has_localization_table/active_record/callbacks.rb +16 -4
- data/lib/has_localization_table/active_record/meta_methods.rb +12 -12
- data/lib/has_localization_table/active_record/relation.rb +14 -8
- data/lib/has_localization_table/version.rb +1 -1
- data/spec/active_record/callbacks_spec.rb +51 -0
- data/spec/active_record/relation_spec.rb +24 -2
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZDVjZmEwMjUwZTk5OTMxMWJhZmQ4MmJhNTk5NTFjNDZhNjcxNDk3OQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
Y2ExNzJkNWJkMTY0MmQyMDM4MmQ5Y2YzYTVlNWE5YWUwMzhkYjg1ZA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OTQzNGFhMThhMmZmY2NiMjliOTJlYmQ2YWVmYjM3YTYzM2E0ZDdmNTA0YzI4
|
10
|
+
OTdkODNmYzRhYjNiNGIyNTdkMGIwYzRjMTBjMzZkNmQ3MjczMTUyZmQ5NmVj
|
11
|
+
ODQyZTQ5N2JjYTcwZjYwMDgwNTY3ZTBkNDM4MWUxMmZjNzE1ZTc=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZDkwZGMxODU0ODNiNjNkMzVmNGRmYzYyODBhYmUzMjgyNTViMDYxYjgxY2E2
|
14
|
+
YzM1MDY5OGNkZTVlYWFkMTYyMjdjZGI2MWMzODFlYTE4OGU3NGY2NTRlYzYz
|
15
|
+
NDcwMzViNTc5Yjg4MTgxNGNkN2QzMTUwYWEzYTBiMzA1ZDc0ODQ=
|
@@ -1,17 +1,21 @@
|
|
1
1
|
module HasLocalizationTable
|
2
2
|
module ActiveRecord
|
3
3
|
module Callbacks
|
4
|
+
def self.extended(klass)
|
5
|
+
klass.send(:include, InstanceMethods)
|
6
|
+
end
|
7
|
+
|
4
8
|
def setup_localization_callbacks!
|
5
9
|
# Initialize string records after main record initialization
|
6
|
-
after_initialize do
|
10
|
+
after_initialize(if: :add_localization_after_initialize?) do
|
7
11
|
build_missing_localizations!
|
8
12
|
end
|
9
|
-
|
13
|
+
|
10
14
|
before_validation do
|
11
15
|
reject_empty_localizations!
|
12
16
|
build_missing_localizations!
|
13
17
|
end
|
14
|
-
|
18
|
+
|
15
19
|
# Reject any blank strings before saving the record
|
16
20
|
# Validation will have happened by this point, so if there is a required string that is needed, it won't be rejected
|
17
21
|
before_save do
|
@@ -19,6 +23,14 @@ module HasLocalizationTable
|
|
19
23
|
end
|
20
24
|
end
|
21
25
|
private :setup_localization_callbacks!
|
26
|
+
|
27
|
+
module InstanceMethods
|
28
|
+
def add_localization_after_initialize?
|
29
|
+
localization_table_options.fetch(:initialize, true) && !localization_table_options.fetch(:include, false)
|
30
|
+
end
|
31
|
+
|
32
|
+
private :add_localization_after_initialize?
|
33
|
+
end
|
22
34
|
end
|
23
35
|
end
|
24
|
-
end
|
36
|
+
end
|
@@ -4,52 +4,52 @@ module HasLocalizationTable
|
|
4
4
|
def self.extended(klass)
|
5
5
|
klass.send(:include, InstanceMethods)
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def localization_class
|
9
9
|
localization_table_options[:class_name].constantize
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def localization_association_name
|
13
13
|
localization_table_options[:association_name]
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
def localized_attributes
|
17
17
|
# Determine which attributes of the association model should be accessible through the base class
|
18
18
|
# ie. everything that's not a primary key, foreign key, or timestamp attribute
|
19
19
|
association_name = self.localization_table_options[:association_name] || :strings
|
20
20
|
association = reflect_on_association(association_name)
|
21
|
-
|
21
|
+
|
22
22
|
attribute_names = association.klass.attribute_names
|
23
23
|
timestamp_attrs = association.klass.new.send(:all_timestamp_attributes_in_model).map(&:to_s)
|
24
24
|
foreign_keys = association.klass.reflect_on_all_associations.map{ |a| a.association_foreign_key }
|
25
25
|
primary_keys = [association.klass.primary_key]
|
26
26
|
# protected_attrs = association.klass.protected_attributes.to_a
|
27
|
-
|
27
|
+
|
28
28
|
(attribute_names - timestamp_attrs - foreign_keys - primary_keys).map(&:to_sym)
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def localized_attribute_required?(attribute)
|
32
32
|
return false unless localization_table_options[:required] || false
|
33
33
|
return true unless localization_table_options[:optional]
|
34
|
-
|
35
|
-
!localization_table_options[:optional].include?(attribute)
|
34
|
+
|
35
|
+
!localization_table_options[:optional].include?(attribute)
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
module InstanceMethods
|
39
39
|
# Helper method for getting the localization association without having to look up the name each time
|
40
40
|
def localization_association
|
41
41
|
association_name = localization_table_options[:association_name]
|
42
42
|
send(association_name)
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
def localized_attributes
|
46
46
|
self.class.localized_attributes
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def localization_table_options
|
50
50
|
self.class.localization_table_options
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
55
|
-
end
|
55
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module HasLocalizationTable
|
2
2
|
module ActiveRecord
|
3
3
|
module Relation
|
4
|
+
RESERVED_KEYS = [:association_name, :required, :optional, :dependent, :has_one, :initialize, :include]
|
5
|
+
|
4
6
|
def self.extended(klass)
|
5
7
|
klass.send(:include, InstanceMethods)
|
6
8
|
klass.send(:create_localization_associations!)
|
@@ -8,10 +10,10 @@ module HasLocalizationTable
|
|
8
10
|
# Alias the scoping method to use the actual association name
|
9
11
|
alias_method :"with_#{klass.localization_association_name}", :with_localizations
|
10
12
|
end
|
11
|
-
|
13
|
+
|
12
14
|
def with_localizations(locale = HasLocalizationTable.current_locale.id)
|
13
15
|
lcat = localization_class.arel_table
|
14
|
-
|
16
|
+
|
15
17
|
scoped.joins(
|
16
18
|
arel_table.join(lcat, Arel::Nodes::OuterJoin).
|
17
19
|
on(lcat[:"#{self.name.underscore}_id"].eq(arel_table[self.primary_key]).and(lcat[HasLocalizationTable.locale_foreign_key].eq(locale))).
|
@@ -37,7 +39,7 @@ module HasLocalizationTable
|
|
37
39
|
association_name = localization_association_name.to_s.singularize.to_sym
|
38
40
|
association_name = :localization if localized_attributes.include?(association_name)
|
39
41
|
|
40
|
-
has_one_options = localization_table_options.except(
|
42
|
+
has_one_options = localization_table_options.except(*RESERVED_KEYS).
|
41
43
|
merge({ conditions: Proc.new { "#{table_name}.#{foreign_key} = #{HasLocalizationTable.current_locale.id}"} })
|
42
44
|
|
43
45
|
self.has_one association_name, has_one_options
|
@@ -46,18 +48,22 @@ module HasLocalizationTable
|
|
46
48
|
|
47
49
|
# Collect all localizations for the object
|
48
50
|
def create_has_many_association
|
49
|
-
self.has_many localization_association_name, localization_table_options.except(
|
51
|
+
self.has_many localization_association_name, localization_table_options.except(*RESERVED_KEYS).reverse_merge(autosave: true) do
|
50
52
|
def for_locale(locale)
|
51
53
|
# where(HasLocalizationTable.locale_foreign_key => locale).first
|
52
54
|
select{ |s| s.send(HasLocalizationTable.locale_foreign_key) == locale }.first
|
53
55
|
end
|
54
56
|
end
|
57
|
+
|
58
|
+
if localization_table_options.fetch(:include, false)
|
59
|
+
self.default_scope -> { includes(localization_association_name) }
|
60
|
+
end
|
55
61
|
end
|
56
62
|
|
57
63
|
public
|
58
64
|
|
59
65
|
module InstanceMethods
|
60
|
-
# Add localization objects for any available locale that doesn't have one
|
66
|
+
# Add localization objects for any available locale that doesn't have one
|
61
67
|
def build_missing_localizations!
|
62
68
|
return unless HasLocalizationTable.all_locales.any?
|
63
69
|
|
@@ -66,11 +72,11 @@ module HasLocalizationTable
|
|
66
72
|
unless localization_association.detect{ |str| str.send(HasLocalizationTable.locale_foreign_key) == locale.id }
|
67
73
|
localization_association.build(HasLocalizationTable.locale_foreign_key => locale.id)
|
68
74
|
end
|
69
|
-
|
75
|
+
|
70
76
|
localization_association.sort_by!{ |l| locale_ids.index(l.send(HasLocalizationTable.locale_foreign_key)) || 0 }
|
71
77
|
end
|
72
78
|
end
|
73
|
-
|
79
|
+
|
74
80
|
# Remove localization objects that are not filled in
|
75
81
|
def reject_empty_localizations!
|
76
82
|
localization_association.reject! { |l| !l.persisted? and localized_attributes.all?{ |attr| l.send(attr).blank? } }
|
@@ -78,4 +84,4 @@ module HasLocalizationTable
|
|
78
84
|
end
|
79
85
|
end
|
80
86
|
end
|
81
|
-
end
|
87
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HasLocalizationTable do
|
4
|
+
before do
|
5
|
+
# Configure HLT
|
6
|
+
HasLocalizationTable.configure do |c|
|
7
|
+
c.primary_locale = Locale.first
|
8
|
+
c.current_locale = Locale.first
|
9
|
+
c.all_locales = Locale.all
|
10
|
+
end
|
11
|
+
|
12
|
+
Object.send(:remove_const, :Article) rescue nil
|
13
|
+
Article = Class.new(ActiveRecord::Base)
|
14
|
+
Article.has_localization_table
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:article) { Article.create!(name: "Test", description: "Description") }
|
18
|
+
|
19
|
+
it 'should initialize the localizations association on initialize' do
|
20
|
+
a = Article.new
|
21
|
+
a.localizations.wont_be_empty
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should initialize the localizations association on initialize for an existing object' do
|
25
|
+
a = Article.find(article.id)
|
26
|
+
a.localizations.wont_be_empty
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should not initialize the association on initialize if initialize: false is given in config' do
|
30
|
+
Article.has_localization_table initialize: false
|
31
|
+
a = Article.new
|
32
|
+
a.localizations.must_be_empty
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should not initialize the association for an existing object if initialize: false is given in config' do
|
36
|
+
Article.has_localization_table initialize: false
|
37
|
+
a = Article.find(article.id)
|
38
|
+
refute(a.localizations.loaded?)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should not initialize the association on initialize if include: true is given in config' do
|
42
|
+
Article.has_localization_table include: true
|
43
|
+
a = Article.new
|
44
|
+
a.localizations.must_be_empty
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should load associations if include: true is given' do
|
48
|
+
Article.has_localization_table include: true
|
49
|
+
assert Article.find(article.id).localizations.loaded?
|
50
|
+
end
|
51
|
+
end
|
@@ -5,7 +5,7 @@ describe HasLocalizationTable do
|
|
5
5
|
before do
|
6
6
|
# Configure HLT
|
7
7
|
HasLocalizationTable.configure do |c|
|
8
|
-
c.primary_locale = Locale.first
|
8
|
+
c.primary_locale = Locale.first
|
9
9
|
c.current_locale = Locale.first
|
10
10
|
c.all_locales = Locale.all
|
11
11
|
end
|
@@ -91,4 +91,26 @@ describe HasLocalizationTable do
|
|
91
91
|
conditions.call.must_equal "article_localizations.locale_id = 3"
|
92
92
|
end
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
|
+
it 'should add a default scope if include: true is given' do
|
96
|
+
Article.stub :localization_table_options, { include: true } do
|
97
|
+
Article.default_scopes.must_be_empty
|
98
|
+
Article.send(:extend, HasLocalizationTable::ActiveRecord::Relation)
|
99
|
+
Article.default_scopes.size.must_equal(1)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should not add a default scope if include: false is given' do
|
104
|
+
Article.stub :localization_table_options, { include: false } do
|
105
|
+
Article.send(:extend, HasLocalizationTable::ActiveRecord::Relation)
|
106
|
+
Article.default_scopes.must_be_empty
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should not add a default scope if include: is not given' do
|
111
|
+
Article.stub :localization_table_options, { } do
|
112
|
+
Article.send(:extend, HasLocalizationTable::ActiveRecord::Relation)
|
113
|
+
Article.default_scopes.must_be_empty
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_localization_table
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Vandersluis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
type: :runtime
|
@@ -106,6 +106,7 @@ files:
|
|
106
106
|
- lib/has_localization_table/config.rb
|
107
107
|
- lib/has_localization_table/version.rb
|
108
108
|
- spec/active_record/attributes_spec.rb
|
109
|
+
- spec/active_record/callbacks_spec.rb
|
109
110
|
- spec/active_record/finder_method_spec.rb
|
110
111
|
- spec/active_record/ordered_by_spec.rb
|
111
112
|
- spec/active_record/relation_spec.rb
|
@@ -140,6 +141,7 @@ summary: Sets up associations and attribute methods for AR models that have a re
|
|
140
141
|
table to contain user-created data in multiple languages.
|
141
142
|
test_files:
|
142
143
|
- spec/active_record/attributes_spec.rb
|
144
|
+
- spec/active_record/callbacks_spec.rb
|
143
145
|
- spec/active_record/finder_method_spec.rb
|
144
146
|
- spec/active_record/ordered_by_spec.rb
|
145
147
|
- spec/active_record/relation_spec.rb
|