This commit is contained in:
dinedine 2010-08-02 16:16:08 +02:00
commit c76cd6527c
44 changed files with 754 additions and 173 deletions

22
Gemfile
View File

@ -4,13 +4,16 @@ source 'http://rubygems.org'
gem 'rails', '3.0.0.rc' gem 'rails', '3.0.0.rc'
gem 'liquid', '2.0.0' gem 'liquid', '2.0.0'
# i think we'll need to fork our templating language
# gem 'locomotive-liquid'
gem 'bson_ext', '>= 1.0.1' gem 'bson_ext', '>= 1.0.1'
gem 'mongoid', '2.0.0.beta.15' gem 'mongoid', :git => "git://github.com/durran/mongoid.git", :ref => "e387a0d1dc74da057472"
gem 'mongoid_acts_as_tree', '0.1.5' gem 'mongoid_acts_as_tree', '0.1.5'
gem 'mongo_session_store', '2.0.0.pre' gem 'mongo_session_store', '2.0.0.pre'
gem 'warden' gem 'warden'
gem 'devise', '1.1.rc2' gem 'devise', :git => "git://github.com/plataformatec/devise.git"
gem 'haml', '3.0.13' gem 'haml', '3.0.15'
gem 'rmagick', '2.12.2' gem 'rmagick', '2.12.2'
gem 'aws' gem 'aws'
gem 'mimetype-fu', :require => 'mimetype_fu' gem 'mimetype-fu', :require => 'mimetype_fu'
@ -29,7 +32,6 @@ group :development do
gem 'mongrel' gem 'mongrel'
gem 'cgi_multipart_eof_fix' gem 'cgi_multipart_eof_fix'
gem 'fastthread' gem 'fastthread'
# gem 'mongrel_experimental'
end end
group :test, :development do group :test, :development do
@ -37,11 +39,17 @@ group :test, :development do
end end
group :test do group :test do
gem 'autotest' gem "autotest"
gem 'rspec-rails', '2.0.0.beta.18' gem "growl-glue"
gem 'rspec-rails', '2.0.0.beta.19'
gem 'factory_girl_rails' gem 'factory_girl_rails'
gem "pickle", :git => "http://github.com/codegram/pickle.git"
gem "pickle-mongoid"
gem 'capybara' gem 'capybara'
gem 'capybara-envjs', '>= 0.1.5'
# would be nice..
# gem "capybara-envjs"
gem 'database_cleaner' gem 'database_cleaner'
gem 'cucumber' gem 'cucumber'
gem 'cucumber-rails' gem 'cucumber-rails'

View File

@ -1,3 +1,9 @@
GIT
remote: git://github.com/durran/mongoid.git
revision: e387a0d
ref: e387a0d1dc74da057472
specs:
GIT GIT
remote: git://github.com/floehopper/mocha.git remote: git://github.com/floehopper/mocha.git
revision: d1715ff revision: d1715ff
@ -5,6 +11,20 @@ GIT
mocha (0.9.8.20090918115329) mocha (0.9.8.20090918115329)
rake rake
GIT
remote: git://github.com/plataformatec/devise.git
revision: 01c272c
specs:
devise (1.2.0)
bcrypt-ruby (~> 2.1.2)
warden (~> 0.10.7)
GIT
remote: http://github.com/codegram/pickle.git
revision: 2834204
specs:
pickle (0.3.0)
GEM GEM
remote: http://rubygems.org/ remote: http://rubygems.org/
specs: specs:
@ -55,9 +75,6 @@ GEM
rack (>= 1.0.0) rack (>= 1.0.0)
rack-test (>= 0.5.4) rack-test (>= 0.5.4)
selenium-webdriver (>= 0.0.3) selenium-webdriver (>= 0.0.3)
capybara-envjs (0.1.6)
capybara (>= 0.3.9)
envjs (>= 0.3.7)
carrierwave (0.5.0.beta2) carrierwave (0.5.0.beta2)
activesupport (>= 3.0.0.beta4) activesupport (>= 3.0.0.beta4)
cgi_multipart_eof_fix (2.5.0) cgi_multipart_eof_fix (2.5.0)
@ -75,12 +92,7 @@ GEM
culerity (0.2.10) culerity (0.2.10)
daemons (1.1.0) daemons (1.1.0)
database_cleaner (0.5.2) database_cleaner (0.5.2)
devise (1.1.rc2)
bcrypt-ruby (~> 2.1.2)
warden (~> 0.10.7)
diff-lcs (1.1.2) diff-lcs (1.1.2)
envjs (0.3.7)
johnson (>= 2.0.0.pre3)
erubis (2.6.6) erubis (2.6.6)
abstract (>= 1.0.0) abstract (>= 1.0.0)
factory_girl (1.3.1) factory_girl (1.3.1)
@ -98,7 +110,8 @@ GEM
gherkin (2.1.5) gherkin (2.1.5)
trollop (~> 1.16.2) trollop (~> 1.16.2)
git (1.2.5) git (1.2.5)
haml (3.0.13) growl-glue (1.0.7)
haml (3.0.15)
has_scope (0.5.0) has_scope (0.5.0)
heroku (1.9.13) heroku (1.9.13)
json_pure (>= 1.2.0, < 1.5.0) json_pure (>= 1.2.0, < 1.5.0)
@ -115,8 +128,6 @@ GEM
gemcutter (>= 0.1.0) gemcutter (>= 0.1.0)
git (>= 1.2.5) git (>= 1.2.5)
rubyforge (>= 2.0.0) rubyforge (>= 2.0.0)
johnson (2.0.0.pre3)
stackdeck (~> 0.2)
json_pure (1.4.3) json_pure (1.4.3)
launchy (0.3.7) launchy (0.3.7)
configuration (>= 0.0.5) configuration (>= 0.0.5)
@ -148,6 +159,9 @@ GEM
fastthread (>= 1.0.1) fastthread (>= 1.0.1)
gem_plugin (>= 0.2.3) gem_plugin (>= 0.2.3)
nokogiri (1.4.3.1) nokogiri (1.4.3.1)
pickle-mongoid (0.1.6)
mongoid (>= 2.0.0.beta.7)
pickle (>= 0.3.0)
polyglot (0.3.1) polyglot (0.3.1)
rack (1.2.1) rack (1.2.1)
rack-mount (0.6.9) rack-mount (0.6.9)
@ -180,9 +194,9 @@ GEM
rspec-expectations (2.0.0.beta.19) rspec-expectations (2.0.0.beta.19)
diff-lcs (>= 1.1.2) diff-lcs (>= 1.1.2)
rspec-mocks (2.0.0.beta.19) rspec-mocks (2.0.0.beta.19)
rspec-rails (2.0.0.beta.18) rspec-rails (2.0.0.beta.19)
rspec (>= 2.0.0.beta.14) rspec (= 2.0.0.beta.19)
webrat (>= 0.7.0) webrat (>= 0.7.2.beta.1)
ruby-debug (0.10.3) ruby-debug (0.10.3)
columnize (>= 0.1) columnize (>= 0.1)
ruby-debug-base (~> 0.10.3.0) ruby-debug-base (~> 0.10.3.0)
@ -196,7 +210,6 @@ GEM
json_pure json_pure
rubyzip rubyzip
spork (0.8.4) spork (0.8.4)
stackdeck (0.2.0)
term-ansicolor (1.0.5) term-ansicolor (1.0.5)
thor (0.14.0) thor (0.14.0)
treetop (1.4.8) treetop (1.4.8)
@ -206,7 +219,7 @@ GEM
uuidtools (2.1.1) uuidtools (2.1.1)
warden (0.10.7) warden (0.10.7)
rack (>= 1.0.0) rack (>= 1.0.0)
webrat (0.7.1) webrat (0.7.2.beta.1)
nokogiri (>= 1.2.0) nokogiri (>= 1.2.0)
rack (>= 1.0) rack (>= 1.0)
rack-test (>= 0.5.3) rack-test (>= 0.5.3)
@ -223,17 +236,17 @@ DEPENDENCIES
aws aws
bson_ext (>= 1.0.1) bson_ext (>= 1.0.1)
capybara capybara
capybara-envjs (>= 0.1.5)
carrierwave (= 0.5.0.beta2) carrierwave (= 0.5.0.beta2)
cgi_multipart_eof_fix cgi_multipart_eof_fix
cucumber cucumber
cucumber-rails cucumber-rails
database_cleaner database_cleaner
devise (= 1.1.rc2) devise!
factory_girl_rails factory_girl_rails
fastthread fastthread
formtastic-rails3 (= 1.0.0.beta3) formtastic-rails3 (= 1.0.0.beta3)
haml (= 3.0.13) growl-glue
haml (= 3.0.15)
heroku heroku
httparty (= 0.6.1) httparty (= 0.6.1)
inherited_resources (= 1.1.2) inherited_resources (= 1.1.2)
@ -243,12 +256,14 @@ DEPENDENCIES
mimetype-fu mimetype-fu
mocha! mocha!
mongo_session_store (= 2.0.0.pre) mongo_session_store (= 2.0.0.pre)
mongoid (= 2.0.0.beta.15) mongoid!
mongoid_acts_as_tree (= 0.1.5) mongoid_acts_as_tree (= 0.1.5)
mongrel mongrel
pickle!
pickle-mongoid
rails (= 3.0.0.rc) rails (= 3.0.0.rc)
rmagick (= 2.12.2) rmagick (= 2.12.2)
rspec-rails (= 2.0.0.beta.18) rspec-rails (= 2.0.0.beta.19)
ruby-debug ruby-debug
spork spork
warden warden

