multilang-hstore 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +134 -0
- data/lib/multilang-hstore/active_record_extensions.rb +114 -0
- data/lib/multilang-hstore/translation_keeper.rb +103 -0
- data/lib/multilang-hstore/translation_proxy.rb +22 -0
- data/lib/multilang-hstore/version.rb +3 -0
- data/lib/multilang-hstore.rb +7 -0
- data/spec/multilang_spec.rb +258 -0
- data/spec/schema.rb +19 -0
- data/spec/spec_helper.rb +63 -0
- metadata +59 -0
data/README.rdoc
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
== Multilang-hstore
|
2
|
+
|
3
|
+
Multilang is a small translation library for translating database values for Rails 3 using the [Hstore datatype](http://www.postgresql.org/docs/9.0/static/hstore.html).
|
4
|
+
|
5
|
+
This project is a fork of [artworklv/multilang](https://github.com/artworklv/multilang) with some remarkable differences:
|
6
|
+
|
7
|
+
* Replaced YAML text fields in favor of Hstore fields.
|
8
|
+
* The translation hash is no longer limited to locales in `I18n.available_locales`.
|
9
|
+
|
10
|
+
It uses [engageis/activerecord-postgres-hstore](https://github.com/engageis/activerecord-postgres-hstore)
|
11
|
+
|
12
|
+
== Installation
|
13
|
+
|
14
|
+
You need configure the multilang gem inside your gemfile:
|
15
|
+
|
16
|
+
gem 'multilang-hstore'
|
17
|
+
|
18
|
+
Do not forget to run
|
19
|
+
|
20
|
+
bundle install
|
21
|
+
|
22
|
+
|
23
|
+
== Basic Usage
|
24
|
+
|
25
|
+
This is a walkthrough with all steps you need to setup multilang translated attributes, including model and migration.
|
26
|
+
|
27
|
+
We're assuming here you want a Post model with some multilang attributes, as outlined below:
|
28
|
+
|
29
|
+
class Post < ActiveRecord::Base
|
30
|
+
multilang :title, :accessible => true
|
31
|
+
end
|
32
|
+
|
33
|
+
or
|
34
|
+
|
35
|
+
class Post < ActiveRecord::Base
|
36
|
+
multilang :title, :description, :required => true, :length => 100, :accessible => true
|
37
|
+
end
|
38
|
+
|
39
|
+
The multilang translations are stored in the same model attributes (eg. title):
|
40
|
+
|
41
|
+
You may need to create migration for Post as usual, but multilang attributes should be in hstore type:
|
42
|
+
|
43
|
+
create_table(:posts) do |t|
|
44
|
+
t.hstore :title
|
45
|
+
t.timestamps
|
46
|
+
end
|
47
|
+
|
48
|
+
Thats it!
|
49
|
+
|
50
|
+
Now you are able to translate values for the attributes :title and :description per locale:
|
51
|
+
|
52
|
+
I18n.locale = :en
|
53
|
+
post.title = 'Multilang rocks!'
|
54
|
+
I18n.locale = :lv
|
55
|
+
post.title = 'Multilang rulle!'
|
56
|
+
|
57
|
+
I18n.locale = :en
|
58
|
+
post.title #=> Multilang rocks!
|
59
|
+
I18n.locale = :lv
|
60
|
+
post.title #=> Multilang rulle!
|
61
|
+
|
62
|
+
|
63
|
+
You may assign attributes through auto generated methods (this methods depend from I18n.available_locales):
|
64
|
+
|
65
|
+
I18n.available_locales #=> [:en. :lv]
|
66
|
+
|
67
|
+
post.title_en = 'Multilang rocks!'
|
68
|
+
post.title_lv = 'Multilang rulle!'
|
69
|
+
|
70
|
+
post.title_en #=> 'Multilang rocks!'
|
71
|
+
post.title_lv #=> 'Multilang rulle!'
|
72
|
+
|
73
|
+
You may use mass assignment on model creation (if :accessible param is defined):
|
74
|
+
|
75
|
+
Post.new(:title => {:en => 'Multilang rocks!', :lv => 'Multilang rulle!'})
|
76
|
+
|
77
|
+
or
|
78
|
+
|
79
|
+
Post.new(:title_en => 'Multilang rocks!', :title_lv => 'Multilang rulle!')
|
80
|
+
|
81
|
+
Also, you may ise same hashes with setters:
|
82
|
+
|
83
|
+
post.title = {:en => 'Multilang rocks!', :lv => 'Multilang rulle!'}
|
84
|
+
|
85
|
+
== Attribute methods
|
86
|
+
|
87
|
+
You may get other translations via attribute translation method:
|
88
|
+
|
89
|
+
post.title.translation[:lv] #=> 'Multilang rocks!'
|
90
|
+
post.title.translation[:en] #=> 'Multilang rulle!'
|
91
|
+
post.title.translation.locales #=> [:en, :lv]
|
92
|
+
|
93
|
+
If you have incomplete translations, you can get translation from other locale:
|
94
|
+
|
95
|
+
post.title = {:en => 'Multilang rocks!', :lv => ''}
|
96
|
+
I18n.locale = :lv
|
97
|
+
post.title.any #=> 'Multilang rocks!'
|
98
|
+
|
99
|
+
The value from "any" method returns value for I18n.current_locale or, if value is empty, it searches through all locales. It takes searching order from I18n.available_locales array.
|
100
|
+
|
101
|
+
== Validations
|
102
|
+
Multilang has some validation features:
|
103
|
+
|
104
|
+
multilang :title, :length => 100 #define maximal length validator
|
105
|
+
multilang :title, :required => true #define requirement validator
|
106
|
+
multilang :title, :format => /regexp/ #define validates_format_of validator
|
107
|
+
|
108
|
+
== Tests
|
109
|
+
|
110
|
+
Test runs using a temporary database in your local PostgreSQL server:
|
111
|
+
|
112
|
+
Create a test database:
|
113
|
+
|
114
|
+
$ createdb multilang-hstore-test
|
115
|
+
|
116
|
+
Create the [hstore extension](http://www.postgresql.org/docs/9.1/static/sql-createextension.html):
|
117
|
+
psql -d multilang-hstore-test -c "CREATE EXTENSION IF NOT EXISTS hstore"
|
118
|
+
|
119
|
+
Create the role *postgres* if necessary:
|
120
|
+
|
121
|
+
$ createuser -s -r postgres
|
122
|
+
|
123
|
+
Finally, you can run your tests:
|
124
|
+
|
125
|
+
rspec
|
126
|
+
|
127
|
+
== Bugs and Feedback
|
128
|
+
|
129
|
+
Use [http://github.com/artworklv/multilang/issues](http://github.com/artworklv/multilang/issues)
|
130
|
+
|
131
|
+
== License(MIT)
|
132
|
+
|
133
|
+
Copyright (c) 2010 Arthur Meinart
|
134
|
+
Copyright (c) 2012 Firebase.co
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Multilang
|
2
|
+
module ActiveRecordExtensions
|
3
|
+
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
def multilang_accessible_translations
|
7
|
+
class_variable_get(:@@multilang_accessible_translations)
|
8
|
+
end
|
9
|
+
|
10
|
+
def multilang(*args)
|
11
|
+
|
12
|
+
options = {
|
13
|
+
:required => false,
|
14
|
+
:length => nil,
|
15
|
+
:accessible => false,
|
16
|
+
:format => nil
|
17
|
+
}.merge(args.extract_options!)
|
18
|
+
|
19
|
+
options.assert_valid_keys([:required, :length, :accessible, :format, :nil])
|
20
|
+
|
21
|
+
define_translation_base! unless included_modules.include?(InstanceMethods)
|
22
|
+
|
23
|
+
args.each do |attribute|
|
24
|
+
|
25
|
+
define_method attribute do
|
26
|
+
multilang_translation_keeper(attribute).value
|
27
|
+
end
|
28
|
+
|
29
|
+
define_method "#{attribute}=" do |value|
|
30
|
+
multilang_translation_keeper(attribute).update(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
#attribute accessibility for mass assignment
|
34
|
+
if options[:accessible]
|
35
|
+
matr = multilang_accessible_translations + [attribute.to_sym]
|
36
|
+
class_variable_set(:@@multilang_accessible_translations, matr)
|
37
|
+
end
|
38
|
+
|
39
|
+
module_eval do
|
40
|
+
serialize "#{attribute}", ActiveRecord::Coders::Hstore
|
41
|
+
end
|
42
|
+
|
43
|
+
I18n.available_locales.each do |locale|
|
44
|
+
|
45
|
+
define_method "#{attribute}_#{locale}" do
|
46
|
+
multilang_translation_keeper(attribute)[locale]
|
47
|
+
end
|
48
|
+
|
49
|
+
define_method "#{attribute}_#{locale}=" do |value|
|
50
|
+
multilang_translation_keeper(attribute)[locale] = value
|
51
|
+
end
|
52
|
+
|
53
|
+
# locale based attribute accessibility for mass assignment
|
54
|
+
if options[:accessible]
|
55
|
+
matr = multilang_accessible_translations + ["#{attribute}_#{locale}".to_sym]
|
56
|
+
class_variable_set(:@@multilang_accessible_translations, matr)
|
57
|
+
end
|
58
|
+
|
59
|
+
# attribute presence validator
|
60
|
+
if options[:required]
|
61
|
+
module_eval do
|
62
|
+
validates_presence_of "#{attribute}_#{locale}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
#attribute maximal length validator
|
67
|
+
if options[:length]
|
68
|
+
module_eval do
|
69
|
+
validates_length_of "#{attribute}_#{locale}", :maximum => options[:length]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
#attribute format validator
|
74
|
+
if options[:format]
|
75
|
+
module_eval do
|
76
|
+
validates_format_of "#{attribute}_#{locale}", :with => options[:format]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def define_translation_base!
|
87
|
+
include InstanceMethods
|
88
|
+
|
89
|
+
define_method "multilang_translation_keeper" do |attribute|
|
90
|
+
unless instance_variable_defined?("@multilang_attribute_#{attribute}")
|
91
|
+
instance_variable_set("@multilang_attribute_#{attribute}", MultilangTranslationKeeper.new(self, attribute))
|
92
|
+
end
|
93
|
+
instance_variable_get "@multilang_attribute_#{attribute}"
|
94
|
+
end
|
95
|
+
|
96
|
+
unless class_variable_defined?(:@@multilang_accessible_translations)
|
97
|
+
class_variable_set(:@@multilang_accessible_translations, [])
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
module InstanceMethods
|
105
|
+
def mass_assignment_authorizer(role = :default)
|
106
|
+
super(role) + (self.class.multilang_accessible_translations || [])
|
107
|
+
end
|
108
|
+
end #module InstanceMethods
|
109
|
+
|
110
|
+
end #module ActiveRecordExtensions
|
111
|
+
end ##module Multilang
|
112
|
+
|
113
|
+
ActiveRecord::Base.extend Multilang::ActiveRecordExtensions::ClassMethods
|
114
|
+
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Multilang
|
2
|
+
|
3
|
+
class MultilangTranslationKeeper
|
4
|
+
attr_reader :model
|
5
|
+
attr_reader :attribute
|
6
|
+
attr_reader :translations
|
7
|
+
|
8
|
+
def initialize(model, attribute)
|
9
|
+
@model = model
|
10
|
+
@attribute = attribute
|
11
|
+
@translations = {}
|
12
|
+
load!
|
13
|
+
end
|
14
|
+
|
15
|
+
def value(locale = nil)
|
16
|
+
locale ||= actual_locale
|
17
|
+
read(locale)
|
18
|
+
end
|
19
|
+
|
20
|
+
def current_or_any_value
|
21
|
+
v = value
|
22
|
+
if v.empty?
|
23
|
+
reduced_locales = locales - [actual_locale]
|
24
|
+
reduced_locales.each do |locale|
|
25
|
+
v = value(locale)
|
26
|
+
return v unless v.empty?
|
27
|
+
end
|
28
|
+
else
|
29
|
+
return v
|
30
|
+
end
|
31
|
+
return ''
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
raw_read(actual_locale)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_str(locale = nil)
|
39
|
+
locale ||= actual_locale
|
40
|
+
raw_read(locale)
|
41
|
+
end
|
42
|
+
|
43
|
+
def update(value)
|
44
|
+
if value.is_a?(Hash)
|
45
|
+
clear
|
46
|
+
value.each{|k, v| write(k, v)}
|
47
|
+
elsif value.is_a?(String)
|
48
|
+
write(actual_locale, value)
|
49
|
+
end
|
50
|
+
flush!
|
51
|
+
end
|
52
|
+
|
53
|
+
def [](locale)
|
54
|
+
read(locale)
|
55
|
+
end
|
56
|
+
|
57
|
+
def []=(locale, value)
|
58
|
+
write(locale, value)
|
59
|
+
flush!
|
60
|
+
end
|
61
|
+
|
62
|
+
def locales
|
63
|
+
@translations.keys.map(&:to_sym)
|
64
|
+
end
|
65
|
+
|
66
|
+
def empty?
|
67
|
+
@translations.empty?
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def actual_locale
|
73
|
+
I18n.locale
|
74
|
+
end
|
75
|
+
|
76
|
+
def write(locale, value)
|
77
|
+
@translations[locale.to_s] = value
|
78
|
+
end
|
79
|
+
|
80
|
+
def read(locale)
|
81
|
+
MultilangTranslationProxy.new(self, locale)
|
82
|
+
end
|
83
|
+
|
84
|
+
def raw_read(locale)
|
85
|
+
@translations[locale.to_s] || ''
|
86
|
+
end
|
87
|
+
|
88
|
+
def clear
|
89
|
+
@translations.clear
|
90
|
+
end
|
91
|
+
|
92
|
+
def load!
|
93
|
+
data = @model[@attribute]
|
94
|
+
data = data.blank? ? nil : data
|
95
|
+
@translations = data.is_a?(Hash) ? data : {}
|
96
|
+
end
|
97
|
+
|
98
|
+
def flush!
|
99
|
+
@model[@attribute] = @translations
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Multilang
|
2
|
+
class MultilangTranslationProxy < String
|
3
|
+
attr_reader :multilang_keeper
|
4
|
+
|
5
|
+
def initialize(multi_keeper, locale)
|
6
|
+
@multilang_keeper = multi_keeper
|
7
|
+
super(@multilang_keeper.to_str(locale))
|
8
|
+
end
|
9
|
+
|
10
|
+
def translation
|
11
|
+
@multilang_keeper
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
String.new(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
def any
|
19
|
+
@multilang_keeper.current_or_any_value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,258 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
$KCODE = "U"
|
3
|
+
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
5
|
+
|
6
|
+
describe Multilang do
|
7
|
+
before :each do
|
8
|
+
setup_db
|
9
|
+
I18n.locale = :lv
|
10
|
+
end
|
11
|
+
|
12
|
+
after :each do
|
13
|
+
teardown_db
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should test database connection" do
|
17
|
+
AbstractPost.create
|
18
|
+
AbstractPost.count.should == 1
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should add getters/setters in RegularPost" do
|
22
|
+
regular_post = RegularPost.new
|
23
|
+
%w(title body).each do |attr|
|
24
|
+
regular_post.should respond_to(attr)
|
25
|
+
regular_post.should respond_to("#{attr}=")
|
26
|
+
I18n.available_locales.each do |loc|
|
27
|
+
regular_post.should respond_to("#{attr}_#{loc}")
|
28
|
+
regular_post.should respond_to("#{attr}_#{loc}=")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should set attributes in RegularPost" do
|
34
|
+
rp = RegularPost.new
|
35
|
+
|
36
|
+
# set
|
37
|
+
rp.title = "Latviešu nosaukums"
|
38
|
+
rp.body = "Latviešu apraksts"
|
39
|
+
I18n.locale = :ru
|
40
|
+
rp.title = "Русский заголовок"
|
41
|
+
rp.body = "Русский текст"
|
42
|
+
|
43
|
+
# test
|
44
|
+
I18n.locale = :lv
|
45
|
+
rp.title.should == "Latviešu nosaukums"
|
46
|
+
rp.body.should == "Latviešu apraksts"
|
47
|
+
|
48
|
+
I18n.locale = :ru
|
49
|
+
rp.title.should == "Русский заголовок"
|
50
|
+
rp.body.should == "Русский текст"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should set attributes through alternative setters in RegularPost" do
|
54
|
+
rp = RegularPost.new
|
55
|
+
|
56
|
+
# set
|
57
|
+
rp.title_lv = "Latviešu nosaukums"
|
58
|
+
rp.body_lv = "Latviešu apraksts"
|
59
|
+
rp.title_ru = "Русский заголовок"
|
60
|
+
rp.body_ru = "Русский текст"
|
61
|
+
|
62
|
+
# test
|
63
|
+
rp.title_lv.should == "Latviešu nosaukums"
|
64
|
+
rp.body_lv.should == "Latviešu apraksts"
|
65
|
+
rp.title_ru.should == "Русский заголовок"
|
66
|
+
rp.body_ru.should == "Русский текст"
|
67
|
+
|
68
|
+
I18n.locale = :lv
|
69
|
+
rp.title.should == "Latviešu nosaukums"
|
70
|
+
rp.body.should == "Latviešu apraksts"
|
71
|
+
|
72
|
+
I18n.locale = :ru
|
73
|
+
rp.title.should == "Русский заголовок"
|
74
|
+
rp.body.should == "Русский текст"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should set attributes through fullset hash in RegularPost" do
|
78
|
+
rp = RegularPost.new
|
79
|
+
|
80
|
+
# set
|
81
|
+
rp.title = {:lv => "Latviešu nosaukums", :ru => "Русский заголовок"}
|
82
|
+
rp.body = {:lv => "Latviešu apraksts", :ru => "Русский текст"}
|
83
|
+
|
84
|
+
# test
|
85
|
+
rp.title_lv.should == "Latviešu nosaukums"
|
86
|
+
rp.body_lv.should == "Latviešu apraksts"
|
87
|
+
rp.title_ru.should == "Русский заголовок"
|
88
|
+
rp.body_ru.should == "Русский текст"
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should set attributes through halfset hash in RegularPost" do
|
92
|
+
rp = RegularPost.new
|
93
|
+
|
94
|
+
# set
|
95
|
+
rp.title = {:lv => "Latviešu nosaukums"}
|
96
|
+
rp.body = {:lv => "Latviešu apraksts"}
|
97
|
+
|
98
|
+
# test
|
99
|
+
rp.title_lv.should == "Latviešu nosaukums"
|
100
|
+
rp.body_lv.should == "Latviešu apraksts"
|
101
|
+
rp.title_ru.should == ""
|
102
|
+
rp.body_ru.should == ""
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should be validated in RegularPost" do
|
106
|
+
rp = RegularPost.new
|
107
|
+
|
108
|
+
rp.title = "Latviešu nosaukums"
|
109
|
+
rp.body = "Latviešu apraksts"
|
110
|
+
I18n.locale = :ru
|
111
|
+
rp.title = "Русский заголовок"
|
112
|
+
rp.body = "Русский текст"
|
113
|
+
|
114
|
+
rp.should be_valid
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should not be validated in RegularPost" do
|
118
|
+
rp = RegularPost.new
|
119
|
+
|
120
|
+
rp.title_lv = "Latviešu nosaukums"*100 #too long
|
121
|
+
rp.body_lv = "" #empty
|
122
|
+
rp.title_ru = "" #empty
|
123
|
+
rp.body_ru = "Русский текст"*1000 #too long
|
124
|
+
|
125
|
+
rp.valid?
|
126
|
+
|
127
|
+
rp.should have(4).errors
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should mass assign attributes in RegularPost" do
|
131
|
+
rp = RegularPost.new( :title_lv => "Latviešu nosaukums",
|
132
|
+
:title_ru => "Русский заголовок",
|
133
|
+
:body_lv => "Latviešu apraksts",
|
134
|
+
:body_ru => "Русский текст" )
|
135
|
+
|
136
|
+
# test
|
137
|
+
rp.title_lv.should == "Latviešu nosaukums"
|
138
|
+
rp.body_lv.should == "Latviešu apraksts"
|
139
|
+
rp.title_ru.should == "Русский заголовок"
|
140
|
+
rp.body_ru.should == "Русский текст"
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should not mass assign attributes in ProtectedPost" do
|
144
|
+
rp = ProtectedPost.new( :title_lv => "Latviešu nosaukums",
|
145
|
+
:title_ru => "Русский заголовок",
|
146
|
+
:body_lv => "Latviešu apraksts",
|
147
|
+
:body_ru => "Русский текст" )
|
148
|
+
|
149
|
+
# test
|
150
|
+
rp.title_lv.should_not == "Latviešu nosaukums"
|
151
|
+
rp.body_lv.should_not == "Latviešu apraksts"
|
152
|
+
rp.title_ru.should_not == "Русский заголовок"
|
153
|
+
rp.body_ru.should_not == "Русский текст"
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
it "should mass assign attributes in RegulularPost, v2" do
|
158
|
+
rp = RegularPost.new( { :title => {
|
159
|
+
:lv => "Latviešu nosaukums",
|
160
|
+
:ru => "Русский заголовок"
|
161
|
+
},
|
162
|
+
:body => {:lv => "Latviešu apraksts",
|
163
|
+
:ru => "Русский текст"
|
164
|
+
}
|
165
|
+
} )
|
166
|
+
|
167
|
+
# test
|
168
|
+
rp.title_lv.should == "Latviešu nosaukums"
|
169
|
+
rp.body_lv.should == "Latviešu apraksts"
|
170
|
+
rp.title_ru.should == "Русский заголовок"
|
171
|
+
rp.body_ru.should == "Русский текст"
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should not not mass assign attributes in ProtectedPost, v2" do
|
175
|
+
rp = ProtectedPost.new( { :title => {
|
176
|
+
:lv => "Latviešu nosaukums",
|
177
|
+
:ru => "Русский заголовок"
|
178
|
+
},
|
179
|
+
:body => {:lv => "Latviešu apraksts",
|
180
|
+
:ru => "Русский текст"
|
181
|
+
}
|
182
|
+
} )
|
183
|
+
|
184
|
+
# test
|
185
|
+
rp.title_lv.should_not == "Latviešu nosaukums"
|
186
|
+
rp.body_lv.should_not == "Latviešu apraksts"
|
187
|
+
rp.title_ru.should_not == "Русский заголовок"
|
188
|
+
rp.body_ru.should_not == "Русский текст"
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should save/load attributes in RegularPost" do
|
192
|
+
rp = RegularPost.new( :title_lv => "Latviešu nosaukums",
|
193
|
+
:title_ru => "Русский заголовок",
|
194
|
+
:body_lv => "Latviešu apraksts",
|
195
|
+
:body_ru => "Русский текст" )
|
196
|
+
|
197
|
+
rp.save
|
198
|
+
|
199
|
+
rp = RegularPost.last
|
200
|
+
|
201
|
+
rp.title_lv.should == "Latviešu nosaukums"
|
202
|
+
rp.body_lv.should == "Latviešu apraksts"
|
203
|
+
rp.title_ru.should == "Русский заголовок"
|
204
|
+
rp.body_ru.should == "Русский текст"
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should save attributes in db as indexable values" do
|
208
|
+
rp = RegularPost.new( :title_lv => "Latviešu nosaukums",
|
209
|
+
:title_ru => "Русский заголовок",
|
210
|
+
:body_lv => "Latviešu apraksts",
|
211
|
+
:body_ru => "Русский текст" )
|
212
|
+
|
213
|
+
rp.save
|
214
|
+
|
215
|
+
rp = RegularPost.last
|
216
|
+
|
217
|
+
rp.title_before_type_cast.should == {"lv"=>"Latviešu nosaukums", "ru"=>"Русский заголовок"}
|
218
|
+
rp.body_before_type_cast.should == {"lv"=>"Latviešu apraksts", "ru"=>"Русский текст"}
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should return proxied attribute" do
|
222
|
+
rp = RegularPost.new( :title_lv => "Latviešu nosaukums",
|
223
|
+
:title_ru => "Русский заголовок",
|
224
|
+
:body_lv => "Latviešu apraksts",
|
225
|
+
:body_ru => "Русский текст" )
|
226
|
+
|
227
|
+
|
228
|
+
rp.title.should be_an_instance_of(Multilang::MultilangTranslationProxy)
|
229
|
+
rp.title.should be_a_kind_of(String)
|
230
|
+
|
231
|
+
rp.body.should respond_to(:translation)
|
232
|
+
rp.title.translation[:lv].should == "Latviešu nosaukums"
|
233
|
+
rp.body.translation[:ru].should == "Русский текст"
|
234
|
+
|
235
|
+
rp.title.to_s.should be_an_instance_of(String)
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should set/get some attributes in/from PartialrPost" do
|
239
|
+
rp = RegularPost.new
|
240
|
+
|
241
|
+
# set
|
242
|
+
rp.title = "Latviešu nosaukums"
|
243
|
+
rp.body = "Latviešu apraksts"
|
244
|
+
|
245
|
+
# test
|
246
|
+
I18n.locale = :lv
|
247
|
+
rp.title.should == "Latviešu nosaukums"
|
248
|
+
rp.body.should == "Latviešu apraksts"
|
249
|
+
|
250
|
+
I18n.locale = :ru
|
251
|
+
rp.title.should == ""
|
252
|
+
rp.body.should == ""
|
253
|
+
|
254
|
+
rp.title.any.should == "Latviešu nosaukums"
|
255
|
+
rp.body.any.should == "Latviešu apraksts"
|
256
|
+
|
257
|
+
end
|
258
|
+
end
|
data/spec/schema.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 1) do
|
2
|
+
create_table :abstract_posts do |t|
|
3
|
+
t.hstore :title
|
4
|
+
t.hstore :body
|
5
|
+
t.integer :void, :default => 1
|
6
|
+
end
|
7
|
+
|
8
|
+
#create_table :posts do |t|
|
9
|
+
# t.text :title
|
10
|
+
# t.text :body
|
11
|
+
# t.integer :void, :default => 1
|
12
|
+
#end
|
13
|
+
|
14
|
+
#create_table :pages do |t|
|
15
|
+
# t.text :title
|
16
|
+
# t.text :body
|
17
|
+
# t.integer :void, :default => 1
|
18
|
+
#end
|
19
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
2
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_record'
|
7
|
+
require 'activerecord-postgres-hstore/activerecord'
|
8
|
+
require 'activerecord-postgres-hstore/coder'
|
9
|
+
require 'activerecord-postgres-hstore/hash'
|
10
|
+
require 'activerecord-postgres-hstore/string'
|
11
|
+
require 'multilang-hstore'
|
12
|
+
require 'logger'
|
13
|
+
|
14
|
+
ActiveRecord::Base.logger = Logger.new(nil)
|
15
|
+
ActiveRecord::Base.establish_connection(:adapter => "postgresql", :database => "multilang-hstore-test", :host=>'127.0.0.1', :user=>'postgres')
|
16
|
+
|
17
|
+
I18n.available_locales = [:lv, :ru]
|
18
|
+
I18n.locale = I18n.default_locale = :lv
|
19
|
+
|
20
|
+
def setup_db
|
21
|
+
ActiveRecord::Migration.verbose = false
|
22
|
+
load "schema.rb"
|
23
|
+
end
|
24
|
+
|
25
|
+
def teardown_db
|
26
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
27
|
+
ActiveRecord::Base.connection.drop_table(table)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
#testable models
|
32
|
+
class AbstractPost < ActiveRecord::Base
|
33
|
+
serialize :title, ActiveRecord::Coders::Hstore
|
34
|
+
serialize :body, ActiveRecord::Coders::Hstore
|
35
|
+
end
|
36
|
+
|
37
|
+
class MinimalPost < ActiveRecord::Base
|
38
|
+
self.table_name = 'abstract_posts'
|
39
|
+
multilang :title, :required => false, :accessible => true
|
40
|
+
multilang :body, :required => false, :accessible => true
|
41
|
+
attr_accessible :void
|
42
|
+
end
|
43
|
+
|
44
|
+
class RegularPost < ActiveRecord::Base
|
45
|
+
self.table_name = 'abstract_posts'
|
46
|
+
multilang :title, :required => true, :length => 25, :accessible => true
|
47
|
+
multilang :body, :required => true, :length => 1000, :accessible => true
|
48
|
+
attr_accessible :void
|
49
|
+
end
|
50
|
+
|
51
|
+
class ProtectedPost < ActiveRecord::Base
|
52
|
+
self.table_name = 'abstract_posts'
|
53
|
+
multilang :title, :accessible => false
|
54
|
+
multilang :body, :accessible => false
|
55
|
+
attr_accessible :void
|
56
|
+
end
|
57
|
+
|
58
|
+
class PartialPost < ActiveRecord::Base
|
59
|
+
self.table_name = 'abstract_posts'
|
60
|
+
multilang :title
|
61
|
+
multilang :body
|
62
|
+
attr_accessible :void
|
63
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: multilang-hstore
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Arthur Meinart
|
9
|
+
- Firebase.co
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-10-29 00:00:00.000000000 Z
|
14
|
+
dependencies: []
|
15
|
+
description: Model translations for Rails 3 backed by PostgreSQL and Hstore
|
16
|
+
email: hello@firebase.co
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files:
|
20
|
+
- README.rdoc
|
21
|
+
files:
|
22
|
+
- lib/multilang-hstore.rb
|
23
|
+
- lib/multilang-hstore/active_record_extensions.rb
|
24
|
+
- lib/multilang-hstore/translation_keeper.rb
|
25
|
+
- lib/multilang-hstore/translation_proxy.rb
|
26
|
+
- lib/multilang-hstore/version.rb
|
27
|
+
- README.rdoc
|
28
|
+
- spec/multilang_spec.rb
|
29
|
+
- spec/schema.rb
|
30
|
+
- spec/spec_helper.rb
|
31
|
+
homepage: http://github.com/firebaseco/multilang-hstore
|
32
|
+
licenses: []
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 1.8.24
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: Model translations for Rails 3 backed by PostgreSQL and Hstore
|
55
|
+
test_files:
|
56
|
+
- spec/multilang_spec.rb
|
57
|
+
- spec/schema.rb
|
58
|
+
- spec/spec_helper.rb
|
59
|
+
has_rdoc:
|