locomotive_cms 2.5.5 → 2.5.6.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -2
  3. data/README.textile +3 -3
  4. data/app/assets/images/locomotive/icons/flags/pt.png +0 -0
  5. data/app/assets/javascripts/locomotive/utils/aloha_settings.js.coffee +1 -1
  6. data/app/assets/javascripts/locomotive/views/current_site/edit_view.js.coffee +5 -0
  7. data/app/assets/stylesheets/locomotive/backoffice/menu/main.css.scss +1 -1
  8. data/app/controllers/locomotive/api/theme_assets_controller.rb +1 -1
  9. data/app/controllers/locomotive/public/content_entries_controller.rb +6 -11
  10. data/app/controllers/locomotive/public/pages_controller.rb +1 -1
  11. data/app/controllers/locomotive/public/sitemaps_controller.rb +1 -1
  12. data/app/models/locomotive/extensions/content_type/sync.rb +16 -5
  13. data/app/models/locomotive/extensions/page/tree.rb +7 -3
  14. data/app/models/locomotive/extensions/site/locales.rb +12 -9
  15. data/app/models/locomotive/site.rb +10 -0
  16. data/app/views/locomotive/current_site/_form.html.haml +1 -0
  17. data/config/locales/admin_ui.cs.yml +2 -0
  18. data/config/locales/admin_ui.de.yml +3 -2
  19. data/config/locales/admin_ui.en.yml +1 -0
  20. data/config/locales/admin_ui.es.yml +2 -1
  21. data/config/locales/admin_ui.et.yml +1 -0
  22. data/config/locales/admin_ui.fr.yml +2 -1
  23. data/config/locales/admin_ui.it.yml +23 -0
  24. data/config/locales/admin_ui.ja.yml +1 -0
  25. data/config/locales/admin_ui.nb.yml +1 -0
  26. data/config/locales/admin_ui.nl.yml +4 -0
  27. data/config/locales/admin_ui.pl.yml +1 -0
  28. data/config/locales/admin_ui.pt-BR.yml +6 -5
  29. data/config/locales/admin_ui.pt.yml +320 -0
  30. data/config/locales/admin_ui.ru.yml +1 -0
  31. data/config/locales/admin_ui.sk.yml +2 -0
  32. data/config/locales/admin_ui.sr.yml +1 -0
  33. data/config/locales/admin_ui.zh-CN.yml +1 -0
  34. data/config/locales/carrierwave.pt.yml +4 -0
  35. data/config/locales/default.pt.yml +212 -0
  36. data/config/locales/devise.pt.yml +62 -0
  37. data/config/locales/flash.pt.yml +106 -0
  38. data/config/locales/formtastic.pt.yml +70 -0
  39. data/config/routes.rb +5 -6
  40. data/features/api/authorization/theme_assets.feature +4 -4
  41. data/features/public/contact_form.feature +1 -1
  42. data/features/public/new_contact_form.feature +95 -0
  43. data/features/public/pages.feature +2 -2
  44. data/features/step_definitions/relationships_steps.rb +37 -34
  45. data/lib/generators/locomotive/install/install_generator.rb +2 -0
  46. data/lib/generators/locomotive/install/templates/README +3 -2
  47. data/lib/generators/locomotive/install/templates/devise.rb +175 -0
  48. data/lib/generators/locomotive/install/templates/dragonfly.rb +1 -1
  49. data/lib/generators/locomotive/install/templates/locomotive.rb +2 -2
  50. data/lib/locomotive.rb +9 -0
  51. data/lib/locomotive/action_controller/public_responder.rb +45 -28
  52. data/lib/locomotive/configuration.rb +2 -2
  53. data/lib/locomotive/liquid/drops/content_entry.rb +6 -8
  54. data/lib/locomotive/liquid/drops/site.rb +1 -5
  55. data/lib/locomotive/liquid/filters/translate.rb +1 -1
  56. data/lib/locomotive/liquid/tags/fetch_page.rb +14 -6
  57. data/lib/locomotive/liquid/tags/model_form.rb +75 -0
  58. data/lib/locomotive/middlewares.rb +5 -1
  59. data/lib/locomotive/middlewares/base.rb +45 -0
  60. data/lib/locomotive/middlewares/locale.rb +32 -0
  61. data/lib/locomotive/middlewares/locale_redirection.rb +46 -0
  62. data/lib/locomotive/middlewares/seo_trailing_slash.rb +7 -28
  63. data/lib/locomotive/middlewares/site.rb +26 -0
  64. data/lib/locomotive/regexps.rb +1 -1
  65. data/lib/locomotive/render.rb +22 -2
  66. data/lib/locomotive/routing.rb +1 -0
  67. data/lib/locomotive/routing/post_content_entry_constraint.rb +11 -0
  68. data/lib/locomotive/routing/site_dispatcher.rb +1 -12
  69. data/lib/locomotive/version.rb +1 -1
  70. data/spec/dummy/config/boot.rb +1 -1
  71. data/spec/dummy/config/initializers/dragonfly.rb +1 -1
  72. data/spec/dummy/config/initializers/locomotive.rb +2 -2
  73. data/spec/lib/locomotive/liquid/drops/content_entry_spec.rb +23 -18
  74. data/spec/lib/locomotive/liquid/drops/site_spec.rb +25 -15
  75. data/spec/lib/locomotive/liquid/tags/model_form_spec.rb +46 -0
  76. data/spec/lib/locomotive/routing/site_dispatcher_spec.rb +0 -41
  77. data/spec/models/locomotive/site_spec.rb +1 -1
  78. data/spec/requests/locale_redirection_spec.rb +109 -0
  79. data/spec/requests/locale_spec.rb +85 -0
  80. data/spec/requests/seo_trailing_slash_spec.rb +1 -1
  81. data/spec/requests/site_spec.rb +27 -0
  82. data/spec/support/factories.rb +6 -0
  83. data/spec/support/middlewares.rb +3 -0
  84. metadata +48 -10
