Skip to content

Loading…

Allow for unicode alphanumeric characters in page URL slugs with some validation changes and escaping #172

Merged
merged 2 commits into from

2 participants

@ericisaiah

Example: website.com/es/acción (note the accented o). Currently, that is failing validation. These slugs need to pass validation, but then still be escaped as ASCII in the db since URLs only support ASCII characters.

@GBH GBH merged commit bd590f5 into comfy:master
@GBH
Comfy Projects member
GBH commented

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 4, 2012
  1. Allow for unicode alphanumeric characters in page URL slugs with some…

    Eric Lukoff committed
    … validation changes and escaping.
This page is out of date. Refresh to see the latest.
Showing with 35 additions and 2 deletions.
  1. +16 −2 app/models/cms/page.rb
  2. +19 −0 test/unit/models/page_test.rb
View
18 app/models/cms/page.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
class Cms::Page < ActiveRecord::Base
ComfortableMexicanSofa.establish_connection(self)
@@ -24,10 +25,12 @@ class Cms::Page < ActiveRecord::Base
# -- Callbacks ------------------------------------------------------------
before_validation :assigns_label,
:assign_parent
+ after_validation :escape_slug
before_create :assign_position
before_save :assign_full_path,
:set_cached_content
after_save :sync_child_pages
+ after_find :unescape_slug_and_path
# -- Validations ----------------------------------------------------------
validates :site_id,
@@ -36,7 +39,7 @@ class Cms::Page < ActiveRecord::Base
:presence => true
validates :slug,
:presence => true,
- :format => /^\w[\.a-z0-9_-]*$/i,
+ :format => /^\p{Alnum}[\.\p{Alnum}_-]*$/i,
:uniqueness => { :scope => :parent_id },
:unless => lambda{ |p| p.site && (p.site.pages.count == 0 || p.site.pages.root == self) }
validates :layout,
@@ -139,7 +142,7 @@ def assign_parent
end
def assign_full_path
- self.full_path = self.parent ? "#{self.parent.full_path}/#{self.slug}".squeeze('/') : '/'
+ self.full_path = self.parent ? "#{CGI::escape(self.parent.full_path).gsub('%2F', '/')}/#{self.slug}".squeeze('/') : '/'
end
def assign_position
@@ -166,5 +169,16 @@ def set_cached_content
def sync_child_pages
children.each{ |p| p.save! } if full_path_changed?
end
+
+ # Escape slug unless it's nonexistent (root)
+ def escape_slug
+ self.slug = CGI::escape(self.slug) unless self.slug.nil?
+ end
+
+ # Unescape the slug and full path back into their original forms unless they're nonexistent
+ def unescape_slug_and_path
+ self.slug = CGI::unescape(self.slug) unless self.slug.nil?
+ self.full_path = CGI::unescape(self.full_path) unless self.full_path.nil?
+ end
end
View
19 test/unit/models/page_test.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
require File.expand_path('../../test_helper', File.dirname(__FILE__))
class CmsPageTest < ActiveSupport::TestCase
@@ -51,6 +52,9 @@ def test_validation_of_slug
page.slug = 'inva lid'
assert page.invalid?
+
+ page.slug = 'acción'
+ assert page.valid?
end
def test_label_assignment
@@ -204,6 +208,21 @@ def test_url
assert_equal 'http://test.host/', cms_pages(:default).url
assert_equal 'http://test.host/child-page', cms_pages(:child).url
end
+
+ def test_unicode_slug_escaping
+ page = cms_pages(:child)
+ page_1 = cms_sites(:default).pages.create!(new_params(:parent => page, :slug => 'tést-ünicode-slug'))
+ assert_equal CGI::escape('tést-ünicode-slug'), page_1.slug
+ assert_equal CGI::escape('/child-page/tést-ünicode-slug').gsub('%2F', '/'), page_1.full_path
+ end
+
+ def test_unicode_slug_unescaping
+ page = cms_pages(:child)
+ page_1 = cms_sites(:default).pages.create!(new_params(:parent => page, :slug => 'tést-ünicode-slug'))
+ found_page = cms_sites(:default).pages.where(:slug => CGI::escape('tést-ünicode-slug')).first
+ assert_equal 'tést-ünicode-slug', found_page.slug
+ assert_equal '/child-page/tést-ünicode-slug', found_page.full_path
+ end
protected
Something went wrong with that request. Please try again.