View File

@ -7,7 +7,7 @@ require 'rake'
require 'rake/testtask' require 'rake/testtask'
require 'rake/rdoctask' require 'rake/rdoctask'
Rails::Application.load_tasks Locomotive::Application.load_tasks
begin begin
require "jeweler" require "jeweler"

View File

@ -1,12 +1,11 @@
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
protect_from_forgery protect_from_forgery
# rescue_from Exception, :with => :render_error protected
private rescue_from Exception, :with => :render_error
def render_error(exception) def render_error
ActionDispatch::ShowExceptions.new(self).send(:log_error, exception) # TODO: find a better way to access log_error
render :template => "/admin/errors/500", :layout => 'admin/box', :status => 500 render :template => "/admin/errors/500", :layout => 'admin/box', :status => 500
end end
end end

View File

@ -7,7 +7,7 @@ class AssetCollection
field :slug field :slug
## associations ## ## associations ##
belongs_to_related :site referenced_in :site
embeds_many :assets embeds_many :assets
## behaviours ## ## behaviours ##

View File

@ -23,7 +23,7 @@ class ContentInstance
before_create :add_to_list_bottom before_create :add_to_list_bottom
## named scopes ## ## named scopes ##
named_scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb
## methods ## ## methods ##

View File

@ -12,7 +12,7 @@ class ContentType
field :api_enabled, :type => Boolean, :default => false field :api_enabled, :type => Boolean, :default => false
## associations ## ## associations ##
belongs_to_related :site referenced_in :site
embeds_many :contents, :class_name => 'ContentInstance' do embeds_many :contents, :class_name => 'ContentInstance' do
def visible def visible
@target.find_all { |c| c.visible? } @target.find_all { |c| c.visible? }

View File

@ -6,9 +6,11 @@ module Models
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
before_validation do |p|
before_create { |p| p.parts << PagePart.build_body_part if p.parts.empty? } if p.parts.empty?
p.parts << PagePart.build_body_part(p.respond_to?(:body) ? p.body : nil)
end
end
end end
module InstanceMethods module InstanceMethods

View File

@ -7,7 +7,7 @@ module Models
included do included do
belongs_to_related :content_type referenced_in :content_type
field :templatized, :type => Boolean, :default => false field :templatized, :type => Boolean, :default => false

View File

@ -1,7 +1,7 @@
class Layout < LiquidTemplate class Layout < LiquidTemplate
## associations ## ## associations ##
has_many_related :pages references_many :pages
embeds_many :parts, :class_name => 'PagePart' embeds_many :parts, :class_name => 'PagePart'
## callbacks ## ## callbacks ##

View File

@ -8,7 +8,7 @@ class LiquidTemplate
field :value field :value
## associations ## ## associations ##
belongs_to_related :site referenced_in :site
## callbacks ## ## callbacks ##
before_validation :normalize_slug before_validation :normalize_slug