@@ -1,42 +1,21 @@
1
1
  module Locomotive
2
2
  module Middlewares
3
- class SeoTrailingSlash
3
+ class SeoTrailingSlash < Base
4
4
 
5
5
  def initialize(app, opts = {})
6
6
  @app = app
7
7
  end
8
8
 
9
9
  def call(env)
10
- path, query = env['PATH_INFO'], env['QUERY_STRING']
10
+ request = Rack::Request.new(env)
11
11
 
12
- if !path.starts_with?("#{Locomotive.mounted_on}/") && (match = path.match(%r{(.+)/$}))
13
- url = self.redirect_url(match[1], query)
14
- self.redirect_to(url)
15
- else
16
- @app.call(env)
17
- end
18
- end
12
+ path = request.path
19
13
 
20
- protected
21
-
22
- # Create a 301 response and set it up accordingly.
23
- #
24
- # @params [ String ] url The url for the redirection
25
- #
26
- # @return [ Array ] It has the 3 parameters (status, header, body)
27
- #
28
- def redirect_to(url)
29
- response = Rack::Response.new
30
- response.redirect(url, 301) # moved permanently
31
- response.finish
32
- response.to_a
33
- end
34
-
35
- def redirect_url(base, query)
36
- if query.blank?
37
- base
14
+ if !is_backoffice?(request) && path.size > 1 && path.ends_with?('/')
15
+ url = modify_url(request, request.path.chop)
16
+ redirect_to(url)
38
17
  else
39
- "#{base}?#{query}"
18
+ @app.call(env)
40
19
  end
41
20
  end
42
21
 
@@ -0,0 +1,26 @@
1
+ module Locomotive
2
+ module Middlewares
3
+ class Site
4
+
5
+ def initialize(app, opts = {})
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env['locomotive.site'] = fetch_site(env)
11
+ @app.call(env)
12
+ end
13
+
14
+ def fetch_site(env)
15
+ request = Rack::Request.new(env)
16
+ Locomotive.log "[fetch site] host = #{request.host} / #{env['HTTP_HOST']}"
17
+ if Locomotive.config.multi_sites?
18
+ Locomotive::Site.match_domain(request.host).first
19
+ else
20
+ Locomotive::Site.first
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -3,7 +3,7 @@ module Locomotive
3
3
 
4
4
  SUBDOMAIN = /^[a-z][a-z0-9_-]*[a-z0-9]{1}$/
5
5
 
6
- DOMAIN = /^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}(:[0-9]{1,5})?(\/.*)?$/ix
6
+ DOMAIN = /^(([a-z])([a-z\d-]){0,61}([a-z\d]))(\.([a-z])([a-z\d-]){0,61}([a-z\d]))*$/i
7
7
 
8
8
  URL = /((http|https|ftp):\/)?\/\S*/
9
9
 
@@ -68,7 +68,7 @@ module Locomotive
68
68
  # Inputs which define the ETag for this response
