mongo_translatable 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. data/.document +5 -0
  2. data/.gitignore +26 -0
  3. data/.gitmodules +3 -0
  4. data/LICENSE +295 -0
  5. data/README.rdoc +131 -0
  6. data/Rakefile +55 -0
  7. data/VERSION +1 -0
  8. data/app/controllers/translations_controller.rb +150 -0
  9. data/app/helpers/translations_helper.rb +71 -0
  10. data/app/views/layouts/translations.html.erb +18 -0
  11. data/app/views/translations/_form.html.erb +50 -0
  12. data/app/views/translations/_translatable_value.html.erb +17 -0
  13. data/app/views/translations/_translation_field.html.erb +34 -0
  14. data/app/views/translations/_translation_field_input.html.erb +8 -0
  15. data/app/views/translations/edit.html.erb +8 -0
  16. data/app/views/translations/index.html.erb +22 -0
  17. data/app/views/translations/new.html.erb +7 -0
  18. data/app/views/translations/show.html.erb +12 -0
  19. data/config/locales/en.yml +33 -0
  20. data/config/locales/fr.yml +18 -0
  21. data/lib/mongo_translatable.rb +336 -0
  22. data/lib/mongo_translatable_configuration.rb +5 -0
  23. data/lib/translatables_helper.rb +227 -0
  24. data/lib/translations_controller_helpers.rb +37 -0
  25. data/rails/init.rb +3 -0
  26. data/test/full_2_3_5_app_with_tests/.gitignore +27 -0
  27. data/test/full_2_3_5_app_with_tests/README +1 -0
  28. data/test/full_2_3_5_app_with_tests/Rakefile +10 -0
  29. data/test/full_2_3_5_app_with_tests/app/controllers/application_controller.rb +26 -0
  30. data/test/full_2_3_5_app_with_tests/app/controllers/items_controller.rb +85 -0
  31. data/test/full_2_3_5_app_with_tests/app/helpers/application_helper.rb +3 -0
  32. data/test/full_2_3_5_app_with_tests/app/helpers/items_helper.rb +2 -0
  33. data/test/full_2_3_5_app_with_tests/app/models/comment.rb +3 -0
  34. data/test/full_2_3_5_app_with_tests/app/models/item.rb +5 -0
  35. data/test/full_2_3_5_app_with_tests/app/models/not_swapped_in_record.rb +3 -0
  36. data/test/full_2_3_5_app_with_tests/app/models/person.rb +3 -0
  37. data/test/full_2_3_5_app_with_tests/app/models/recipe.rb +21 -0
  38. data/test/full_2_3_5_app_with_tests/app/views/items/edit.html.erb +24 -0
  39. data/test/full_2_3_5_app_with_tests/app/views/items/index.html.erb +24 -0
  40. data/test/full_2_3_5_app_with_tests/app/views/items/new.html.erb +23 -0
  41. data/test/full_2_3_5_app_with_tests/app/views/items/show.html.erb +21 -0
  42. data/test/full_2_3_5_app_with_tests/app/views/layouts/items.html.erb +19 -0
  43. data/test/full_2_3_5_app_with_tests/config/boot.rb +110 -0
  44. data/test/full_2_3_5_app_with_tests/config/database.yml +22 -0
  45. data/test/full_2_3_5_app_with_tests/config/environment.rb +54 -0
  46. data/test/full_2_3_5_app_with_tests/config/environments/development.rb +17 -0
  47. data/test/full_2_3_5_app_with_tests/config/environments/production.rb +28 -0
  48. data/test/full_2_3_5_app_with_tests/config/environments/test.rb +28 -0
  49. data/test/full_2_3_5_app_with_tests/config/initializers/backtrace_silencers.rb +7 -0
  50. data/test/full_2_3_5_app_with_tests/config/initializers/inflections.rb +10 -0
  51. data/test/full_2_3_5_app_with_tests/config/initializers/mime_types.rb +5 -0
  52. data/test/full_2_3_5_app_with_tests/config/initializers/new_rails_defaults.rb +21 -0
  53. data/test/full_2_3_5_app_with_tests/config/initializers/session_store.rb +15 -0
  54. data/test/full_2_3_5_app_with_tests/config/locales.yml +5 -0
  55. data/test/full_2_3_5_app_with_tests/config/locales/en.yml +4 -0
  56. data/test/full_2_3_5_app_with_tests/config/locales/fr.yml +4 -0
  57. data/test/full_2_3_5_app_with_tests/config/locales/zh.yml +4 -0
  58. data/test/full_2_3_5_app_with_tests/config/routes.rb +4 -0
  59. data/test/full_2_3_5_app_with_tests/db/migrate/20100407010602_create_items.rb +14 -0
  60. data/test/full_2_3_5_app_with_tests/db/migrate/20100504234216_create_not_swapped_in_records.rb +15 -0
  61. data/test/full_2_3_5_app_with_tests/db/migrate/20100509011052_create_people.rb +13 -0
  62. data/test/full_2_3_5_app_with_tests/db/migrate/20100509042718_create_comments.rb +14 -0
  63. data/test/full_2_3_5_app_with_tests/db/migrate/20110112023516_create_recipes.rb +14 -0
  64. data/test/full_2_3_5_app_with_tests/db/schema.rb +56 -0
  65. data/test/full_2_3_5_app_with_tests/db/seeds.rb +7 -0
  66. data/test/full_2_3_5_app_with_tests/doc/README_FOR_APP +2 -0
  67. data/test/full_2_3_5_app_with_tests/public/404.html +30 -0
  68. data/test/full_2_3_5_app_with_tests/public/422.html +30 -0
  69. data/test/full_2_3_5_app_with_tests/public/500.html +30 -0
  70. data/test/full_2_3_5_app_with_tests/public/favicon.ico +0 -0
  71. data/test/full_2_3_5_app_with_tests/public/images/rails.png +0 -0
  72. data/test/full_2_3_5_app_with_tests/public/index.html +275 -0
  73. data/test/full_2_3_5_app_with_tests/public/javascripts/application.js +2 -0
  74. data/test/full_2_3_5_app_with_tests/public/javascripts/controls.js +963 -0
  75. data/test/full_2_3_5_app_with_tests/public/javascripts/dragdrop.js +973 -0
  76. data/test/full_2_3_5_app_with_tests/public/javascripts/effects.js +1128 -0
  77. data/test/full_2_3_5_app_with_tests/public/javascripts/prototype.js +4320 -0
  78. data/test/full_2_3_5_app_with_tests/public/robots.txt +5 -0
  79. data/test/full_2_3_5_app_with_tests/public/stylesheets/scaffold.css +54 -0
  80. data/test/full_2_3_5_app_with_tests/script/about +4 -0
  81. data/test/full_2_3_5_app_with_tests/script/console +3 -0
  82. data/test/full_2_3_5_app_with_tests/script/dbconsole +3 -0
  83. data/test/full_2_3_5_app_with_tests/script/destroy +3 -0
  84. data/test/full_2_3_5_app_with_tests/script/generate +3 -0
  85. data/test/full_2_3_5_app_with_tests/script/performance/benchmarker +3 -0
  86. data/test/full_2_3_5_app_with_tests/script/performance/profiler +3 -0
  87. data/test/full_2_3_5_app_with_tests/script/plugin +3 -0
  88. data/test/full_2_3_5_app_with_tests/script/runner +3 -0
  89. data/test/full_2_3_5_app_with_tests/script/server +3 -0
  90. data/test/full_2_3_5_app_with_tests/test/factories.rb +18 -0
  91. data/test/full_2_3_5_app_with_tests/test/functional/translations_controller_test.rb +66 -0
  92. data/test/full_2_3_5_app_with_tests/test/integration/translation_test.rb +72 -0
  93. data/test/full_2_3_5_app_with_tests/test/performance/browsing_test.rb +9 -0
  94. data/test/full_2_3_5_app_with_tests/test/selenium.rb +83 -0
  95. data/test/full_2_3_5_app_with_tests/test/test_helper.rb +86 -0
  96. data/test/full_2_3_5_app_with_tests/test/unit/helpers/translatables_helper_test.rb +37 -0
  97. data/test/full_2_3_5_app_with_tests/test/unit/helpers/translations_helper_test.rb +62 -0
  98. data/test/full_2_3_5_app_with_tests/test/unit/mongo_translatable_test.rb +342 -0
  99. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/init.rb +1 -0
  100. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter.rb +94 -0
  101. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/base.rb +31 -0
  102. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/force_extension.rb +57 -0
  103. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/locale.rb +70 -0
  104. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/pagination.rb +33 -0
  105. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/uuid_token.rb +78 -0
  106. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/force_extension_spec.rb +65 -0
  107. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/generation_spec.rb +367 -0
  108. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/pagination_extension_spec.rb +19 -0
  109. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/recognition_spec.rb +76 -0
  110. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/routing_filter_spec.rb +114 -0
  111. data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/spec_helper.rb +108 -0
  112. metadata +309 -0