View File

@ -6,7 +6,7 @@ class Membership
field :admin, :type => Boolean, :default => false field :admin, :type => Boolean, :default => false
## associations ## ## associations ##
belongs_to_related :account referenced_in :account
embedded_in :site, :inverse_of => :memberships embedded_in :site, :inverse_of => :memberships
## validations ## ## validations ##

View File

@ -15,9 +15,12 @@ class Page
field :published, :type => Boolean, :default => false field :published, :type => Boolean, :default => false
field :cache_strategy, :default => 'none' field :cache_strategy, :default => 'none'
# allows newly pages to have a default body
attr_accessor :body
## associations ## ## associations ##
belongs_to_related :site referenced_in :site
belongs_to_related :layout referenced_in :layout
embeds_many :parts, :class_name => 'PagePart' embeds_many :parts, :class_name => 'PagePart'
## callbacks ## ## callbacks ##
@ -31,10 +34,10 @@ class Page
validates_exclusion_of :slug, :in => Locomotive.config.reserved_slugs, :if => Proc.new { |p| p.depth == 0 } validates_exclusion_of :slug, :in => Locomotive.config.reserved_slugs, :if => Proc.new { |p| p.depth == 0 }
## named scopes ## ## named scopes ##
named_scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb
named_scope :index, :where => { :slug => 'index', :depth => 0 } scope :index, :where => { :slug => 'index', :depth => 0 }
named_scope :not_found, :where => { :slug => '404', :depth => 0 } scope :not_found, :where => { :slug => '404', :depth => 0 }
named_scope :published, :where => { :published => true } scope :published, :where => { :published => true }
## behaviours ## ## behaviours ##
liquify_template :joined_parts liquify_template :joined_parts

View File

@ -16,7 +16,7 @@ class PagePart
validates_presence_of :name, :slug validates_presence_of :name, :slug
## named scopes ## ## named scopes ##
named_scope :enabled, where(:disabled => false) scope :enabled, where(:disabled => false)
## methods ## ## methods ##
@ -24,10 +24,10 @@ class PagePart
"{% capture content_for_#{self.slug} %}#{self.value}{% endcapture %}" "{% capture content_for_#{self.slug} %}#{self.value}{% endcapture %}"
end end
def self.build_body_part def self.build_body_part(body_content = nil)
self.new({ self.new({
:name => I18n.t('attributes.defaults.page_parts.name'), :name => I18n.t('attributes.defaults.page_parts.name'),
:value => I18n.t('attributes.defaults.pages.other.body'), :value => body_content || I18n.t('attributes.defaults.pages.other.body'),
:slug => 'layout' :slug => 'layout'
}) })
end end

View File

@ -10,12 +10,12 @@ class Site
field :meta_description field :meta_description
## associations ## ## associations ##
has_many_related :pages references_many :pages
has_many_related :layouts references_many :layouts
has_many_related :snippets references_many :snippets
has_many_related :theme_assets references_many :theme_assets
has_many_related :asset_collections references_many :asset_collections
has_many_related :content_types references_many :content_types
embeds_many :memberships embeds_many :memberships
## validations ## ## validations ##
@ -31,8 +31,8 @@ class Site
after_destroy :destroy_in_cascade! after_destroy :destroy_in_cascade!
## named scopes ## ## named scopes ##
named_scope :match_domain, lambda { |domain| { :where => { :domains => domain } } } 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 } } } scope :match_domain_with_exclusion_of, lambda { |domain, site| { :where => { :domains => domain, :_id.ne => site.id } } }
## methods ## ## methods ##
@ -82,7 +82,8 @@ class Site
self.pages.create({ self.pages.create({
:slug => slug, :slug => slug,
:title => I18n.t("attributes.defaults.pages.#{slug}.title"), :title => I18n.t("attributes.defaults.pages.#{slug}.title"),
:body => I18n.t("attributes.defaults.pages.#{slug}.body") :body => I18n.t("attributes.defaults.pages.#{slug}.body"),
:published => true
}) })
end end
end end

View File

@ -15,7 +15,7 @@ class ThemeAsset
mount_uploader :source, ThemeAssetUploader mount_uploader :source, ThemeAssetUploader
## associations ## ## associations ##
belongs_to_related :site referenced_in :site
## callbacks ## ## callbacks ##
before_validation :sanitize_slug before_validation :sanitize_slug

View File

@ -33,6 +33,7 @@
%ul{ :id => "parts" } %ul{ :id => "parts" }
= f.fields_for :parts do |g| = f.fields_for :parts do |g|
%li{ :style => "#{'display: none' if g.object.disabled?}" } %li{ :style => "#{'display: none' if g.object.disabled?}" }
= g.label :value, g.object.name, :style => "display:none"
%code= g.text_area :value %code= g.text_area :value
= g.hidden_field :name = g.hidden_field :name
= g.hidden_field :slug = g.hidden_field :slug

View File

@ -1,2 +1,2 @@
default: features --format pretty --color --tags ~@wip default: features --require features --format pretty --color --tags ~@wip
wip: features --tags @wip wip: features --require features --tags @wip

View File

@ -11,7 +11,6 @@ Locomotive::Application.configure do
# Show full error reports and disable caching # Show full error reports and disable caching
config.consider_all_requests_local = true config.consider_all_requests_local = true
config.action_view.debug_rjs = true
config.action_controller.perform_caching = false config.action_controller.perform_caching = false
# Don't care if the mailer can't send # Don't care if the mailer can't send

View File

@ -121,12 +121,6 @@ Devise.setup do |config|
# are using only default views. # are using only default views.
config.scoped_views = true config.scoped_views = true
# By default, devise detects the role accessed based on the url. So whenever
# accessing "/users/sign_in", it knows you are accessing an User. This makes
# routes as "/sign_in" not possible, unless you tell Devise to use the default
# scope, setting true below.
config.use_default_scope = true
# Configure the default scope used by Devise. By default it's the first devise # Configure the default scope used by Devise. By default it's the first devise
# role declared in your routes. # role declared in your routes.
config.default_scope = :account config.default_scope = :account

View File