69
69
  etag_inputs = {
70
70
  'page' => @page.cache_key,
71
- 'locale' => params[:locale]
71
+ 'locale' => request.env['locomotive.locale'] || params[:locale]
72
72
  }
73
73
 
74
74
  if @page.with_cache?
@@ -108,13 +108,33 @@ module Locomotive
108
108
  #
109
109
  def locomotive_page(path = nil)
110
110
  # TODO: params[:path] is more consistent
111
- path ||= (params[:path] || params[:page_path] || request.fullpath).clone
111
+ path = self.locomotive_path(path)
112
112
 
113
113
  path = self.sanitize_locomotive_page_path(path)
114
114
 
115
115
  current_site.fetch_page path, current_locomotive_account.present?
116
116
  end
117
117
 
118
+ # Get the Locomotive path by testing different sources:
119
+ # - request.env['locomotive.path'] (set only for urls with the locale inside)
120
+ # - params[:path]
121
+ # - params[:page_path]
122
+ # - request.fullpath
123
+ #
124
+ # It performs a clone of the path before returning it.
125
+ #
126
+ # @param [ String ] path Nil by default. In case we force a path.
127
+ #
128
+ # @return [ STring ] The LocomotiveCMS path
129
+ #
130
+ def locomotive_path(path = nil)
131
+ (path ||
132
+ request.env['locomotive.path'] ||
133
+ params[:path] ||
134
+ params[:page_path] ||
135
+ request.fullpath).clone
136
+ end
137
+
118
138
  # Clean the path that can be understood by Locomotive in order to retrieve
119
139
  # the matching Locomotive page (see the locomotive_page method)
120
140
  #
@@ -1,2 +1,3 @@
1
1
  require 'locomotive/routing/default_constraint'
2
+ require 'locomotive/routing/post_content_entry_constraint'
2
3
  require 'locomotive/routing/site_dispatcher'
@@ -0,0 +1,11 @@
1
+ module Locomotive
2
+ module Routing
3
+ class PostContentEntryConstraint
4
+
5
+ def matches?(request)
6
+ request.post? && request.params[:content_type_slug].present?
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -6,7 +6,6 @@ module Locomotive
6
6
 
7
7
  included do
8
8
  if self.respond_to?(:before_filter)
9
- before_filter :fetch_site
10
9
 
11
10
  helper_method :current_site
12
11
  end
@@ -14,18 +13,8 @@ module Locomotive
14
13
 
15
14
  protected
16
15
 
17
- def fetch_site
18
- Locomotive.log "[fetch site] host = #{request.host} / #{request.env['HTTP_HOST']}"
19
-
20
- if Locomotive.config.multi_sites?
21
- @current_site ||= Locomotive::Site.match_domain(request.host).first
22
- else
23
- @current_site ||= Locomotive::Site.first
24
- end
25
- end
26
-
27
16
  def current_site
28
- @current_site || fetch_site
17
+ @current_site ||= request.env['locomotive.site']
29
18
  end
30
19
 
31
20
  def require_site
@@ -1,3 +1,3 @@
1
1
  module Locomotive #:nodoc
2
- VERSION = '2.5.5'
2
+ VERSION = '2.5.6.rc1'
3
3
  end
@@ -9,7 +9,7 @@ gemfile = File.expand_path('../../../../Gemfile', __FILE__)
9
9
  # delayed job version is released?
10
10
  #
11
11
  require 'yaml'
12
- YAML::ENGINE.yamler = 'syck' if defined?(YAML::ENGINE)
12
+ YAML::ENGINE.yamler = 'syck' if defined?(Delayed::Worker)
13
13
 
14
14
  if File.exist?(gemfile)
15
15
  ENV['BUNDLE_GEMFILE'] = gemfile
@@ -6,7 +6,7 @@ Dragonfly.app.configure do
6
6
  convert_command: `which convert`.strip.presence || '/usr/local/bin/convert',
7
7
  identify_command: `which identify`.strip.presence || '/usr/local/bin/identify'
8
8
 
9
- protect_from_dos_attacks true
9
+ verify_urls true
10
10
 
11
11
  secret 'a7d8613dc92256d0c0a3665a05d8af1b5efa5f66394ffca74da74eb41cc590e4'
12
12
 
@@ -33,11 +33,11 @@ Locomotive.configure do |config|
33
33
  per_page: 10
34
34
  }
35
35
 
