has_localization_table 0.4.0 → 0.4.2
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 +8 -8
- data/.rspec +1 -0
- data/.travis.yml +11 -0
- data/README.md +3 -0
- data/has_localization_table.gemspec +4 -3
- data/lib/has_localization_table/active_record/attributes.rb +35 -18
- data/lib/has_localization_table/active_record/attributes/cache.rb +35 -0
- data/lib/has_localization_table/active_record/callbacks.rb +0 -17
- data/lib/has_localization_table/active_record/meta_methods.rb +13 -2
- data/lib/has_localization_table/active_record/relation.rb +20 -6
- data/lib/has_localization_table/version.rb +1 -1
- data/spec/active_record/attributes_spec.rb +108 -28
- data/spec/active_record/callbacks_spec.rb +0 -28
- data/spec/has_localization_table_spec.rb +2 -2
- data/spec/support/setup.rb +2 -2
- metadata +13 -10
checksums.yaml
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
!binary "U0hBMQ==":
|
|
3
3
|
metadata.gz: !binary |-
|
|
4
|
-
|
|
4
|
+
ODMwMzhkMGY3Mjg1MzZiZjBkMDJjNDk1ZjFkNjk2Y2Y2N2MxODg1Nw==
|
|
5
5
|
data.tar.gz: !binary |-
|
|
6
|
-
|
|
6
|
+
N2VmZWRhMmQyMjIxNDVhMTVlZTc4ZDk0YWQzNmMzZjcyYzVlNjA5Mw==
|
|
7
7
|
SHA512:
|
|
8
8
|
metadata.gz: !binary |-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
NzFhMjg3NmE1OTcwMzZhNmI2ZDgzNDRhNzk0Njg0MmZlNzVjMTQ0Nzg0YTNj
|
|
10
|
+
NTdjZTI2OGNkYjU1MzI0NmE4YjI4Y2JiNjhmYjk3MjkxM2EwNTMxZmM4MDli
|
|
11
|
+
MmIxNjk5ODE0MzI4ZGY5MzJlOTkyZTk5NmIzMDlmYTg4NzQzZDg=
|
|
12
12
|
data.tar.gz: !binary |-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
ODgyYzU3Y2U3MTExMjg5MjQ5N2NiNDMwMzdhNjMwOGRjMzhjMGRmY2E2N2E0
|
|
14
|
+
OWE5MGIzYzczZjIzODkzNTA4ZTFmMGY4YWVmYWUzNDBjZDk5YWFiYjllNjhh
|
|
15
|
+
OTRlMzA1YzA1YjliZDQwOTIyM2U5MDEwZjUyZmJiY2Y0M2RmYzM=
|
data/.rspec
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# HasLocalizationTable
|
|
2
2
|
|
|
3
|
+
[](https://badge.fury.io/rb/has_localization_table)
|
|
4
|
+
[](https://travis-ci.org/dvandersluis/has_localization_table)
|
|
5
|
+
|
|
3
6
|
ActiveRecord plugin which adds setup and convenience methods for working with a relational localization table for user-driven data.
|
|
4
7
|
|
|
5
8
|
Adds accessors to retrieve localized attributes using the current locale, in order to avoid having to collect the correct object each time a value is needed. Localized attribute values are also cached for the current locale.
|
|
@@ -14,9 +14,10 @@ Gem::Specification.new do |gem|
|
|
|
14
14
|
gem.name = "has_localization_table"
|
|
15
15
|
gem.require_paths = ["lib"]
|
|
16
16
|
gem.version = HasLocalizationTable::VERSION
|
|
17
|
-
|
|
18
|
-
gem.add_dependency 'activesupport',
|
|
19
|
-
gem.add_dependency 'activerecord',
|
|
17
|
+
|
|
18
|
+
gem.add_dependency 'activesupport', '~> 3.0'
|
|
19
|
+
gem.add_dependency 'activerecord', '~> 3.0'
|
|
20
|
+
|
|
20
21
|
gem.add_development_dependency 'minitest'
|
|
21
22
|
gem.add_development_dependency 'sqlite3'
|
|
22
23
|
gem.add_development_dependency 'rake'
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
module HasLocalizationTable
|
|
2
2
|
module ActiveRecord
|
|
3
3
|
module Attributes
|
|
4
|
+
LOCALIZED_ATTRIBUTE_REGEX = /\A(?<name>[a-z0-9_]+)(?<suffix>=|_changed\?)?\Z/i
|
|
5
|
+
|
|
6
|
+
autoload :Cache, 'has_localization_table/active_record/attributes/cache'
|
|
7
|
+
|
|
4
8
|
def read_localized_attribute(attribute, locale = HasLocalizationTable.current_locale, options = {})
|
|
5
9
|
locale ||= HasLocalizationTable.current_locale
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
attr =
|
|
11
|
+
localized_attribute_cache.get(attribute, locale) do
|
|
12
|
+
attr = localization_for(locale).send(attribute) rescue ''
|
|
9
13
|
attr ||= '' # if the attribute somehow is nil, change it to a blank string so we're always dealing with strings
|
|
10
14
|
|
|
11
15
|
fallback = options.fetch(:fallback, HasLocalizationTable.config.fallback_locale)
|
|
@@ -19,46 +23,59 @@ module HasLocalizationTable
|
|
|
19
23
|
attr
|
|
20
24
|
end
|
|
21
25
|
end
|
|
22
|
-
|
|
26
|
+
|
|
23
27
|
def write_localized_attribute(attribute, value, locale = HasLocalizationTable.current_locale)
|
|
24
28
|
value = value.to_s
|
|
25
|
-
localization =
|
|
29
|
+
localization = localization_for(locale) ||
|
|
26
30
|
localization_association.build(HasLocalizationTable.locale_foreign_key => locale.id)
|
|
27
|
-
|
|
31
|
+
|
|
28
32
|
localization.send(:"#{attribute}=", value)
|
|
29
|
-
|
|
33
|
+
value.blank? ? localized_attribute_cache.clear(attribute, locale) : localized_attribute_cache.set(attribute, locale, value)
|
|
30
34
|
end
|
|
31
|
-
|
|
35
|
+
|
|
32
36
|
# Define attribute getters and setters
|
|
33
37
|
def method_missing(name, *args, &block)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
match = name.to_s.match(LOCALIZED_ATTRIBUTE_REGEX)
|
|
39
|
+
|
|
40
|
+
if match
|
|
41
|
+
if localized_attributes.include?(match[:name].to_sym)
|
|
42
|
+
if match[:suffix].nil? # No equals sign -- not a setter
|
|
37
43
|
# Try to load a string for the given locale
|
|
38
44
|
# If that fails, try for the primary locale
|
|
39
45
|
raise ArgumentError, "wrong number of arguments (#{args.size} for 0 or 1)" unless args.size.between?(0, 1)
|
|
40
46
|
options = args.extract_options!
|
|
41
47
|
return read_localized_attribute($1, args.first, options) || read_localized_attribute($1, HasLocalizationTable.primary_locale, options)
|
|
42
|
-
|
|
48
|
+
elsif match[:suffix] == '='
|
|
43
49
|
raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" unless args.size == 1
|
|
44
50
|
return write_localized_attribute($1, args.first)
|
|
51
|
+
elsif current_localization.respond_to?(name).inspect
|
|
52
|
+
return localized_attribute_changed?(name.to_s.sub(/_changed\?/, ''))
|
|
45
53
|
end
|
|
46
54
|
end
|
|
47
55
|
end
|
|
48
|
-
|
|
56
|
+
|
|
49
57
|
super
|
|
50
58
|
end
|
|
51
|
-
|
|
59
|
+
|
|
52
60
|
def respond_to?(*args)
|
|
53
|
-
|
|
61
|
+
match = args.first.to_s.match(LOCALIZED_ATTRIBUTE_REGEX)
|
|
62
|
+
return true if match && localized_attributes.include?(match[:name].to_sym)
|
|
54
63
|
super
|
|
55
64
|
end
|
|
56
|
-
|
|
65
|
+
|
|
66
|
+
def reset_localized_attribute_cache
|
|
67
|
+
localized_attribute_cache.reset
|
|
68
|
+
end
|
|
69
|
+
|
|
57
70
|
private
|
|
58
71
|
|
|
59
|
-
def
|
|
60
|
-
@localization_attribute_cache ||=
|
|
72
|
+
def localized_attribute_cache
|
|
73
|
+
@localization_attribute_cache ||= Cache.new(self)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def localized_attribute_changed?(attr)
|
|
77
|
+
current_localization.send("#{attr}_changed?")
|
|
61
78
|
end
|
|
62
79
|
end
|
|
63
80
|
end
|
|
64
|
-
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module HasLocalizationTable
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
module Attributes
|
|
4
|
+
class Cache < Hash
|
|
5
|
+
attr_reader :klass
|
|
6
|
+
|
|
7
|
+
def initialize(klass)
|
|
8
|
+
@klass = klass
|
|
9
|
+
reset
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def get(attr, locale)
|
|
13
|
+
clear(attr, locale) if changed?(attr, locale)
|
|
14
|
+
self[attr.to_sym][locale.id] ||= yield
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def set(attr, locale, value)
|
|
18
|
+
self[attr.to_sym][locale.id] = value
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def clear(attr, locale)
|
|
22
|
+
self[attr.to_sym].delete(locale.id)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def reset
|
|
26
|
+
replace(klass.localized_attributes.inject({}) { |memo, attr| memo[attr] = {}; memo })
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def changed?(attr, locale)
|
|
30
|
+
klass.localization_for(locale).send(attr) != self[attr.to_sym][locale.id]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -1,16 +1,7 @@
|
|
|
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
|
-
|
|
8
4
|
def setup_localization_callbacks!
|
|
9
|
-
# Initialize string records after main record initialization
|
|
10
|
-
after_initialize(if: :add_localization_after_initialize?) do
|
|
11
|
-
build_missing_localizations!
|
|
12
|
-
end
|
|
13
|
-
|
|
14
5
|
before_validation do
|
|
15
6
|
reject_empty_localizations!
|
|
16
7
|
build_missing_localizations!
|
|
@@ -23,14 +14,6 @@ module HasLocalizationTable
|
|
|
23
14
|
end
|
|
24
15
|
end
|
|
25
16
|
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
|
|
34
17
|
end
|
|
35
18
|
end
|
|
36
19
|
end
|
|
@@ -38,8 +38,11 @@ module HasLocalizationTable
|
|
|
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
|
-
|
|
42
|
-
|
|
41
|
+
send(localization_association_name)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def localization_association_name
|
|
45
|
+
localization_table_options[:association_name]
|
|
43
46
|
end
|
|
44
47
|
|
|
45
48
|
def localized_attributes
|
|
@@ -49,6 +52,14 @@ module HasLocalizationTable
|
|
|
49
52
|
def localization_table_options
|
|
50
53
|
self.class.localization_table_options
|
|
51
54
|
end
|
|
55
|
+
|
|
56
|
+
def localization_for(locale)
|
|
57
|
+
localization_association.detect{ |a| a.send(HasLocalizationTable.locale_foreign_key) == locale.id }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def current_localization
|
|
61
|
+
localization_for(HasLocalizationTable.current_locale)
|
|
62
|
+
end
|
|
52
63
|
end
|
|
53
64
|
end
|
|
54
65
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module HasLocalizationTable
|
|
2
2
|
module ActiveRecord
|
|
3
3
|
module Relation
|
|
4
|
-
RESERVED_KEYS = [:association_name, :required, :optional, :dependent, :has_one, :
|
|
4
|
+
RESERVED_KEYS = [:association_name, :required, :optional, :dependent, :has_one, :include, :build_missing]
|
|
5
5
|
|
|
6
6
|
def self.extended(klass)
|
|
7
7
|
klass.send(:include, InstanceMethods)
|
|
@@ -40,7 +40,7 @@ module HasLocalizationTable
|
|
|
40
40
|
association_name = :localization if localized_attributes.include?(association_name)
|
|
41
41
|
|
|
42
42
|
has_one_options = localization_table_options.except(*RESERVED_KEYS).
|
|
43
|
-
merge(
|
|
43
|
+
merge(conditions: -> { "#{table_name}.#{foreign_key} = #{HasLocalizationTable.current_locale.id}" })
|
|
44
44
|
|
|
45
45
|
self.has_one association_name, has_one_options
|
|
46
46
|
self.has_one(:localization, has_one_options) unless association_name == :localization
|
|
@@ -58,6 +58,18 @@ module HasLocalizationTable
|
|
|
58
58
|
if localization_table_options.fetch(:include, false)
|
|
59
59
|
self.default_scope -> { includes(localization_association_name) }
|
|
60
60
|
end
|
|
61
|
+
|
|
62
|
+
override_association_getter
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def override_association_getter(name = localization_association_name)
|
|
66
|
+
# Update the association getter to build missing localizations
|
|
67
|
+
# This works better than an after_initialize because it allows for strings to not be loaded
|
|
68
|
+
# until they are used, and also repopulates if necessary
|
|
69
|
+
define_method(name) do |build_missing = localization_table_options.fetch(:build_missing, true), force_reload = false|
|
|
70
|
+
build_missing_localizations! if build_missing
|
|
71
|
+
super(force_reload)
|
|
72
|
+
end
|
|
61
73
|
end
|
|
62
74
|
|
|
63
75
|
public
|
|
@@ -68,13 +80,15 @@ module HasLocalizationTable
|
|
|
68
80
|
return unless HasLocalizationTable.all_locales.any?
|
|
69
81
|
|
|
70
82
|
locale_ids = HasLocalizationTable.all_locales.map(&:id)
|
|
83
|
+
assoc = association(localization_association_name).reader
|
|
84
|
+
|
|
71
85
|
HasLocalizationTable.all_locales.each do |locale|
|
|
72
|
-
unless
|
|
73
|
-
|
|
86
|
+
unless assoc.detect{ |record| record.send(HasLocalizationTable.locale_foreign_key) == locale.id }
|
|
87
|
+
assoc.build(HasLocalizationTable.locale_foreign_key => locale.id)
|
|
74
88
|
end
|
|
75
|
-
|
|
76
|
-
localization_association.sort_by!{ |l| locale_ids.index(l.send(HasLocalizationTable.locale_foreign_key)) || 0 }
|
|
77
89
|
end
|
|
90
|
+
|
|
91
|
+
assoc.sort_by!{ |l| locale_ids.index(l.send(HasLocalizationTable.locale_foreign_key)) || 0 }
|
|
78
92
|
end
|
|
79
93
|
|
|
80
94
|
# Remove localization objects that are not filled in
|
|
@@ -4,7 +4,7 @@ describe HasLocalizationTable do
|
|
|
4
4
|
before do
|
|
5
5
|
# Configure HLT
|
|
6
6
|
HasLocalizationTable.configure do |c|
|
|
7
|
-
c.primary_locale = Locale.first
|
|
7
|
+
c.primary_locale = Locale.first
|
|
8
8
|
c.current_locale = Locale.first
|
|
9
9
|
c.all_locales = -> { Locale.all }
|
|
10
10
|
end
|
|
@@ -15,17 +15,17 @@ describe HasLocalizationTable do
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
let(:a) { Article.new(name: "Test", description: "Description") }
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
it "should set localized attributes" do
|
|
20
20
|
a.localizations.first.name.must_equal "Test"
|
|
21
21
|
a.localizations.first.description.must_equal "Description"
|
|
22
22
|
end
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
it "should create accessor methods" do
|
|
25
25
|
a.name.must_equal "Test"
|
|
26
26
|
a.description.must_equal "Description"
|
|
27
27
|
end
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
it "should save localized attributes" do
|
|
30
30
|
a.save!
|
|
31
31
|
a.reload
|
|
@@ -38,7 +38,7 @@ describe HasLocalizationTable do
|
|
|
38
38
|
a.update_attributes!(name: "Test 2")
|
|
39
39
|
Article.find(a.id).name.must_equal "Test 2"
|
|
40
40
|
end
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
it "should create mutator methods" do
|
|
43
43
|
a.name = "Changed"
|
|
44
44
|
a.description = "Changed Description"
|
|
@@ -47,31 +47,31 @@ describe HasLocalizationTable do
|
|
|
47
47
|
a.localizations.first.name.must_equal "Changed"
|
|
48
48
|
a.localizations.first.description.must_equal "Changed Description"
|
|
49
49
|
end
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
it "should use the current locale when setting" do
|
|
52
52
|
a
|
|
53
53
|
|
|
54
54
|
HasLocalizationTable.configure do |c|
|
|
55
55
|
c.current_locale = Locale.last
|
|
56
56
|
end
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
a.name = "French Name"
|
|
59
59
|
a.description = "French Description"
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
eng = a.localizations.detect{ |s| s.locale_id == Locale.first.id }
|
|
62
62
|
fre = a.localizations.detect{ |s| s.locale_id == Locale.last.id }
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
eng.name.must_equal "Test"
|
|
65
65
|
eng.description.must_equal "Description"
|
|
66
66
|
fre.name.must_equal "French Name"
|
|
67
67
|
fre.description.must_equal "French Description"
|
|
68
68
|
end
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
it "should return the correct value when the current locale changes" do
|
|
71
71
|
Locale.class_eval { cattr_accessor :current }
|
|
72
72
|
eng = Locale.find_by_name("English")
|
|
73
73
|
fre = Locale.find_by_name("French")
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
HasLocalizationTable.configure do |c|
|
|
76
76
|
c.current_locale = ->{ Locale.current }
|
|
77
77
|
end
|
|
@@ -79,58 +79,58 @@ describe HasLocalizationTable do
|
|
|
79
79
|
Locale.current = eng
|
|
80
80
|
a.name = "English Name"
|
|
81
81
|
a.description = "English Description"
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
Locale.current = fre
|
|
84
84
|
a.name = "French Name"
|
|
85
85
|
a.description = "French Description"
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
Locale.current = eng
|
|
88
88
|
a.name.must_equal "English Name"
|
|
89
89
|
a.description.must_equal "English Description"
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
Locale.current = fre
|
|
92
92
|
a.name.must_equal "French Name"
|
|
93
93
|
a.description.must_equal "French Description"
|
|
94
94
|
end
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
it "should return the correct locale's value even if the cache is empty" do
|
|
97
97
|
Locale.class_eval { cattr_accessor :current }
|
|
98
|
-
Locale.current =
|
|
98
|
+
Locale.current = Locale.find_by_name("English")
|
|
99
99
|
fre = Locale.find_by_name("French")
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
HasLocalizationTable.configure do |c|
|
|
102
102
|
c.current_locale = ->{ Locale.current }
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
a.localizations.last.attributes = { name: "French Name", description: "French Description" }
|
|
106
|
-
|
|
107
|
-
# Force empty cache
|
|
108
|
-
a.
|
|
106
|
+
|
|
107
|
+
# Force empty cache
|
|
108
|
+
a.reset_localized_attribute_cache
|
|
109
109
|
|
|
110
110
|
Locale.current = fre
|
|
111
111
|
a.name.must_equal "French Name"
|
|
112
112
|
a.description.must_equal "French Description"
|
|
113
113
|
end
|
|
114
|
-
|
|
114
|
+
|
|
115
115
|
it "should return the correct locale's value even if a language was added" do
|
|
116
116
|
Locale.class_eval { cattr_accessor :current }
|
|
117
117
|
Locale.current = eng = Locale.find_by_name("English")
|
|
118
118
|
fre = Locale.find_by_name("French")
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
HasLocalizationTable.configure do |c|
|
|
121
121
|
c.current_locale = ->{ Locale.current }
|
|
122
122
|
c.all_locales = [eng]
|
|
123
123
|
end
|
|
124
|
-
|
|
124
|
+
|
|
125
125
|
Object.send(:remove_const, :Article) rescue nil
|
|
126
126
|
Article = Class.new(ActiveRecord::Base)
|
|
127
127
|
Article.has_localization_table
|
|
128
|
-
|
|
128
|
+
|
|
129
129
|
aa = Article.create!(name: "Name", description: "Description")
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
ArticleLocalization.create!(article: aa, locale: fre, name: "French Name", description: "French Description")
|
|
131
|
+
|
|
132
132
|
aa.reload
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
Locale.current = fre
|
|
135
135
|
aa.name.must_equal "French Name"
|
|
136
136
|
aa.description.must_equal "French Description"
|
|
@@ -219,4 +219,84 @@ describe HasLocalizationTable do
|
|
|
219
219
|
end
|
|
220
220
|
end
|
|
221
221
|
end
|
|
222
|
-
|
|
222
|
+
|
|
223
|
+
it 'should build missing localizations when accessing the association' do
|
|
224
|
+
HasLocalizationTable.config.all_locales = [Locale.first]
|
|
225
|
+
|
|
226
|
+
a = Article.new
|
|
227
|
+
a.localizations.size.must_equal 1
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it 'should build missing localizations when there is more than 1 locale' do
|
|
231
|
+
a = Article.new
|
|
232
|
+
a.localizations.size.must_equal 2
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it 'should not build localizations when they already exist' do
|
|
236
|
+
a = Article.new
|
|
237
|
+
l1 = ArticleLocalization.new(locale_id: Locale.first.id, name: 'Name')
|
|
238
|
+
l2 = ArticleLocalization.new(locale_id: Locale.last.id, name: 'Nom')
|
|
239
|
+
a.localizations = [l1, l2]
|
|
240
|
+
a.localizations.must_equal [l1, l2]
|
|
241
|
+
a.localizations.first.name.must_equal 'Name'
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it 'should add missing localizations if some exist' do
|
|
245
|
+
a = Article.new
|
|
246
|
+
a.localizations = [ArticleLocalization.new(locale_id: Locale.first.id, name: 'Name')]
|
|
247
|
+
a.association(:localizations).reader.size.must_equal 1
|
|
248
|
+
a.localizations.size.must_equal 2
|
|
249
|
+
a.localizations.first.name.must_equal 'Name'
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it 'should not build missing localizations if asked not to' do
|
|
253
|
+
a = Article.new
|
|
254
|
+
a.localizations(false).must_be_empty
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it 'should not build missing localizations if the options disable it' do
|
|
258
|
+
Article.has_localization_table build_missing: false
|
|
259
|
+
a = Article.new
|
|
260
|
+
a.localizations.must_be_empty
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
it 'should build missing localizations if the options disable it but the method requests it' do
|
|
264
|
+
Article.has_localization_table build_missing: false
|
|
265
|
+
a = Article.new
|
|
266
|
+
a.localizations(true).wont_be_empty
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
it 'should update the main model when the string is directly updated' do
|
|
270
|
+
Article.has_localization_table
|
|
271
|
+
a = Article.new
|
|
272
|
+
|
|
273
|
+
string = a.localizations.first
|
|
274
|
+
string.name = 'New Name'
|
|
275
|
+
a.name.must_equal 'New Name'
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
it 'should allow successive changes' do
|
|
279
|
+
Article.has_localization_table
|
|
280
|
+
a = Article.new
|
|
281
|
+
|
|
282
|
+
string = a.localizations.first
|
|
283
|
+
string.name = 'New Name'
|
|
284
|
+
a.name.must_equal 'New Name'
|
|
285
|
+
|
|
286
|
+
string.name = 'Another Name'
|
|
287
|
+
a.name.must_equal 'Another Name'
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
it 'should report if the attribute changed' do
|
|
291
|
+
Article.has_localization_table
|
|
292
|
+
a = Article.create!(name: 'Name')
|
|
293
|
+
a.name = 'New Name'
|
|
294
|
+
assert a.name_changed?
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
it 'should not report that the attribute has changed if it has not' do
|
|
298
|
+
Article.has_localization_table
|
|
299
|
+
a = Article.create!(name: 'Name')
|
|
300
|
+
refute a.name_changed?
|
|
301
|
+
end
|
|
302
|
+
end
|
|
@@ -16,34 +16,6 @@ describe HasLocalizationTable do
|
|
|
16
16
|
|
|
17
17
|
let(:article) { Article.create!(name: "Test", description: "Description") }
|
|
18
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
19
|
it 'should load associations if include: true is given' do
|
|
48
20
|
Article.has_localization_table include: true
|
|
49
21
|
assert Article.find(article.id).localizations.loaded?
|
data/spec/support/setup.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
|
3
3
|
ActiveRecord::Migration.tap do |m|
|
|
4
4
|
m.create_table :articles do |t|
|
|
5
|
-
t.timestamps
|
|
5
|
+
t.timestamps null: false
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
m.create_table :locales do |t|
|
|
@@ -25,4 +25,4 @@ Locale.create!(name: "French")
|
|
|
25
25
|
ArticleLocalization = Class.new(ActiveRecord::Base) do
|
|
26
26
|
belongs_to :article
|
|
27
27
|
belongs_to :locale
|
|
28
|
-
end
|
|
28
|
+
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.
|
|
4
|
+
version: 0.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Vandersluis
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-
|
|
11
|
+
date: 2016-04-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
type: :runtime
|
|
@@ -16,28 +16,28 @@ dependencies:
|
|
|
16
16
|
name: activesupport
|
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
|
18
18
|
requirements:
|
|
19
|
-
- -
|
|
19
|
+
- - ~>
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
|
-
version: 3.0
|
|
21
|
+
version: '3.0'
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- -
|
|
24
|
+
- - ~>
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 3.0
|
|
26
|
+
version: '3.0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
type: :runtime
|
|
29
29
|
prerelease: false
|
|
30
30
|
name: activerecord
|
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
|
32
32
|
requirements:
|
|
33
|
-
- -
|
|
33
|
+
- - ~>
|
|
34
34
|
- !ruby/object:Gem::Version
|
|
35
|
-
version: 3.0
|
|
35
|
+
version: '3.0'
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- -
|
|
38
|
+
- - ~>
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: 3.0
|
|
40
|
+
version: '3.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
type: :development
|
|
43
43
|
prerelease: false
|
|
@@ -89,6 +89,8 @@ extensions: []
|
|
|
89
89
|
extra_rdoc_files: []
|
|
90
90
|
files:
|
|
91
91
|
- .gitignore
|
|
92
|
+
- .rspec
|
|
93
|
+
- .travis.yml
|
|
92
94
|
- Gemfile
|
|
93
95
|
- LICENSE
|
|
94
96
|
- README.md
|
|
@@ -97,6 +99,7 @@ files:
|
|
|
97
99
|
- lib/has_localization_table.rb
|
|
98
100
|
- lib/has_localization_table/active_record.rb
|
|
99
101
|
- lib/has_localization_table/active_record/attributes.rb
|
|
102
|
+
- lib/has_localization_table/active_record/attributes/cache.rb
|
|
100
103
|
- lib/has_localization_table/active_record/callbacks.rb
|
|
101
104
|
- lib/has_localization_table/active_record/finder_methods.rb
|
|
102
105
|
- lib/has_localization_table/active_record/meta_methods.rb
|