@ -1,5 +1,5 @@
# Locomotive::Application.routes.draw do |map| # Locomotive::Application.routes.draw do |map|
Rails.application.routes.draw do |map| Rails.application.routes.draw do
constraints(Locomotive::Routing::DefaultConstraint) do constraints(Locomotive::Routing::DefaultConstraint) do
root :to => 'home#show' root :to => 'home#show'

139
doc/PICKLE_STEPS Normal file
View File

@ -0,0 +1,139 @@
== API
==== Given steps
"Given <b>a model</b> exists", e.g.
Given a user exists
Given a user: "fred" exists
Given the user exists
"Given <b>a model</b> exists with <b>fields</b>", e.g.
Given a user exists with name: "Fred"
Given a user exists with name: "Fred", activated: false
You can refer to other models in the fields
Given a user exists
And a post exists with author: the user
Given a person: "fred" exists
And a person: "ethel" exists
And a fatherhood exists with parent: user "fred", child: user "ethel"
"Given <b>n models</b> exist", e.g.
Given 10 users exist
"Given <b>n models</b> exist with <b>fields</b>", examples:
Given 10 users exist with activated: false
"Given the following <b>models</b> exist:", examples:
Given the following users exist
| name | activated |
| Fred | false |
| Ethel | true |
==== Then steps
===== Asserting existence of models
"Then <b>a model</b> should exist", e.g.
Then a user should exist
"Then <b>a model</b> should exist with <b>fields</b>", e.g.
Then a user: "fred" should exist with name: "Fred" # we can label the found user for later use
You can use other models, booleans, numerics, and strings as fields
Then a person should exist with child: person "ethel"
Then a user should exist with activated: false
Then a user should exist with activated: true, email: "fred@gmail.com"
"Then <b>n models</b> should exist", e.g.
Then 10 events should exist
"Then <b>n models</b> should exist with <b>fields</b>", e.g.
Then 2 people should exist with father: person "fred"
"Then the following <b>models</b> exist". This allows the creation of multiple models
using a table syntax. Using a column with the singularized name of the model creates a referenceable model. E.g.
Then the following users exist:
| name | activated |
| Freddy | false |
Then the following users exist:
| user | name | activated |
| Fred | Freddy | false |
===== Asserting associations
One-to-one assocs: "Then <b>a model</b> should be <b>other model</b>'s <b>association</b>", e.g.
Then the person: "fred" should be person: "ethel"'s father
Many-to-one assocs: "Then <b>a model</b> should be [in|one of] <b>other model</b>'s <b>association</b>", e.g.
Then the person: "ethel" should be one of person: "fred"'s children
Then the comment should be in the post's comments
===== Asserting predicate methods
"Then <b>a model</b> should [be|have] [a|an] <b>predicate</b>", e.g.
Then the user should have a status # => user.status.should be_present
Then the user should have a stale password # => user.should have_stale_password
Then the car: "batmobile" should be fast # => car.should be_fast
"Then <b>a model</b> should not [be|have] [a|an] <b>predicate</b>", e.g.
Then person: "fred" should not be childless # => fred.should_not be_childless
=== Regexps for use in your own steps
By default you get some regexps available in the main namespace for use
in creating your own steps: `capture_model`, `capture_fields`, and others (see lib/pickle.rb)
(You can use any of the regexps that Pickle uses by using the Pickle.parser namespace, see
Pickle::Parser::Matchers for the methods available)
*capture_model*
Given /^#{capture_model} exists$/ do |model_name|
model(model_name).should_not == nil
end
Then /^I should be at the (.*?) page$/ |page|
if page =~ /#{capture_model}'s/
url_for(model($1))
else
# ...
end
end
Then /^#{capture_model} should be one of #{capture_model}'s posts$/ do |post, forum|
post = model!(post)
forum = model!(forum)
forum.posts.should include(post)
end
*capture_fields*
This is useful for setting attributes, and knows about pickle model names so that you
can build up composite objects with ease
Given /^#{capture_model} exists with #{capture_fields}$/ do |model_name, fields|
create_model(model_name, fields)
end
# example of use
Given a user exists
And a post exists with author: the user # this step will assign the above user as :author on the post

View File

@ -1,2 +0,0 @@
Use this README file to introduce your application and point to useful places in the API for learning more.
Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.

19
doc/autotest_setup Normal file
View File

@ -0,0 +1,19 @@
# ADD THIS to your ~/.autotest
require 'rubygems'
require 'growl_glue'
GrowlGlue::Autotest.initialize
Autotest.add_hook :initialize do |at|
# Ignore files in tmp/
at.add_exception %r%^\./tmp%
at.add_exception %r%^\./sass-cache%
at.add_exception %r%^\./log%
at.add_exception %r%^\./spec/tmp%
at.add_exception %r%^\./doc%
end
# RUN `autotest` in order to autotest your specs
# RUN `AUTOFEATURE=true autotest` in order to autotest your cucumber features

75
doc/feature_list.txt Normal file
View File

@ -0,0 +1,75 @@
General Cucumbering Strategy:
Admin Pages
Contents
Pages
- Create a Page (DONE)
- Create a Sub Page
- Create another Sub Page
- Move Sub Pages around (use Selenium for this)
- Edit a Page (DONE)
- Delete a Page
Models
- Create a New Model
- Add a Few Field Types
- Edit a Model
- Add a New Model Entry
- Delete a Model Entry
Assets
- Create a New Collection
- Edit Custom Fields
- Remove a Collection
- Create an Asset
- Delete an Asset (broken i think)
- Edit an Asset
Settings
Site
- Edit Settings
- Add Access Point
- Remove Access Point
- Add Account
- Remove Account
Layouts
- Add New Layout
- Add Images to Layout
- Assign Layout to a Page
Snippets
- Create new Snippet
- Edit Snippet
- Delete Snippet
- Use Snippet in a Page
Theme files
- Add New Stylesheet
- Edit Stylesheet
- Delete Stylesheet
- Add New Javascript
- Edit Javascript
- Delete Javascript
- Add New Image
- Edit Image
- Delete Image
My Account
- Edit Password
- Edit Email
- Change Language
- Create New Site
Authentication Stuff
- Log In
- Log out
- Forgot password
Rendering Features
- Basic render (DONE)
- using a layout (DONE)
- using a layout with multiple parts (DONE)
- using snippets
- referencing images
- using data models
- loop through data models