36
- # default locale (for now, only en, de, fr, pl, pt-BR, it, nl, nb, ja, cs, bg and sk are supported)
36
+ # default locale (for now, only en, de, fr, pl, pt, pt-BR, it, nl, nb, ja, cs, bg and sk are supported)
37
37
  config.default_locale = :en
38
38
 
39
39
  # available locales suggested to "localize" a site. You will have to pick up at least one among that list.
40
- # config.site_locales = %w{en de fr pl pt-BR it nl nb es ru ja cs bg sk}
40
+ # config.site_locales = %w{en de fr pl pt pt-BR it nl nb es ru ja cs bg sk}
41
41
 
42
42
  # tell if logs are enabled. Useful for debug purpose.
43
43
  config.enable_logs = true
@@ -22,36 +22,41 @@ describe Locomotive::Liquid::Drops::ContentEntry do
22
22
 
23
23
  describe 'a list of entries' do
24
24
 
25
- before(:each) do
26
- @list = mock('list')
27
- @list.stubs(:all).returns(true)
28
- @category = Locomotive::Liquid::Drops::ContentEntry.new(mock('category', projects: @list))
29
- end
25
+ let(:list) { stub('list', all: true, to_a: %w(a b)) }
26
+ let(:category) { Locomotive::Liquid::Drops::ContentEntry.new(mock('category', projects: list)) }
27
+
28
+ subject { render(template, { 'category' => category }) }
29
+
30
+ describe 'accessing a has_many relationship' do
31
+
32
+ describe 'looping through the list' do
30
33
 
31
- context '#accessing a has_many relationship' do
34
+ let(:template) { %({% for project in category.projects %}{{ project }},{% endfor %}) }
32
35
 
33
- it 'loops through the list' do
34
- template = %({% for project in category.projects %}{{ project }},{% endfor %})
36
+ before { list.expects(:filtered).with({ '_visible' => true }, nil).returns(list.to_a) }
35
37
 
36
- @list.expects(:ordered).returns(%w(a b))
38
+ it { should eq 'a,b,' }
37
39
 
38
- render(template, { 'category' => @category }).should == 'a,b,'
39
40
  end
40
41
 
41
- it 'filters the list' do
42
- template = %({% with_scope order_by: 'name ASC', active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %})
42
+ describe 'filtering the list' do
43
43
 
44
- @list.expects(:filtered).with({ 'active' => true }, ['name', 'ASC']).returns(%w(a b))
44
+ let(:template) { %({% with_scope order_by: 'name ASC', active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %}) }
45
+
46
+ before { list.expects(:filtered).with({ 'active' => true, '_visible' => true }, ['name', 'ASC']).returns(list.to_a) }
47
+
48
+ it { should eq 'a,b,' }
45
49
 
46
- render(template, { 'category' => @category }).should == 'a,b,'
47
50
  end
48
51
 
49
- it 'filters the list and uses the default order' do
50
- template = %({% with_scope active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %})
52
+ describe 'filtering the list with the default order' do
53
+
54
+ let(:template) { %({% with_scope active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %}) }
55
+
56
+ before { list.expects(:filtered).with({ 'active' => true, '_visible' => true }, nil).returns(list.to_a) }
51
57
 
52
- @list.expects(:filtered).with({ 'active' => true }, nil).returns(%w(a b))
58
+ it { should eq 'a,b,' }
53
59
 
54
- render(template, { 'category' => @category }).should == 'a,b,'
55
60
  end
56
61
 
57
62
  end
@@ -2,31 +2,41 @@ require 'spec_helper'
2
2
 
3
3
  describe Locomotive::Liquid::Drops::Site do
4
4
 
5
- before(:each) do
6
- @site = FactoryGirl.build(:site)
7
- page_1 = FactoryGirl.build(:page, site: @site)
8
- page_2 = FactoryGirl.build(:page, site: @site, title: 'About us', slug: 'about_us')
9
- @site.stubs(:pages).returns([page_1, page_2])
10
- end
5
+ let(:site) { FactoryGirl.create(:site) }
6
+ let(:root_page) { site.pages.root.first }
7
+ let(:about_us_page) { add_page('About us') }
8
+ let(:contact_page) { add_page('Contact') }
9
+
10
+ before { about_us_page && contact_page }
11
+
12
+ describe '.pages' do
13
+
14
+ let(:template) { '' }
15
+ subject { render_template(template) }
11
16
 
12
- context '#pages' do
17
+ describe 'display the number of pages' do
18
+
19
+ let(:template) { '{{ site.pages.size }}' }
20
+ it { should eq '4' }
13
21
 