@@ -0,0 +1,37 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'test_helper'
3
+
4
+ class TranslatablesHelperTest < ActionView::TestCase
5
+ context "Helpers for translatables" do
6
+ setup do
7
+ I18n.locale = I18n.default_locale
8
+ @item = Factory.create(:item, :label => "a label")
9
+ @translatable_params_name = "item"
10
+
11
+ def url_for_translated(options = { })
12
+ @controller.url_for_translated(options.merge(
13
+ :translated => @item,
14
+ :translatable_params_name => @translatable_params_name
15
+ ))
16
+ end
17
+ end
18
+
19
+ # TODO: current request need to be in environment for this to run
20
+ should "have provide available_in_locales_for that returns current translations for passed in item as list" do
21
+ @item.translate(:label => 'une étiquette', :locale => 'fr').save
22
+ html = "<ul><li><a href=\"/fr/items/1\">Français</li></ul>"
23
+ assert_equal html, available_in_locales_for(@item)
24
+ end
25
+
26
+ should "have provide needed_in_locales_for that returns current locales that don't have a translation for passed in item as list" do
27
+ locales = LOCALE_LABELS.keys - [:zh, :en]
28
+ translate_item_for_locales(@item, locales)
29
+ html = "<ul style='list-style:none; margin:0; padding:0;'>"
30
+ html += "<li style='float:left;'>Needs translating to:</li>"
31
+ html += "<li style=\"float: left; padding: 0 10px; \"><a href=\"/en/items/1/translations/new?to_locale=zh\">中文</a></li>"
32
+ html += "</ul><div style='clear:both;'></div>"
33
+ I18n.locale = I18n.default_locale
34
+ assert_equal html, needed_in_locales_for(@item)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,62 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'test_helper'
3
+
4
+ class TranslationsHelperTest < ActionView::TestCase
5
+ context "Helpers for translation" do
6
+ setup do
7
+ I18n.locale = I18n.default_locale
8
+ @translatable = Factory.create(:item, :label => "a label")
9
+ @translatable_class = Item
10
+ @translatable_key = :item_id
11
+ @translatable_params_name = "item"
12
+
13
+ def url_for_translated(options = { })
14
+ @controller.url_for_translated(options.merge(
15
+ :translated => @translatable,
16
+ :translatable_params_name => @translatable_params_name
17
+ ))
18
+ end
19
+ end
20
+
21
+ should "have avalailable_locales_for_options" do
22
+ locale_options = [["Français", "fr"],
23
+ ["中文", "zh"],
24
+ ["Suomi", "fi"],
25
+ ["العربية", "ar"],
26
+ ["English", "en"]]
27
+ assert_equal locale_options, available_locales_for_options
28
+ end
29
+
30
+ should "have provide available_in_locales that returns current translations for @translatable as list" do
31
+ @translatable.translate(:label => 'une étiquette', :locale => 'fr').save
32
+ html = "<ul><li><a href=\"http://test.host/en/items/1\">English</a></li><li><a href=\"http://test.host/fr/items/1\">Français</a></li></ul>"
33
+ assert_equal html, available_in_locales
34
+ end
35
+
36
+ should "have provide needed_in_locales that returns current locales that don't have a translation for @translatable as list" do
37
+ locales = LOCALE_LABELS.keys - [:zh, :en]
38
+ translate_item_for_locales(@translatable, locales)
39
+ html = "<ul><li><a href=\"/en/items/1/translations/new?to_locale=zh\">中文</a></li></ul>"
40
+ I18n.locale = I18n.default_locale
41
+ assert_equal html, needed_in_locales
42
+ end
43
+
44
+ should "take attribute_key and give localized label" do
45
+ assert_equal "Label", localized_label_for(:label)
46
+ end
47
+
48
+ should "take translatable and output internationalized html to display the original text of the attributes" do
49
+ array_with_hashes_of_translatable_attributes_with_internationalized_names = [{:attribute_key=>:label, :localized_label => "Label", :value => "a label"}]
50
+ # ignoring description for now (thus wrapped in array and .first)
51
+ assert_equal array_with_hashes_of_translatable_attributes_with_internationalized_names, [untranslated_values_with_localized_labels.first]
52
+ end
53
+
54
+ should "take translation and output internationalized html to display the translated text of the attributes" do
55
+ @translatable.translate(:label => 'une étiquette', :locale => 'fr').save
56
+ @translation = @translatable.translation_for(:fr)
57
+ array_with_hashes_of_translated_attributes_with_internationalized_names = [{:attribute_key=>:label, :localized_label => "Label", :value => "une étiquette"}]
58
+ # ignoring description for now (thus wrapped in array and .first)
59
+ assert_equal array_with_hashes_of_translated_attributes_with_internationalized_names, [translated_values_with_localized_labels.first]
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,342 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'test_helper'
3
+
4
+ class MongodbTranslatableTest < ActiveSupport::TestCase
5
+ context "A translation" do
6
+ setup do
7
+ I18n.locale = I18n.default_locale
8
+
9
+ @item = Factory.create(:item)
10
+
11
+ item_hash = Hash.new
12
+ item_hash[:label] = @item.attributes['label']
13
+ item_hash[:locale] = :fr
14
+ item_hash[@item.class.as_foreign_key_sym] = @item.id
15
+ @translation = @item.class::Translation.create(item_hash)
16
+ end
17
+
18
+ should "have a locale" do
19
+ if assert(@translation.respond_to?(:locale))
20
+ assert @translation.locale
21
+ end
22
+ end
23
+
24
+ should "have a translated object's translated attributes" do
25
+ assert @translation.attributes[Item.translatable_attributes.first]
26
+ end
27
+
28
+ should "be accessable from its item" do
29
+ if assert(@item.respond_to?(:translations))
30
+ assert @item.translation_for(I18n.locale)
31
+ end
32
+ end
33
+
34
+ should "be able to retrieve just the translated attribute" do
35
+ if assert(@item.respond_to?(:translations) && @item.respond_to?(:label_translation_for))
36
+ assert @item.label_translation_for(I18n.locale)
37
+ end
38
+ end
39
+
40
+ should "be able to retrieve its item from the item's persistence" do
41
+ assert @translation.translatable
42
+ end
43
+ end
44
+
45
+ context "When there is an Item needing translating" do
46
+ setup do
47
+ @item = Factory.create(:item, { :label => LOCALE_LABELS[:en] })
48
+ end
49
+
50
+ should "create translation" do
51
+ translate_item_for_locales(@item, :zh)
52
+ assert @item.translations.count == 1
53
+ end
54
+
55
+ should "not create translation if no translated text submitted" do
56
+ # arabic
57
+ I18n.locale = :ar
58
+ @item.translate
59
+ assert @item.translations.count == 0
60
+ end
61
+
62
+ should "not create translation if item's original_locale is same as translation locale" do
63
+ I18n.locale = :en
64
+ @item.translate(:label => LOCALE_LABELS[:en])
65
+ assert @item.translations.count == 0
66
+ end
67
+
68
+ should "create translation and it should reflect current locale" do
69
+ # french
70
+ translate_item_for_locales(@item, :fr)
71
+ assert @item.translation_for(:fr)
72
+ end
73
+
74
+ should "find item with the proper translation for current locale" do
75
+ translate_item_for_locales(@item, :fi)
76
+
77
+ # reloading item should detect current locale and pass back translated version of object
78
+ @item = Item.find(@item.id)
79
+
80
+ assert_equal @item.label, LOCALE_LABELS[:fi]
81
+ end
82
+
83
+ should "find item with the proper translation for current locale and fallback to original's value for translatable attribute that hasn't been translated" do
84
+ translate_item_for_locales(@item, :fi)
85
+
86
+ original_description = @item.description
87
+
88
+ # reloading item should detect current locale and pass back translated version of object
89
+ @item = Item.find(@item.id)
90
+
91
+ assert_equal @item.label, LOCALE_LABELS[:fi]
92
+ assert_equal original_description, @item.description
93
+ end
94
+
95
+ should "find item with the proper translation for current locale when there is more than one translation" do
96
+ # add a couple translations
97
+ translate_item_for_locales(@item, [:fi, :fr])
98
+
99
+ # then back to finnish
100
+ I18n.locale = :fi
101
+
102
+ # reloading item should detect current locale and pass back translated version of object
103
+ @item = Item.find(@item.id)
104
+
105
+ assert_equal @item.label, LOCALE_LABELS[:fi]
106
+ end
107
+
108
+ # test dynamic finder
109
+ should "find item with the proper translation for current locale when there is more than one translation and finding using dynamic finder" do
110
+ @item = Factory.create(:item, {:value => "a value"})
111
+
112
+ # add a couple translations
113
+ translate_item_for_locales(@item, [:fi, :fr])
114
+
115
+ # then back to finnish
116
+ I18n.locale = :fi
117
+
118
+ # reloading item should detect current locale and pass back translated version of object
119
+ @item = Item.find_by_value(@item.value)
120
+
121
+ assert_equal @item.label, LOCALE_LABELS[:fi]
122
+ end
123
+
124
+ should "after creating translations, if the item is destroyed, the translations are destroyed" do
125
+ # add a couple translations
126
+ translate_item_for_locales(@item, [:fi, :fr])
127
+
128
+ translations_ids = @item.translations.collect { |translation| translation.id }
129
+
130
+ @item.destroy
131
+
132
+ remaining_translations = Item::Translation.find(translations_ids)
133
+
134
+ assert_equal 0, remaining_translations.size
135
+ end
136
+
137
+ should "when the item is destroyed, when it has no translations, it should succeed in being destroyed" do
138
+ assert_equal 0, @item.translations.size
139
+ assert @item.destroy
140
+ end
141
+
142
+ teardown do
143
+ I18n.locale = @original_locale
144
+ end
145
+ end
146
+
147
+ context "When there are many items being translated" do
148
+ setup do
149
+ # TODO: pull out this locale, not sure why before_save filter is not being called
150
+ @original_locale = I18n.locale
151
+ end
152
+
153
+ should "find items with the proper translation for current locale" do
154
+ ids = many_setup
155
+
156
+ # reloading item should detect current locale and pass back translated version of object
157
+ @items = Item.find(ids)
158
+
159
+ many_tests
160
+ end
161
+
162
+ should "find items with the proper translation for current locale using dynamic finder" do
163
+ value = "a value"
164
+ many_setup({:value => value})
165
+
166
+ # reloading item should detect current locale and pass back translated version of object
167
+ @items = Item.find_all_by_value(value)
168
+
169
+ many_tests(:fi => 10)
170
+ end
171
+
172
+ teardown do
173
+ I18n.locale = @original_locale
174
+ end
175
+ end
176
+
177
+ context "translations for an item" do
178
+ setup do
179
+ I18n.locale = I18n.default_locale
180
+ @item = Factory.create(:item)
181
+ @translation_keys = LOCALE_LABELS.keys - [:en]
182
+ translate_item_for_locales(@item, @translation_keys)
183
+ end
184
+
185
+ should "be retrievable from translations method" do
186
+ assert_equal @translation_keys.size, @item.translations.size
187
+ end
188
+
189
+ should "hae just locales be retrievable from translations_locales method" do
190
+ # these should be partial objects and not have any values for other attributes
191
+ locale_keys = @item.translations_locales.collect { |translation| translation.locale.to_sym if translation.label.nil? }.compact
192
+
193
+ assert_equal 0, (@translation_keys - locale_keys).size
194
+ end
195
+
196
+ should "have translation locales plus original local be retrievable as available_in_these_locales" do
197
+ locale_keys = @item.available_in_these_locales.collect { |locale| locale.to_sym }
198
+
199
+ assert_equal 0, ( ([:en] + @translation_keys) - locale_keys ).size
200
+ end
201
+
202
+ should "have needed_in_these_locales method that returns locales that haven't been translated yet" do
203
+ Item::Translation.first(:item_id => @item.id, :locale => "zh").destroy
204
+ assert_equal [:zh], @item.needed_in_these_locales.collect { |locale| locale.to_sym }
205
+ end
206
+ end
207
+
208
+ context "A Translatable class that has a plural associated accessors (has_many) in another class through an association" do
209
+ setup do
210
+ I18n.locale = I18n.default_locale
211
+
212
+ @person = Factory.create(:person)
213
+ @item1 = Factory.create(:item, :person => @person)
214
+ @item2 = Factory.create(:item, :person => @person)
215
+
216
+ translate_item_for_locales(@item1, :fr)
217
+ end
218
+
219
+ should "get translated results from plural accessor" do
220
+ I18n.locale = :fr
221
+ results_with_one_translated_labels = [@item1.reload, @item2].collect(&:label)
222
+
223
+ assert_equal results_with_one_translated_labels, @person.items.collect(&:label)
224
+ end
225
+ end
226
+
227
+ context "A Translatable class that has a singular associated accessor (belongs_to, has_one) in another class through an association" do
228
+ setup do
229
+ I18n.locale = I18n.default_locale
230
+
231
+ @item = Factory.create(:item, :person => @person)
232
+ @comment = @item.comments.create(:subject => "usual mallarky")
233
+
234
+ translate_item_for_locales(@item, :fr)
235
+ end
236
+
237
+ should "get translated results from singular accessor" do
238
+ I18n.locale = :fr
239
+ translated_label = Item.find(@item).label
240
+ assert_equal translated_label, @comment.item.label
241
+ end
242
+ end
243
+
244
+ context "A Translatable class that has redefine_find == false" do
245
+ setup do
246
+ I18n.locale = I18n.default_locale
247
+ @record = Factory.create(:not_swapped_in_record)
248
+ record_hash = Hash.new
249
+ record_hash[:name] = @record.attributes['name']
250
+ record_hash[:locale] = :fr
251
+ record_hash[@record.class.as_foreign_key_sym] = @record.id
252
+ @no_find_translation = @record.class::Translation.create(record_hash)
253
+ end
254
+
255
+ should "not swap out locale specific translation for record when loaded from a translated locale" do
256
+ I18n.locale = :fr
257
+ @record.reload
258
+ assert_equal 'en', @record.locale
259
+ end
260
+ end
261
+
262
+ context "A Translatable class that has some translatable_attributes with key_type specified" do
263
+
264
+ should "have String for type of key without key_type specified (default)" do
265
+ assert_equal Recipe::Translation.keys['name'].type, String
266
+ end
267
+
268
+ should "have Array for type of key when " do
269
+ assert_equal Recipe::Translation.keys['steps'].type, Array
270
+ assert_equal Recipe::Translation.keys['ingredients'].type, Array
271
+ end
272
+
273
+ context "can create translations that" do
274
+ setup do
275
+ I18n.locale = I18n.default_locale
276
+ @recipe = Factory.create(:recipe)
277
+ end
278
+
279
+ should "return value in correct key type for translatable_attribute" do
280
+ assert_equal @recipe.steps, ["steps1 - 1", "steps1 - 2"]
281
+ assert_equal @recipe.ingredients, ["ingredients1 - 1", "ingredients1 - 2"]
282
+
283
+ fr_steps = ['fr step 1', 'fr step 2']
284
+ fr_ingredients = ['fr ingredient 1', 'fr ingredient 2']
285
+
286
+ @recipe_translation = @recipe.class::Translation.create(:name => @recipe.attributes['name'],
287
+ :steps => fr_steps,
288
+ :ingredients => fr_ingredients,
289
+ :locale => :fr,
290
+ @recipe.class.as_foreign_key_sym => @recipe.id)
291
+
292
+ @recipe_translation.reload
293
+
294
+ assert_equal fr_steps, @recipe_translation.steps
295
+ assert_equal fr_ingredients, @recipe_translation.ingredients
296
+ end
297
+
298
+ end
299
+ end
300
+
301
+ private
302
+
303
+ # see many_tests for what it expects
304
+ def many_setup(item_spec = nil)
305
+ ids = Array.new
306
+ 5.times do
307
+ I18n.locale = @original_locale
308
+ item = item_spec ? Factory.create(:item, item_spec) : Factory.create(:item)
309
+ translate_item_for_locales(item, [:ar, :fr])
310
+ ids << item.id
311
+ end
312
+
313
+ 5.times do
314
+ I18n.locale = @original_locale
315
+ item = item_spec ? Factory.create(:item, item_spec) : Factory.create(:item)
316
+ translate_item_for_locales(item, [:zh, :fi])
317
+ ids << item.id
318
+ end
319
+
320
+ # excluding these from ids searched
321
+ 5.times do
322
+ I18n.locale = @original_locale
323
+ item = item_spec ? Factory.create(:item, item_spec) : Factory.create(:item)
324
+ translate_item_for_locales(item, [:fr, :fi])
325
+ end
326
+
327
+ I18n.locale = :fi
328
+ ids
329
+ end
330
+
331
+ # expect 5 en, 5 finnish, and none in french, chinese, or arabic
332
+ def many_tests(passed_amounts = { })
333
+ results_number_for = { :fi => 5, :en => 5, :fr => 0, :ar => 0, :zh => 0}
334
+ results_number_for.merge!(passed_amounts)
335
+
336
+ assert_equal results_number_for[:fi], @items.select { |i| i.locale.to_sym == :fi }.size
337
+ assert_equal results_number_for[:en], @items.select { |i| i.locale.to_sym == :en }.size
338
+ assert_equal results_number_for[:fr], @items.select { |i| i.locale.to_sym == :fr }.size
339
+ assert_equal results_number_for[:ar], @items.select { |i| i.locale.to_sym == :ar }.size
340
+ assert_equal results_number_for[:zh], @items.select { |i| i.locale.to_sym == :zh }.size
341
+ end
342
+ end
@@ -0,0 +1,94 @@
1
+ module RoutingFilter
2
+ mattr_accessor :active
3
+ @@active = true
4
+
5
+ class Chain < Array
6
+ def << (filter)
7
+ filter.chain = self
8
+ super
9
+ end
10
+
11
+ def run(method, *args, &final)
12
+ RoutingFilter.active && !first.nil? ? first.run(method, *args, &final) : final.call
13
+ end
14
+
15
+ def run_reverse(method, *args, &final)
16
+ RoutingFilter.active && !last.nil? ? last.run_reverse(method, *args, &final) : final.call
17
+ end
18
+
19
+ def predecessor(filter)
20
+ ix = index(filter)
21
+ ix > 0 ? self[ix - 1] : nil
22
+ end
23
+
24
+ def successor(filter)
25
+ ix = index(filter)
26
+ ix < length - 1 ? self[ix + 1] : nil
27
+ end
28
+ end
29
+ end
30
+
31
+ # allows to install a filter to the route set by calling: map.filter 'locale'
32
+ ActionController::Routing::RouteSet::Mapper.class_eval do
33
+ def filter(name, options = {})
34
+ require options.delete(:file) || "routing_filter/#{name}"
35
+ klass = RoutingFilter.const_get(name.to_s.camelize)
36
+ @set.filters << klass.new(options)
37
+ end
38
+ end
39
+
40
+ # same here for the optimized url generation in named routes
41
+ ActionController::Routing::RouteSet::NamedRouteCollection.class_eval do
42
+ # gosh. monkey engineering optimization code
43
+ def generate_optimisation_block_with_filtering(*args)
44
+ code = generate_optimisation_block_without_filtering(*args)
45
+ if match = code.match(%r(^return (.*) if (.*)))
46
+ # returned string must not contain newlines, or we'll spill out of inline code comments in
47
+ # ActionController::Routing::RouteSet::NamedRouteCollection#define_url_helper
48
+ "returning(#{match[1]}) { |result|" +
49
+ " ActionController::Routing::Routes.filters.run_reverse(:around_generate, *args, &lambda{ result }) " +
50
+ "} if #{match[2]}"
51
+ end
52
+ end
53
+ alias_method_chain :generate_optimisation_block, :filtering
54
+ end
55
+
56
+ ActionController::Routing::RouteSet.class_eval do
57
+ def clear_with_filtering!
58
+ @filters.clear if @filters
59
+ clear_without_filtering!
60
+ end
61
+ alias_method_chain :clear!, :filtering
62
+
63
+ attr_writer :filters
64
+
65
+ def filters
66
+ @filters ||= RoutingFilter::Chain.new
67
+ end
68
+
69
+ def recognize_path_with_filtering(path, env = {})
70
+ path = ::URI.unescape(path.dup) # string is frozen due to memoize
71
+ filters.run(:around_recognize, path, env, &lambda{ recognize_path_without_filtering(path, env) })
72
+ end
73
+ alias_method_chain :recognize_path, :filtering
74
+
75
+ def generate_with_filtering(*args)
76
+ filters.run_reverse(:around_generate, args.first, &lambda{ generate_without_filtering(*args) })
77
+ end
78
+ alias_method_chain :generate, :filtering
79
+
80
+ # add some useful information to the request environment
81
+ # right, this is from jamis buck's excellent article about routes internals
82
+ # http://weblog.jamisbuck.org/2006/10/26/monkey-patching-rails-extending-routes-2
83
+ # TODO move this ... where?
84
+ alias_method :extract_request_environment_without_host, :extract_request_environment unless method_defined? :extract_request_environment_without_host
85
+ def extract_request_environment(request)
86
+ returning extract_request_environment_without_host(request) do |env|
87
+ env.merge! :host => request.host,
88
+ :port => request.port,
89
+ :host_with_port => request.host_with_port,
90
+ :domain => request.domain,
91
+ :subdomain => request.subdomains.first
92
+ end
93
+ end
94
+ end