View File

@ -1,11 +1,13 @@
@site_up Feature: Cross Domain Authentication
@another_site_up
@authenticated
Feature:
In order to manage a new site I created In order to manage a new site I created
As an administrator signed in another site of mine As an administrator signed in another site of mine
I want to bypass the authentication I want to bypass the authentication
Background:
Given I have the site: "test site" set up
And I have the site: "another site" set up
And I am an authenticated user
Scenario: Successful authentication Scenario: Successful authentication
When I go to pages When I go to pages
Then I should see "Locomotive test website" Then I should see "Locomotive test website"

View File

@ -1,19 +1,21 @@
@site_up
Feature: Login Feature: Login
In order to access locomotive admin panel In order to access locomotive admin panel
As an administrator As an administrator
I want to log in I want to log in
Background:
Given I have the site: "test site" set up
Scenario: Successful authentication Scenario: Successful authentication
When I go to login When I go to login
And I fill in "admin_email" with "admin@locomotiveapp.org" And I fill in "Email" with "admin@locomotiveapp.org"
And I fill in "admin_password" with "easyone" And I fill in "Password" with "easyone"
And I press "Log in" And I press "Log in"
Then I should see "Listing pages" Then I should see "Listing pages"
Scenario: Failed authentication Scenario: Failed authentication
When I go to login When I go to login
And I fill in "admin_email" with "admin@locomotiveapp.org" And I fill in "Email" with "admin@locomotiveapp.org"
And I fill in "admin_password" with "" And I fill in "Password" with ""
And I press "Log in" And I press "Log in"
Then I should not see "Listing pages" Then I should not see "Listing pages"

View File

@ -1,10 +1,12 @@
@site_up Feature: Manage Pages
@authenticated
Feature: Manage Skills
In order to manage pages In order to manage pages
As an administrator As an administrator
I want to add/edit/delete pages of my site I want to add/edit/delete pages of my site
Background:
Given I have the site: "test site" set up
And I am an authenticated user
Scenario: Pages list is not accessible for non authenticated accounts Scenario: Pages list is not accessible for non authenticated accounts
Given I am not authenticated Given I am not authenticated
When I go to pages When I go to pages
@ -16,7 +18,7 @@ Scenario: Creating a valid page
And I fill in "Title" with "Test" And I fill in "Title" with "Test"
And I fill in "Slug" with "test" And I fill in "Slug" with "test"
And I select "Home page" from "Parent" And I select "Home page" from "Parent"
And I fill in "page_parts_attributes_0_value" with "Lorem ipsum...." And I fill in "Body" with "Lorem ipsum...."
And I press "Create" And I press "Create"
Then I should see "Page was successfully created." Then I should see "Page was successfully created."
And I should have "Lorem ipsum...." in the test page layout And I should have "Lorem ipsum...." in the test page layout
@ -25,7 +27,7 @@ Scenario: Updating a valid page
When I go to pages When I go to pages
And I follow "Home page" And I follow "Home page"
And I fill in "Title" with "Home page !" And I fill in "Title" with "Home page !"
And I fill in "page_parts_attributes_0_value" with "My new content is here" And I fill in "Body" with "My new content is here"
And I press "Update" And I press "Update"
Then I should see "Page was successfully updated." Then I should see "Page was successfully updated."
And I should have "My new content is here" in the index page layout And I should have "My new content is here" in the index page layout

View File

@ -0,0 +1,88 @@
Feature: Engine
As a website user
I want to be able to view someones created locomotive pages
Background:
Given I have the site: "test site" set up
Scenario: Simple Page
Given a simple page named "hello-world" with the body:
"""
Hello World
"""
When I view the rendered page at "/hello-world"
Then the rendered output should look like:
"""
Hello World
"""
Scenario: Simple Page with layout
Given a layout named "above_and_below" with the source:
"""
<div class="header"></div>
{{ content_for_layout }}
<div class="footer"></div>
"""
And a page named "hello-world-with-layout" with the layout "above_and_below" and the body:
"""
Hello World
"""
When I view the rendered page at "/hello-world-with-layout"
Then the rendered output should look like:
"""
<div class="header"></div>
Hello World
<div class="footer"></div>
"""
Scenario: Page with Parts
Given a layout named "layout_with_sidebar" with the source:
"""
<div class="header"></div>
<div class="content">
<div class="sidebar">{{ content_for_sidebar }}</div>
<div class="body">
{{ content_for_layout }}
</div>
</div>
<div class="footer"></div>
"""
And a page named "hello-world-multipart" with the layout "layout_with_sidebar" and the body:
"""
IM IN UR BODY OUTPUTTING SUM CODEZ!!
"""
And the page named "hello-world-multipart" has the part "sidebar" with the content:
"""
IM IN UR SIDEBAR PUTTING OUT LINKZ
"""
When I view the rendered page at "/hello-world-multipart"
Then the rendered output should look like:
"""
<div class="header"></div>
<div class="content">
<div class="sidebar">IM IN UR SIDEBAR PUTTING OUT LINKZ</div>
<div class="body">
IM IN UR BODY OUTPUTTING SUM CODEZ!!
</div>
</div>
<div class="footer"></div>
"""
@wip
Scenario: Simple Page with Admin Inline Editing
Given a simple page named "hello-world-inline" with the body:
"""
{% block hello %}Hello World{% endblock %}
"""
When And I'm an admin
And I view the rendered page at "/hello-world-inline"
Then the rendered output shoud look like:
"""
<div class="inline-editing" data-url="/admin/parts/XXXX" data-title="hello">Hello World</div>
"""

View File