14
- it 'has access to all the pages' do
15
- render_template('{{ site.pages.size }}').should == '2'
16
22
  end
17
23
 
18
- it 'loops thru the pages' do
19
- render_template('{% for page in site.pages %}{{ page.title }} {% endfor %}').should == 'Home page About us '
24
+ describe 'display the title of all the pages' do
25
+
26
+ let(:template) { '{% for page in site.pages %}{{ page.title }} {% endfor %}' }
27
+ it { should eq 'Home page Page not found About us Contact ' }
28
+
20
29
  end
21
30
 
22
31
  end
23
32
 
24
33
  def render_template(template = '', assigns = {})
25
- assigns = {
26
- 'site' => @site
27
- }.merge(assigns)
34
+ assigns = { 'site' => site }.merge(assigns)
35
+ Liquid::Template.parse(template).render(::Liquid::Context.new({}, assigns, { site: site }))
36
+ end
28
37
 
29
- Liquid::Template.parse(template).render(::Liquid::Context.new({}, assigns, { site: @site }))
38
+ def add_page(title)
39
+ FactoryGirl.create(:page, site: site, parent: root_page, title: title, slug: nil)
30
40
  end
31
41
 
32
42
  end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Locomotive::Liquid::Tags::ModelForm do
4
+
5
+ let(:tag_class) { Locomotive::Liquid::Tags::ModelForm }
6
+
7
+ describe '#display' do
8
+
9
+ let(:tokens) { ['Hello world', '{% endmodel_form %}'] }
10
+ let(:options) { '"articles"' }
11
+ let(:assigns) { {} }
12
+ let(:controller) { stub(request_forgery_protection_token: 'token', form_authenticity_token: '42') }
13
+ let(:context) { Liquid::Context.new({}, assigns, { controller: controller }) }
14
+
15
+ subject { tag_class.new('model_form', options, tokens).render(context) }
16
+
17
+ it { should be == '<form method="POST" enctype="multipart/form-data"><input type="hidden" name="content_type_slug" value="articles" /><input type="hidden" name="token" value="42" />Hello world</form>' }
18
+
19
+ context 'with a css class' do
20
+
21
+ let(:options) { '"articles", class: "col-md-12"' }
22
+
23
+ it { should include '<form method="POST" enctype="multipart/form-data" class="col-md-12">' }
24
+
25
+ end
26
+
27
+ context 'with an id (dom)' do
28
+
29
+ let(:options) { '"articles", id: "my-form"' }
30
+
31
+ it { should include '<form method="POST" enctype="multipart/form-data" id="my-form">' }
32
+
33
+ end
34
+
35
+ context 'using callbacks' do
36
+
37
+ let(:options) { '"articles", success: "/success", error: "/error"' }
38
+
39
+ it { should include '<input type="hidden" name="success_callback" value="/success" />' }
40
+ it { should include '<input type="hidden" name="error_callback" value="/error" />' }
41
+
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -24,47 +24,6 @@ describe Locomotive::Routing::SiteDispatcher do
24
24
 
25
25
  end
26
26
 
27
- describe '#fetch_site' do
28
-
29
- before :each do
30
- @request = Object.new
31
- @site = FactoryGirl.build(:site)
32
-
33
- @controller.stubs(:request).returns(@request)
34
- @request.stubs(:host).returns('host')
35
- @request.stubs(:env).returns({})
36
- end
37
-
38
- it 'returns the current site instance if available' do
39
- @controller.instance_variable_set(:@current_site, @site)
40
- @controller.send(:fetch_site).should == @site
41
- end
42
-
43
- it 'returns the site with matching domain if there is no current site instance' do
44
- Locomotive::Site.expects(:match_domain).with('host').returns([@site])
45
- @controller.send(:fetch_site).should == @site
46
- end
47
-
48
- end
49
-
50
- describe '#current_site' do
51
-
52
- before :each do
53
- @site = FactoryGirl.build(:site)
54
- end
55
-
56
- it 'returns the current site instance if available' do
57
- @controller.instance_variable_set(:@current_site, @site)
58
- @controller.send(:current_site).should == @site
59
- end
60
-
61
- it 'runs fetch site if no instance is available' do
62
- @controller.stubs(:fetch_site).returns(@site)
63
- @controller.send(:current_site).should == @site
64
- end
65
-
66
- end
67
-
68
27
  describe '#require_site' do
69
28
 
70
29
  context 'when there is a current site' do
@@ -59,7 +59,7 @@ describe Locomotive::Site do
59
59
  end
