add validations to site

This commit is contained in:
dinedine 2010-04-10 17:25:07 +02:00
parent ff6fcf43f1
commit 3b8a6c67df
12 changed files with 169 additions and 25 deletions

View File

@ -15,10 +15,10 @@ gem "devise", ">= 1.1.rc0"
# Development environment
group :development do
# Using mongrel instead of webrick (default server)
gem "mongrel"
gem "cgi_multipart_eof_fix"
gem "fastthread"
gem "mongrel_experimental"
# gem "mongrel"
# gem "cgi_multipart_eof_fix"
# gem "fastthread"
# gem "mongrel_experimental"
end
group :test do

View File

@ -4,29 +4,51 @@ class Site
## fields ##
field :name
field :subdomain, :type => String
field :domains, :type => Array, :default => []
## validations ##
validates_presence_of :name
validates_length_of :domains, :minimum => 1
# validates_each :domains, :logic => :domains_are_unique_and_valid
validates_presence_of :name, :subdomain
validates_uniqueness_of :subdomain
validates_exclusion_of :subdomain, :in => Locomotive::Configuration.forbidden_subdomains
validates_format_of :subdomain, :with => Locomotive::Regexps::SUBDOMAIN, :allow_blank => true
validate :domains_must_be_valid_and_unique
## callbacks ##
before_save :add_subdomain_to_domains
## named scopes ##
named_scope :match_domain, lambda { |domain| { :where => { :domains => domain } } }
named_scope :match_domain_with_exclusion_of, lambda { |domain, site| { :where => { :domains => domain, :id.ne => site.id } } }
## behaviours ##
# timestamps!
add_dirty_methods :domains
## methods ##
def subdomain=(value)
return if value.blank?
(self.domains << "#{value}.#{Locomotive::Configuration.default_domain_name}").uniq!
def add_subdomain_to_domains
self.domains ||= []
(self.domains << "#{self.subdomain}.#{Locomotive::Configuration.default_domain}").uniq!
end
def domains_without_subdomain
(self.domains || []) - ["#{self.subdomain}.#{Locomotive::Configuration.default_domain}"]
end
protected
def domains_are_unique_and_valid
# self.domains.each do |domain|
# self.errors.add(:domains, t())
# end
def domains_must_be_valid_and_unique
return if self.domains.empty? || (!self.new_record? && !self.domains_changed?)
(self.domains_without_subdomain - (self.domains_was || [])) .each do |domain|
if not self.class.match_domain_with_exclusion_of(domain, self).first.nil?
self.errors.add(:domains, :domain_taken, :value => domain)
end
if not domain =~ Locomotive::Regexps::DOMAIN
self.errors.add(:domains, :invalid_domain, :value => domain)
end
end
end
end

View File

@ -1,3 +1,3 @@
Locomotive::Configuration.setup do |config|
config.default_domain_name = 'example.com'
config.default_domain = 'example.com'
end

View File

@ -0,0 +1,2 @@
en:
hello: "Hello world"

View File

@ -0,0 +1,2 @@
fr:
hello: 'Bonjour le monde'

View File

@ -0,0 +1,5 @@
en:
errors:
messages:
domain_taken: "{{value}} is already taken"
invalid_domain: "{{value}} is invalid"

View File

@ -0,0 +1,29 @@
fr:
errors:
# The default format use in full error messages.
format: "{{attribute}} {{message}}"
# The values :model, :attribute and :value are always available for interpolation
# The value :count is available when applicable. Can be used for pluralization.
messages:
inclusion: "n'est pas inclus(e) dans la liste"
exclusion: "n'est pas disponible"
invalid: "n'est pas valide"
confirmation: "ne concorde pas avec la confirmation"
accepted: "doit être accepté(e)"
empty: "doit être rempli(e)"
blank: "doit être rempli(e)"
too_long: "est trop long (pas plus de {{count}} caractères)"
too_short: "est trop court (au moins {{count}} caractères)"
wrong_length: "ne fait pas la bonne longueur (doit comporter {{count}} caractères)"
taken: "n'est pas disponible"
not_a_number: "n'est pas un nombre"
greater_than: "doit être supérieur à {{count}}"
greater_than_or_equal_to: "doit être supérieur ou égal à {{count}}"
equal_to: "doit être égal à {{count}}"
less_than: "doit être inférieur à {{count}}"
less_than_or_equal_to: "doit être inférieur ou égal à {{count}}"
odd: "doit être impair"
even: "doit être pair"
domain_taken: "{{value}} a été déjà pris"