@ -1,27 +1,13 @@
Before('@site_up') do
create_site_and_admin_account
create_layout_samples
end
Before('@another_site_up') do
add_new_site
end
Before('@authenticated') do
Given %{I am an authenticated user}
end
### Authentication ### Authentication
Given /^I am not authenticated$/ do Given /^I am not authenticated$/ do
visit('/admin/sign_out') visit('/admin/sign_out')
end end
Given /^I am an authenticated user$/ do Given /^I am an authenticated user$/ do
Given %{I go to login} Given %{I go to login}
And %{I fill in "admin_email" with "admin@locomotiveapp.org"} And %{I fill in "Email" with "admin@locomotiveapp.org"}
And %{I fill in "admin_password" with "easyone"} And %{I fill in "Password" with "easyone"}
And %{I press "Log in"} And %{I press "Log in"}
end end
@ -32,16 +18,6 @@ Then /^I am redirected to "([^\"]*)"$/ do |url|
visit location visit location
end end
### Pages
Then /^I should have "(.*)" in the (.*) page (.*)$/ do |content, page_slug, slug|
page = @site.pages.where(:slug => page_slug).first
part = page.parts.where(:slug => slug).first
part.should_not be_nil
part.value.should == content
end
### Cross-domain authentication ### Cross-domain authentication
When /^I forget to press the button on the cross-domain notice page$/ do When /^I forget to press the button on the cross-domain notice page$/ do
@ -51,27 +27,13 @@ end
### Common ### Common
def create_site_and_admin_account
@site = Factory(:site, :name => 'Locomotive test website', :subdomain => 'test')
@admin = Factory(:account, { :name => 'Admin', :email => 'admin@locomotiveapp.org' })
@site.memberships.build :account => @admin, :admin => true
@site.save
end
def add_new_site
@another_site = Factory.build(:site, :name => 'Locomotive test website #2', :subdomain => 'test2')
@another_site.memberships.build :account => @admin, :admin => true
@another_site.save
end
def create_layout_samples def create_layout_samples
Factory(:layout, :site => @site, :name => 'One column', :value => %{<html> Factory(:layout, :site => @site, :name => 'One column', :value => %{<html>
<head> <head>
<title>My website</title> <title>My website</title>
</head> </head>
<body> <body>
<div id="main">\{\{ content_for_layout \}\}</div> <div id="main">{{ content_for_layout }}</div>
</body> </body>
</html>}) </html>})
Factory(:layout, :site => @site)
end end

View File

@ -0,0 +1,69 @@
### Pages
# helps create a simple content page (parent: "index") with a slug, contents, and layout
def create_content_page(page_slug, page_contents, layout = nil)
@home = @site.pages.where(:slug => "index").first || Factory(:page)
page = @site.pages.create(:slug => page_slug, :body => page_contents, :layout => layout, :parent => @home, :title => "some title", :published => true)
page.should be_valid
page
end
# creates a page
Given /^a simple page named "([^"]*)" with the body:$/ do |page_slug, page_contents|
@page = create_content_page(page_slug, page_contents)
end
# creates a page (that has a layout)
Given /^a page named "([^"]*)" with the layout "([^"]*)" and the body:$/ do |page_slug, layout_name, page_contents|
layout = @site.layouts.where(:name => layout_name).first
raise "Could not find layout: #{layout_name}" unless layout
@page = create_content_page(page_slug, page_contents, layout)
end
# creates a layout
Given /^a layout named "([^"]*)" with the source:$/ do |layout_name, layout_body|
@layout = Factory(:layout, :name => layout_name, :value => layout_body, :site => @site)
end
# creates a part within a page
Given /^the page named "([^"]*)" has the part "([^"]*)" with the content:$/ do |page_slug, part_slug, part_contents|
page = @site.pages.where(:slug => page_slug).first
raise "Could not find page: #{page_slug}" unless page
# find or crate page part
part = page.parts.where(:slug => part_slug).first
unless part
part = page.parts.build(:name => part_slug.titleize, :slug => part_slug)
end
# set part value
part.value = part_contents
part.should be_valid
# save page with embedded part
page.save
end
# try to render a page by slug
When /^I view the rendered page at "([^"]*)"$/ do |path|
visit "http://#{@site.domains.first}#{path}"
end
# checks to see if a string is in the slug
Then /^I should have "(.*)" in the (.*) page (.*)$/ do |content, page_slug, part_slug|
page = @site.pages.where(:slug => page_slug).first
raise "Could not find page: #{page_slug}" unless page
part = page.parts.where(:slug => part_slug).first
raise "Could not find part: #{part_slug} within page: #{page_slug}" unless part
part.value.should == content
end
# checks if the rendered body matches a string
Then /^the rendered output should look like:$/ do |body_contents|
page.body.should == body_contents
end

View File