60
60
 
61
61
  it 'should validate format of domains' do
62
- site = FactoryGirl.build(:site, domains: ['barformat.a', '-foo.net', 'goodformat.superlong'])
62
+ site = FactoryGirl.build(:site, domains: ['barformat.a', '-foo.net', 'goodformat.superlong', 'local.lb-service'])
63
63
  site.should_not be_valid
64
64
  site.errors[:domains].should == ['barformat.a is invalid', '-foo.net is invalid']
65
65
  end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Locomotive::Middlewares::LocaleRedirection' do
4
+
5
+ let(:prefixed) { false }
6
+ let(:site) { FactoryGirl.create('existing site', prefix_default_locale: prefixed, locales: %w(de fr)) }
7
+ let(:url) { 'http://models.example.com' }
8
+ let(:app) { ->(env) { [200, env, "app"] } }
9
+ let(:middleware) { Locomotive::Middlewares::LocaleRedirection.new(app) }
10
+ let(:locale) { 'de' }
11
+
12
+ subject do
13
+ code, env = middleware.call(env_for(url, 'locomotive.site' => site, 'locomotive.locale' => locale))
14
+ [code, env['Location']]
15
+ end
16
+
17
+ describe 'not prefixed by locale' do
18
+
19
+ describe 'strip default locale from root path' do
20
+ let(:url) { 'http://models.example.com/de' }
21
+ it { should eq [301, 'http://models.example.com'] }
22
+ end
23
+
24
+ describe 'strip default locale' do
25
+ let(:url) { 'http://models.example.com/de/hello' }
26
+ it { should eq [301, 'http://models.example.com/hello'] }
27
+ end
28
+
29
+ describe 'strip default locale from root path with query' do
30
+ let(:url) { 'http://models.example.com/de?this=is_a_param' }
31
+ it { should eq [301, 'http://models.example.com?this=is_a_param'] }
32
+ end
33
+
34
+ describe 'strip default locale from path with query' do
35
+ let(:url) { 'http://models.example.com/de/hello?this=is_a_param' }
36
+ it { should eq [301, 'http://models.example.com/hello?this=is_a_param'] }
37
+ end
38
+
39
+ describe 'dont strip a non-default locale' do
40
+ let(:locale) { 'fr' }
41
+ let(:url) { 'http://models.example.com/fr/hello' }
42
+ it { should eq [200, nil] }
43
+ end
44
+
45
+ describe 'dont redirect URL without locale' do
46
+ let(:locale) { nil }
47
+ let(:url) { 'http://models.example.com/hello' }
48
+ it { should eq [200, nil] }
49
+ end
50
+
51
+ end
52
+
53
+
54
+
55
+
56
+ describe 'prefixed by locale' do
57
+
58
+ let(:prefixed) { true }
59
+
60
+ describe 'without locale' do
61
+
62
+ let(:locale) { nil }
63
+
64
+ describe 'add default locale to root path' do
65
+ let(:url) { 'http://models.example.com/' }
66
+ it { should eq [301, 'http://models.example.com/de'] }
67
+ end
68
+
69
+ describe 'add default locale to long path' do
70
+ let(:url) { 'http://models.example.com/hello/world' }
71
+ it { should eq [301, 'http://models.example.com/de/hello/world'] }
72
+ end
73
+
74
+ describe 'add default locale to url with path and query' do
75
+ let(:url) { 'http://models.example.com/hello/world?this=is_me' }
76
+ it { should eq [301, 'http://models.example.com/de/hello/world?this=is_me'] }
77
+ end
78
+
79
+ describe 'dont add default locale to backoffice' do
80
+ let(:url) { 'http://models.example.com/locomotive' }
81
+ it { should eq [200, nil] }
82
+ end
83
+
84
+ describe 'dont add default locale to assets' do
85
+ let(:url) { 'http://models.example.com/assets/locomotive.css?body=1' }
86
+ it { should eq [200, nil] }
87
+ end
88
+
89
+ end
90
+
91
+ describe 'with locale' do
92
+
93
+ describe 'dont add default locale if already present' do
94
+ let(:locale) { 'de' }
95
+ let(:url) { 'http://models.example.com/de/hello/world' }
96
+ it { should eq [200, nil] }
97
+ end
98
+
99
+ describe 'dont add default locale to localized path' do
100
+ let(:locale) { 'fr' }
101
+ let(:url) { 'http://models.example.com/fr/hello/world' }
102
+ it { should eq [200, nil] }
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+
109
+ end