View File

@ -1,5 +0,0 @@
# Sample localization file for English. Add more files in this directory for other locales.
# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
en:
hello: "Hello world"

16
doc/site.txt Normal file
View File

@ -0,0 +1,16 @@
h1. Sites
Site is the parent model of all pages, assets, ...etc.
h2. Subdomain
A site must have a subdomain in case of all the other domains are not reachable (dns problems, ...etc).
h2. Domains
When a request reaches the application, the site dispatcher method looks for a site responding to the domain name specified in the request. New domains can be added further by the administrator of the site.
The very first domain is the one built from the subdomain.
A site must own at least one domain.
*Note:* domains like www.example.com and example.com are equals

View File

@ -22,7 +22,8 @@ module Locomotive
class Configuration
DEFAULT_SETTINGS = {
:default_domain_name => 'localhost'
:default_domain => 'localhost',
:forbidden_subdomains => %w{www admin email blog webmail mail support help site sites}
}
cattr_accessor :settings

View File

@ -0,0 +1,6 @@
module Locomotive
module Regexps
SUBDOMAIN = /^[a-z][a-z0-9_]*[a-z0-9]{1}$/
DOMAIN = /^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
end
end

View File

@ -14,11 +14,77 @@ describe Site do
site.errors[:name].should == ["can't be blank"]
end
it 'should have a domain at minimum' do
it 'should validate presence of subdomain' do
site = Factory.build(:site, :subdomain => nil)
site.should_not be_valid
site.domains = %w{acme.net}
site.should be_valid
site.errors[:subdomain].should == ["can't be blank"]
end
%w{test foo_bar test42}.each do |subdomain|
it "should accept subdomain like '#{subdomain}'" do
Factory.build(:site, :subdomain => subdomain).should be_valid
end
end
['-', '_test', 'test_', 't est', '42', '42test'].each do |subdomain|
it "should not accept subdomain like '#{subdomain}'" do
(site = Factory.build(:site, :subdomain => subdomain)).should_not be_valid
site.errors[:subdomain].should == ['is invalid']
end
end
it "should not use reserved keywords as subdomain" do
%w{www admin email blog webmail mail support help site sites}.each do |subdomain|
(site = Factory.build(:site, :subdomain => subdomain)).should_not be_valid
site.errors[:subdomain].should == ['is reserved']
end
end
it 'should validate uniqueness of subdomain' do
Factory(:site)
(site = Factory.build(:site)).should_not be_valid
site.errors[:subdomain].should == ["is already taken"]
end
it 'should validate uniqueness of domains' do
Factory(:site, :domains => %w{www.acme.net www.acme.com})
(site = Factory.build(:site, :domains => %w{www.acme.com})).should_not be_valid
site.errors[:domains].should == ["www.acme.com is already taken"]
end
it 'should validate format of domains' do
site = Factory.build(:site, :domains => ['barformat.superlongextension', '-foo.net'])
site.should_not be_valid
site.errors[:domains].should == ['barformat.superlongextension is invalid', '-foo.net is invalid']
end
## Named scopes ##
it 'should retrieve sites by domain' do
site_1 = Factory(:site, :domains => %w{www.acme.net})
site_2 = Factory(:site, :subdomain => 'test', :domains => %w{www.example.com})
sites = Site.match_domain('www.acme.net')
sites.size.should == 1
sites.first.should == site_1
sites = Site.match_domain('www.example.com')
sites.size.should == 1
sites.first.should == site_2
sites = Site.match_domain('test.example.com')
sites.size.should == 1
sites.first.should == site_2
sites = Site.match_domain('www.unknown.com')
sites.should be_empty
end
## Methods ##
it 'should return domains without subdomain' do
site = Factory(:site, :domains => %w{www.acme.net www.acme.com})
site.domains.should == %w{www.acme.net www.acme.com acme.example.com}
site.domains_without_subdomain.should == %w{www.acme.net www.acme.com}
end
end