@ -0,0 +1,100 @@
# this file generated by script/generate pickle
# create a model
Given(/^#{capture_model} exists?(?: with #{capture_fields})?$/) do |name, fields|
create_model(name, fields)
end
# create n models
Given(/^(\d+) #{capture_plural_factory} exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|
count.to_i.times { create_model(plural_factory.singularize, fields) }
end
# create models from a table
Given(/^the following #{capture_plural_factory} exists?:?$/) do |plural_factory, table|
create_models_from_table(plural_factory, table)
end
# find a model
Then(/^#{capture_model} should exist(?: with #{capture_fields})?$/) do |name, fields|
find_model!(name, fields)
end
# not find a model
Then(/^#{capture_model} should not exist(?: with #{capture_fields})?$/) do |name, fields|
find_model(name, fields).should be_nil
end
# find models with a table
Then(/^the following #{capture_plural_factory} should exists?:?$/) do |plural_factory, table|
find_models_from_table(plural_factory, table).should_not be_any(&:nil?)
end
# find exactly n models
Then(/^(\d+) #{capture_plural_factory} should exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|
find_models(plural_factory.singularize, fields).size.should == count.to_i
end
# assert equality of models
Then(/^#{capture_model} should be #{capture_model}$/) do |a, b|
model!(a).should == model!(b)
end
# assert model is in another model's has_many assoc
Then(/^#{capture_model} should be (?:in|one of|amongst) #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
model!(owner).send(association).should include(model!(target))
end
# assert model is not in another model's has_many assoc
Then(/^#{capture_model} should not be (?:in|one of|amongst) #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
model!(owner).send(association).should_not include(model!(target))
end
# assert model is another model's has_one/belongs_to assoc
Then(/^#{capture_model} should be #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
model!(owner).send(association).should == model!(target)
end
# assert model is not another model's has_one/belongs_to assoc
Then(/^#{capture_model} should not be #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
model!(owner).send(association).should_not == model!(target)
end
# assert model.predicate?
Then(/^#{capture_model} should (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|
if model!(name).respond_to?("has_#{predicate.gsub(' ', '_')}")
model!(name).should send("have_#{predicate.gsub(' ', '_')}")
else
model!(name).should send("be_#{predicate.gsub(' ', '_')}")
end
end
# assert not model.predicate?
Then(/^#{capture_model} should not (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|
if model!(name).respond_to?("has_#{predicate.gsub(' ', '_')}")
model!(name).should_not send("have_#{predicate.gsub(' ', '_')}")
else
model!(name).should_not send("be_#{predicate.gsub(' ', '_')}")
end
end
# model.attribute.should eql(value)
# model.attribute.should_not eql(value)
Then(/^#{capture_model}'s (\w+) (should(?: not)?) be #{capture_value}$/) do |name, attribute, expectation, expected|
actual_value = model(name).send(attribute)
expectation = expectation.gsub(' ', '_')
case expected
when 'nil', 'true', 'false'
actual_value.send(expectation, send("be_#{expected}"))
when /^[+-]?[0-9_]+(\.\d+)?$/
actual_value.send(expectation, eql(expected.to_f))
else
actual_value.to_s.send(expectation, eql(eval(expected)))
end
end
# assert size of association
Then /^#{capture_model} should have (\d+) (\w+)$/ do |name, size, association|
model!(name).send(association).size.should == size.to_i
end

View File

@ -0,0 +1,14 @@
# Creates a Site record
#
# examples:
# - I have the site: "some site" set up
# - I have the site: "some site" set up with name: "Something", domain: "test2"
#
Given /^I have the site: "([^"]*)" set up(?: with #{capture_fields})?$/ do |site_factory, fields|
@site = Factory(site_factory, parse_fields(fields))
@site.should_not be_nil
@admin = @site.memberships.first.account
@admin.should_not be_nil
end

View File

@ -0,0 +1,4 @@
require 'database_cleaner'
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.orm = "mongoid"
Before{ DatabaseCleaner.clean }

View File

@ -16,14 +16,16 @@ require 'capybara/rails'
require 'capybara/cucumber' require 'capybara/cucumber'
require 'capybara/session' require 'capybara/session'
require 'capybara/envjs' # envjs doesnt work at the moment
# require 'capybara/envjs'
# Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In # Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In
# order to ease the transition to Capybara we set the default here. If you'd # order to ease the transition to Capybara we set the default here. If you'd
# prefer to use XPath just remove this line and adjust any selectors in your # prefer to use XPath just remove this line and adjust any selectors in your
# steps to use the XPath syntax. # steps to use the XPath syntax.
Capybara.default_selector = :css Capybara.default_selector = :css
Capybara.javascript_driver = :envjs
Capybara.javascript_driver = :selenium
# If you set this to false, any error raised from within your app will bubble # If you set this to false, any error raised from within your app will bubble
# up to your step definition and out to cucumber unless you catch it somewhere # up to your step definition and out to cucumber unless you catch it somewhere
@ -36,21 +38,9 @@ Capybara.javascript_driver = :envjs
# of your scenarios, as this makes it hard to discover errors in your application. # of your scenarios, as this makes it hard to discover errors in your application.
ActionController::Base.allow_rescue = false ActionController::Base.allow_rescue = false
require 'factory_girl'
Locomotive.configure do |config| Locomotive.configure do |config|
config.default_domain = 'example.com' config.default_domain = 'example.com'
end end
Capybara.default_host = 'test.example.com' Capybara.default_host = 'test.example.com'
# Capybara.app_host = 'http://test.example.com'
# How to clean your database when transactions are turned off. See
# http://github.com/bmabey/database_cleaner for more info.
begin
require 'database_cleaner'
require 'database_cleaner/cucumber'
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.orm = "mongoid"
rescue LoadError => ignore_if_database_cleaner_not_present
puts "Database Cleaner not Present"
end

View File

@ -0,0 +1,2 @@
require 'factory_girl'

View File

@ -0,0 +1,24 @@
# this file generated by script/generate pickle [paths] [email]
#
# Make sure that you are loading your factory of choice in your cucumber environment
#
# For machinist add: features/support/machinist.rb
#
# require 'machinist/active_record' # or your chosen adaptor
# require File.dirname(__FILE__) + '/../../spec/blueprints' # or wherever your blueprints are
# Before { Sham.reset } # to reset Sham's seed between scenarios so each run has same random sequences
#
# For FactoryGirl add: features/support/factory_girl.rb
#
# require 'factory_girl'
# require File.dirname(__FILE__) + '/../../spec/factories' # or wherever your factories are
#
# You may also need to add gem dependencies on your factory of choice in <tt>config/environments/cucumber.rb</tt>
require 'pickle/world'
# Example of configuring pickle:
#
Pickle.configure do |config|
config.adapters = [:factory_girl]
# config.map 'I', 'myself', 'me', 'my', :to => 'user: "me"'
end

View File

@ -11,7 +11,6 @@ module Locomotive
# see actionpack/lib/action_dispatch/http/url.rb for more information # see actionpack/lib/action_dispatch/http/url.rb for more information
def self.domain_and_subdomain(request) def self.domain_and_subdomain(request)
subdomain = extract_subdomain(request)
[extract_domain(request), extract_subdomain(request)] [extract_domain(request), extract_subdomain(request)]
end end

View File

@ -888,7 +888,7 @@ Gem::Specification.new do |s|
"vendor/plugins/custom_fields/lib/custom_fields.rb", "vendor/plugins/custom_fields/lib/custom_fields.rb",
"vendor/plugins/custom_fields/lib/custom_fields/custom_fields_for.rb", "vendor/plugins/custom_fields/lib/custom_fields/custom_fields_for.rb",
"vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/embeds_many.rb", "vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/embeds_many.rb",
"vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/has_many_related.rb", "vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/references_many.rb",
"vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/proxy.rb", "vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/proxy.rb",
"vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/document.rb", "vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/document.rb",
"vendor/plugins/custom_fields/lib/custom_fields/field.rb", "vendor/plugins/custom_fields/lib/custom_fields/field.rb",

View File

@ -5,6 +5,20 @@ Factory.define :site do |s|
s.created_at Time.now s.created_at Time.now
end end
Factory.define "test site", :parent => :site do |s|
s.name 'Locomotive test website'
s.subdomain 'test'
s.after_build do |site_test|
site_test.memberships.build :account => Account.where(:name => "Admin").first || Factory("admin user"), :admin => true
end
end
Factory.define "another site", :parent => "test site" do |s|
s.name "Locomotive test website #2"
s.subdomain "test2"
end
# Accounts ## # Accounts ##
Factory.define :account do |a| Factory.define :account do |a|
a.name 'Bart Simpson' a.name 'Bart Simpson'
@ -14,30 +28,47 @@ Factory.define :account do |a|
a.locale 'en' a.locale 'en'
end end
Factory.define "admin user", :parent => :account do |a|
a.name "Admin"
a.email "admin@locomotiveapp.org"
end
Factory.define "frenchy user", :parent => :account do |a|
a.name "Jean Claude"
a.email "jean@frenchy.fr"
a.locale 'fr'
end
## Memberships ## ## Memberships ##
Factory.define :membership do |m| Factory.define :membership do |m|
m.association :account, :factory => :account
m.admin true m.admin true
m.account{ Account.where(:name => "Bart Simpson").first || Factory(:account) }
end end
## Pages ## ## Pages ##
Factory.define :page do |p| Factory.define :page do |p|
p.association :site, :factory => :site
p.title 'Home page' p.title 'Home page'
p.slug 'index' p.slug 'index'
p.published true
p.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end end
# Factory.define "unpub"
## Liquid templates ## ## Liquid templates ##
Factory.define :liquid_template do |t| Factory.define :liquid_template do |t|
t.association :site, :factory => :site
t.name 'Simple one' t.name 'Simple one'
t.slug 'simple_one' t.slug 'simple_one'
t.value %{simple liquid template} t.value %{simple liquid template}
t.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end end
## Layouts ## ## Layouts ##
Factory.define :layout do |l| Factory.define :layout do |l|
l.association :site, :factory => :site
l.name '1 main column + sidebar' l.name '1 main column + sidebar'
l.value %{<html> l.value %{<html>
<head> <head>
@ -48,30 +79,35 @@ Factory.define :layout do |l|
<div id="main">\{\{ content_for_layout | textile \}\}</div> <div id="main">\{\{ content_for_layout | textile \}\}</div>
</body> </body>
</html>} </html>}
l.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end end
## Snippets ## ## Snippets ##
Factory.define :snippet do |s| Factory.define :snippet do |s|
s.association :site, :factory => :site
s.name 'My website title' s.name 'My website title'
s.slug 'header' s.slug 'header'
s.value %{<title>Acme</title>} s.value %{<title>Acme</title>}
s.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end end
## Theme assets ## ## Theme assets ##
Factory.define :theme_asset do |a| Factory.define :theme_asset do |a|
a.association :site a.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end end
## Asset collections ## ## Asset collections ##
Factory.define :asset_collection do |s| Factory.define :asset_collection do |s|
s.association :site, :factory => :site
s.name 'Trip to Chicago' s.name 'Trip to Chicago'
s.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end end
## Content types ## ## Content types ##
Factory.define :content_type do |t| Factory.define :content_type do |t|
t.association :site, :factory => :site
t.name 'My project' t.name 'My project'
t.site { Site.where(:subdomain => "acme").first || Factory(:site) }
end end

View File

@ -61,34 +61,34 @@ describe Account do
end end
end end
describe 'cross domain authentication' do describe 'cross domain authentication' do
before(:each) do before(:each) do
@account = Factory.build(:account) @account = Factory.build(:account)
@account.stubs(:save).returns(true) @account.stubs(:save).returns(true)
end end
it 'sets a token' do it 'sets a token' do
@account.reset_switch_site_token!.should be_true @account.reset_switch_site_token!.should be_true
@account.switch_site_token.should_not be_empty @account.switch_site_token.should_not be_empty
end end
context 'retrieving an account' do context 'retrieving an account' do
it 'does not find it with an empty token' do it 'does not find it with an empty token' do
Account.find_using_switch_site_token(nil).should be_nil Account.find_using_switch_site_token(nil).should be_nil
end end
it 'raises an exception if not found' do it 'raises an exception if not found' do
lambda { lambda {
Account.find_using_switch_site_token!(nil) Account.find_using_switch_site_token!(nil)
}.should raise_error(Mongoid::Errors::DocumentNotFound) }.should raise_error(Mongoid::Errors::DocumentNotFound)
end end
end end
end end
end end

View File

@ -334,6 +334,32 @@ describe Page do
end end
describe "creating a new page" do
context "with a body" do
before do
@site = Factory(:site, :subdomain => "somethingweird")
@page = Page.create({
:slug => "some_slug",
:title => "Page Title",
:body => "Page Body",
:published => true,
:site => @site
})
end
it "should be valid" do
@page.should be_valid
end
it "should render the passed in body attribute of the page" do
@page.render(Liquid::Context.new).should == "Page Body"
end
end
end
describe 'templatized extension' do describe 'templatized extension' do
before(:each) do before(:each) do

View File

@ -13,6 +13,14 @@ Rspec.configure do |config|
config.before(:each) do config.before(:each) do
Locomotive.config.heroku = false Locomotive.config.heroku = false
Mongoid.master.collections.select { |c| c.name != 'system.indexes' }.each(&:drop) end
require 'database_cleaner'
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.orm = "mongoid"
end
config.before(:each) do
DatabaseCleaner.clean
end end
end end

View File

@ -1,18 +1,18 @@
class Project class Project
include Mongoid::Document include Mongoid::Document
include CustomFields::ProxyClassEnabler include CustomFields::ProxyClassEnabler
include CustomFields::CustomFieldsFor include CustomFields::CustomFieldsFor
field :name field :name
field :description field :description
has_many_related :people references_many :people
embeds_many :tasks embeds_many :tasks
custom_fields_for :people custom_fields_for :people
custom_fields_for :tasks custom_fields_for :tasks
named_scope :ordered, :order_by => [[:name, :asc]] scope :ordered, :order_by => [[:name, :asc]]
end end