categories in content types have been improved a lot + cross-site session + meta keys / description for site + clean code + fix bugs
This commit is contained in:
parent
524ccc3613
commit
b7e1cd0926
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ rails_3_gems
|
||||
doc/performance.txt
|
||||
doc/production.sh
|
||||
*.gem
|
||||
tmp/*
|
||||
|
@ -6,7 +6,7 @@ module Admin
|
||||
before_filter :set_content_type
|
||||
|
||||
def index
|
||||
@contents = @content_type.ordered_contents
|
||||
@contents = @content_type.list_or_group_contents
|
||||
end
|
||||
|
||||
def new
|
||||
|
@ -21,11 +21,10 @@ module Admin
|
||||
protected
|
||||
|
||||
def new_host_if_subdomain_changed
|
||||
host_from_site = "#{@site.subdomain}.#{Locomotive.config.default_domain}"
|
||||
if request.host == host_from_site
|
||||
if @site.domains.include?(request.host)
|
||||
{}
|
||||
else
|
||||
{ :host => "#{host_from_site}:#{request.port}" }
|
||||
{ :host => "#{@site.subdomain}.#{Locomotive.config.default_domain}:#{request.port}" }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -32,17 +32,6 @@ module Admin
|
||||
|
||||
redirect_to edit_admin_my_account_url
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def new_host_if_subdomain_changed
|
||||
host_from_site = "#{@site.subdomain}.#{Locomotive.config.default_domain}"
|
||||
if request.host == host_from_site
|
||||
{}
|
||||
else
|
||||
{ :host => "#{host_from_site}:#{request.port}" }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,3 +1,3 @@
|
||||
class ApplicationController < ActionController::Base
|
||||
class ApplicationController < ActionController::Base
|
||||
protect_from_forgery
|
||||
end
|
||||
|
@ -21,4 +21,11 @@ module Admin::CustomFieldsHelper
|
||||
collection.map { |field| [field.label, field._name] }
|
||||
end
|
||||
|
||||
def options_for_group_by_field(content_type, collection_name)
|
||||
custom_fields_collection_name = "ordered_#{collection_name.singularize}_custom_fields".to_sym
|
||||
collection = content_type.send(custom_fields_collection_name)
|
||||
collection.delete_if { |f| not f.category? }
|
||||
collection.map { |field| [field.label, field._name] }
|
||||
end
|
||||
|
||||
end
|
@ -20,4 +20,14 @@ module Admin::PagesHelper
|
||||
list
|
||||
end
|
||||
|
||||
def options_for_page_cache_expiration
|
||||
[
|
||||
[t('.expiration.never'), 0],
|
||||
[t('.expiration.hour'), 1.hour],
|
||||
[t('.expiration.day'), 1.day],
|
||||
[t('.expiration.week'), 1.week],
|
||||
[t('.expiration.month'), 1.month]
|
||||
]
|
||||
end
|
||||
|
||||
end
|
@ -15,6 +15,9 @@ class ContentInstance
|
||||
## associations ##
|
||||
embedded_in :content_type, :inverse_of => :contents
|
||||
|
||||
## callbacks ##
|
||||
before_create :add_to_list_bottom
|
||||
|
||||
## named scopes ##
|
||||
named_scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb
|
||||
|
||||
@ -26,6 +29,11 @@ class ContentInstance
|
||||
|
||||
protected
|
||||
|
||||
def add_to_list_bottom
|
||||
Rails.logger.debug "add_to_list_bottom"
|
||||
self._position_in_list = self.content_type.contents.size
|
||||
end
|
||||
|
||||
def require_highlighted_field
|
||||
_alias = self.content_type.highlighted_field._alias.to_sym
|
||||
if self.send(_alias).blank?
|
||||
|
@ -8,6 +8,7 @@ class ContentType
|
||||
field :slug
|
||||
field :order_by
|
||||
field :highlighted_field_name
|
||||
field :group_by_field_name
|
||||
field :api_enabled, :type => Boolean, :default => false
|
||||
|
||||
## associations ##
|
||||
@ -28,6 +29,26 @@ class ContentType
|
||||
|
||||
## methods ##
|
||||
|
||||
def groupable?
|
||||
self.group_by_field && group_by_field.category?
|
||||
end
|
||||
|
||||
def list_or_group_contents
|
||||
if self.groupable?
|
||||
groups = self.contents.klass.send(:"group_by_#{self.group_by_field._alias}", :ordered_contents)
|
||||
|
||||
# look for items with no category or unknown ones
|
||||
items_without_category = self.contents.find_all { |c| !self.group_by_field.category_ids.include?(c.send(self.group_by_field_name)) }
|
||||
if not items_without_category.empty?
|
||||
groups << { :name => nil, :items => items_without_category }
|
||||
else
|
||||
groups
|
||||
end
|
||||
else
|
||||
self.ordered_contents
|
||||
end
|
||||
end
|
||||
|
||||
def ordered_contents(conditions = {})
|
||||
column = self.order_by.to_sym
|
||||
|
||||
@ -49,6 +70,10 @@ class ContentType
|
||||
self.content_custom_fields.detect { |f| f._name == self.highlighted_field_name }
|
||||
end
|
||||
|
||||
def group_by_field
|
||||
@group_by_field ||= self.content_custom_fields.detect { |f| f._name == self.group_by_field_name }
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_default_values
|
||||
|
@ -12,8 +12,7 @@ class Page
|
||||
field :slug
|
||||
field :fullpath
|
||||
field :published, :type => Boolean, :default => false
|
||||
field :keywords
|
||||
field :description
|
||||
field :cache_expires_in, :type => Integer, :default => 0
|
||||
|
||||
## associations ##
|
||||
belongs_to_related :site
|
||||
@ -36,6 +35,7 @@ class Page
|
||||
named_scope :not_found, :where => { :slug => '404', :depth => 0, :published => true }
|
||||
|
||||
## behaviours ##
|
||||
liquid_methods :title, :fullpath
|
||||
liquify_template :joined_parts
|
||||
|
||||
## methods ##
|
||||
|
@ -6,6 +6,8 @@ class Site
|
||||
field :name
|
||||
field :subdomain
|
||||
field :domains, :type => Array, :default => []
|
||||
field :meta_keywords
|
||||
field :meta_description
|
||||
|
||||
## associations ##
|
||||
has_many_related :pages
|
||||
@ -33,7 +35,7 @@ class Site
|
||||
named_scope :match_domain_with_exclusion_of, lambda { |domain, site| { :where => { :domains => domain, :_id.ne => site.id } } }
|
||||
|
||||
## behaviours ##
|
||||
liquid_methods :name
|
||||
liquid_methods :name, :meta_keywords, :meta_description
|
||||
|
||||
## methods ##
|
||||
|
||||
|
@ -10,9 +10,13 @@
|
||||
= render 'admin/custom_fields/index', :f => f, :collection_name => 'contents'
|
||||
|
||||
- unless f.object.new_record?
|
||||
= f.foldable_inputs :name => :options, :class => 'switchable' do
|
||||
= f.foldable_inputs :name => :presentation, :class => 'switchable' do
|
||||
= f.input :highlighted_field_name, :as => :select, :collection => options_for_highlighted_field(f.object, 'contents'), :include_blank => false
|
||||
= f.input :group_by_field_name, :as => :select, :collection => options_for_group_by_field(f.object, 'contents')
|
||||
|
||||
= f.foldable_inputs :name => :options, :class => 'switchable' do
|
||||
= f.input :order_by, :as => :select, :collection => options_for_order_by(f.object, 'contents'), :include_blank => false
|
||||
= f.custom_input :api_enabled, :css => 'toggle' do
|
||||
= f.check_box :api_enabled
|
||||
|
||||
|
||||
|
16
app/views/admin/contents/_list.html.haml
Normal file
16
app/views/admin/contents/_list.html.haml
Normal file
@ -0,0 +1,16 @@
|
||||
- if contents.empty?
|
||||
%p.no-items= t('.no_items', :url => new_admin_content_url(@content_type.slug))
|
||||
- else
|
||||
- puts contents.inspect
|
||||
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position_in_list'}" }
|
||||
- contents.each do |content|
|
||||
%li.content{ :id => "content-#{content._id}" }
|
||||
%em
|
||||
%strong
|
||||
= link_to content.send(@content_type.highlighted_field_name), edit_admin_content_path(@content_type.slug, content)
|
||||
.more
|
||||
%span
|
||||
= t('admin.contents.index.updated_at')
|
||||
= l content.updated_at, :format => :short rescue 'n/a'
|
||||
|
||||
= link_to image_tag('admin/list/icons/trash.png'), admin_content_path(@content_type.slug, content), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
|
@ -13,21 +13,13 @@
|
||||
- if @content_type.description.present?
|
||||
%p= @content_type.description
|
||||
|
||||
- if @contents.empty?
|
||||
%p.no-items= t('.no_items', :url => new_admin_content_url(@content_type.slug))
|
||||
- if @content_type.groupable?
|
||||
- @contents.each do |group|
|
||||
%h3= group[:name] || t('.category_noname')
|
||||
= render 'list', :contents => group[:items]
|
||||
%br
|
||||
- else
|
||||
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position_in_list'}" }
|
||||
- @contents.each do |content|
|
||||
%li.content{ :id => "content-#{content._id}" }
|
||||
%em
|
||||
%strong
|
||||
= link_to content.send(@content_type.highlighted_field_name), edit_admin_content_path(@content_type.slug, content)
|
||||
.more
|
||||
%span
|
||||
= t('admin.contents.index.updated_at')
|
||||
= l content.updated_at, :format => :short rescue 'n/a'
|
||||
|
||||
= link_to image_tag('admin/list/icons/trash.png'), admin_content_path(@content_type.slug, content), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
|
||||
= render 'list', :contents => @contents
|
||||
|
||||
= form_tag sort_admin_contents_path(@content_type.slug), :method => :put, :class => 'formtastic' do
|
||||
= hidden_field_tag :order
|
||||
|
@ -3,6 +3,11 @@
|
||||
|
||||
= f.foldable_inputs :name => :information, :style => "#{'display: none' unless @site.new_record?}" do
|
||||
= f.input :name, :required => false
|
||||
|
||||
= f.foldable_inputs :name => :meta do
|
||||
|
||||
= f.input :meta_keywords
|
||||
= f.input :meta_description
|
||||
|
||||
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' do
|
||||
|
||||
@ -42,4 +47,4 @@
|
||||
%em= account.email
|
||||
- if account != current_admin
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/icons/trash.png'), admin_membership_url(membership), :class => 'remove first', :confirm => t('admin.messages.confirm'), :method => :delete
|
||||
= link_to image_tag('admin/form/icons/trash.png'), admin_membership_url(membership), :class => 'remove first', :confirm => t('admin.messages.confirm'), :method => :delete
|
@ -16,10 +16,7 @@
|
||||
= f.custom_input :published, :css => 'toggle' do
|
||||
= f.check_box :published
|
||||
|
||||
= f.foldable_inputs :name => :meta do
|
||||
|
||||
= f.input :keywords
|
||||
= f.input :description
|
||||
= f.input :cache_expires_in, :as => :select, :collection => options_for_page_cache_expiration, :include_blank => false
|
||||
|
||||
#page-parts
|
||||
.nav
|
||||
|
@ -32,4 +32,4 @@
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
|
||||
%button{ :class => 'button light add', :type => 'button' }
|
||||
%span= t('admin.buttons.new_item')
|
||||
%span= t('admin.buttons.new_item')
|
@ -84,8 +84,16 @@ en:
|
||||
successful_create: "Page was successfully created."
|
||||
successful_update: "Page was successfully updated."
|
||||
successful_destroy: "Page was successfully deleted."
|
||||
successful_sort: "Pages were successfully sorted."
|
||||
failed_create: "Page was not created."
|
||||
failed_update: "Page was not updated."
|
||||
form:
|
||||
expiration:
|
||||
never: Never
|
||||
hour: 1 hour
|
||||
day: 1 day
|
||||
week: 1 week
|
||||
month: 1 month
|
||||
|
||||
layouts:
|
||||
index:
|
||||
@ -264,10 +272,12 @@ en:
|
||||
edit: edit model
|
||||
destroy: remove model
|
||||
download: download items
|
||||
new: new item
|
||||
no_items: "There are no items for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
|
||||
new: new item
|
||||
category_noname: "No name"
|
||||
lastest_items: "Lastest items"
|
||||
updated_at: "Updated at"
|
||||
list:
|
||||
no_items: "There are no items for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
|
||||
new:
|
||||
title: '{{type}} — new item'
|
||||
edit:
|
||||
@ -297,6 +307,7 @@ en:
|
||||
options: Advanced options
|
||||
custom_fields: Custom fields
|
||||
other_fields: Other information
|
||||
presentation: Presentation
|
||||
labels:
|
||||
theme_asset:
|
||||
new:
|
||||
@ -311,6 +322,8 @@ en:
|
||||
page:
|
||||
keywords: "Meta keywords used within the head tag of the page. They are separeted by an empty space. Required for SEO."
|
||||
description: "Meta description used within the head tag of the page. Required for SEO."
|
||||
published: "Only authenticated accounts can view unpublished pages."
|
||||
cache_expires_in: "Cache the page for better performance. Pressing shift-reload in the browser will regenerate the page."
|
||||
snippet:
|
||||
slug: "You need to know it in order to insert the snippet inside a page or a layout"
|
||||
site:
|
||||
|
23
doc/TODO
23
doc/TODO
@ -1,7 +1,7 @@
|
||||
BOARD:
|
||||
|
||||
- deploy on Heroku
|
||||
- observers to add / remove domains (http://groups.google.com/group/heroku/browse_thread/thread/148d6ea68e4574fb/4d8f1c8545d52bda?lnk=gst&q=heroku+gem+api#4d8f1c8545d52bda)
|
||||
- new custom field types
|
||||
- boolean
|
||||
|
||||
BACKLOG:
|
||||
|
||||
@ -13,16 +13,15 @@ BACKLOG:
|
||||
|
||||
- theme assets: disable version if not image
|
||||
|
||||
- new custom field types
|
||||
- new custom field types:
|
||||
- file
|
||||
- boolean
|
||||
- date
|
||||
|
||||
- refactoring admin crud (pages + layouts + snippets)
|
||||
- refactor slugify method (use parameterize + create a module)
|
||||
- cucumber features for admin pages
|
||||
|
||||
- Heroku / S3 / Worker
|
||||
- tiny mce or similar for custom field text type.
|
||||
|
||||
BUGS:
|
||||
|
||||
@ -32,8 +31,8 @@ NICE TO HAVE:
|
||||
- asset collections: custom resizing if image
|
||||
- super_finder
|
||||
- better icons for mime type
|
||||
- hint for custom fields (super easy to do !)
|
||||
- tiny mce or similar for custom field text type.
|
||||
- traffic statistics
|
||||
- Heroku / S3 / Worker (not so sure finally)
|
||||
|
||||
DONE:
|
||||
x admin layout
|
||||
@ -133,4 +132,12 @@ x site subdomain regexp [a-z][A-Z][0-9]
|
||||
! migrate content_instance to its own collection => http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24sliceoperator
|
||||
x [BUG] "field name" for alias / hint for custom fields
|
||||
x [BUG] can not remove custom fields at creation if object is invalid
|
||||
x internal logger
|
||||
x internal logger
|
||||
x deploy on Heroku
|
||||
x observers to add / remove domains (http://groups.google.com/group/heroku/browse_thread/thread/148d6ea68e4574fb/4d8f1c8545d52bda?lnk=gst&q=heroku+gem+api#4d8f1c8545d52bda)
|
||||
x varnish caching (only with Heroku ?)
|
||||
x page not included in liquid templates
|
||||
x redirect to referer url when updating site
|
||||
x [BUG] items non sorted in a category
|
||||
x contents grouped by "category" in the admin
|
||||
x hint for custom fields (super easy to do !)
|
@ -32,10 +32,9 @@ module Locomotive
|
||||
|
||||
ActionMailer::Base.default_url_options[:host] = self.config.default_domain + (Rails.env.development? ? ':3000' : '')
|
||||
|
||||
# cookies stored in mongodb
|
||||
# cookies stored in mongodb (mongoid_store)
|
||||
Rails.application.config.session_store :mongoid_store, {
|
||||
:key => Locomotive.config.cookie_key,
|
||||
:domain => ".#{Locomotive.config.default_domain}"
|
||||
:key => Locomotive.config.cookie_key
|
||||
}
|
||||
|
||||
# Heroku support
|
||||
|
@ -1,2 +0,0 @@
|
||||
Devise::SessionsController.class_eval do
|
||||
end
|
@ -53,7 +53,11 @@ module Locomotive
|
||||
|
||||
def before_method(meth)
|
||||
klass = @content_type.contents.klass # delegate to the proxy class
|
||||
klass.send(meth)
|
||||
if (meth.to_s =~ /^group_by_.+$/) == 0
|
||||
klass.send(meth, :ordered_contents)
|
||||
else
|
||||
klass.send(meth)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,2 +1 @@
|
||||
# load patches for devise, ...etc
|
||||
require 'locomotive/devise/sessions_controller'
|
||||
# load patches here
|
@ -8,13 +8,13 @@ module Locomotive
|
||||
protected
|
||||
|
||||
def render_locomotive_page
|
||||
page = locomotive_page
|
||||
@page = locomotive_page
|
||||
|
||||
redirect_to application_root_url and return if page.nil?
|
||||
redirect_to application_root_url and return if @page.nil?
|
||||
|
||||
output = page.render(locomotive_context)
|
||||
output = @page.render(locomotive_context)
|
||||
|
||||
prepare_and_set_response(output)
|
||||
prepare_and_set_response(output, @page.cache_expires_in || 0)
|
||||
end
|
||||
|
||||
def locomotive_page
|
||||
@ -35,6 +35,7 @@ module Locomotive
|
||||
def locomotive_context
|
||||
assigns = {
|
||||
'site' => current_site,
|
||||
'page' => @page,
|
||||
'asset_collections' => Locomotive::Liquid::Drops::AssetCollections.new(current_site),
|
||||
'stylesheets' => Locomotive::Liquid::Drops::Stylesheets.new(current_site),
|
||||
'javascripts' => Locomotive::Liquid::Drops::Javascripts.new(current_site),
|
||||
@ -42,13 +43,14 @@ module Locomotive
|
||||
'current_page' => self.params[:page]
|
||||
}
|
||||
|
||||
registers = { :controller => self, :site => current_site }
|
||||
registers = { :controller => self, :site => current_site, :page => @page }
|
||||
|
||||
::Liquid::Context.new(assigns, registers)
|
||||
end
|
||||
|
||||
def prepare_and_set_response(output)
|
||||
response.headers["Content-Type"] = 'text/html; charset=utf-8'
|
||||
def prepare_and_set_response(output, cache_expiration = 0)
|
||||
response.headers['Cache-Control'] = "public, max-age=#{cache_expiration}" if cache_expiration > 0
|
||||
response.headers['Content-Type'] = 'text/html; charset=utf-8'
|
||||
render :text => output, :layout => false, :status => :ok
|
||||
end
|
||||
|
||||
|
@ -1,16 +1,11 @@
|
||||
module Locomotive
|
||||
|
||||
module Routing
|
||||
|
||||
class DefaultConstraint
|
||||
|
||||
def self.matches?(request)
|
||||
domain, subdomain = domain_and_subdomain(request)
|
||||
subdomain = 'www' if subdomain.blank?
|
||||
|
||||
# puts "domain = #{domain} / #{Locomotive.config.default_domain.inspect}"
|
||||
# puts "subdomain = #{subdomain} / #{Locomotive.config.reserved_subdomains.inspect}"
|
||||
|
||||
domain == Locomotive.config.default_domain && Locomotive.config.reserved_subdomains.include?(subdomain)
|
||||
end
|
||||
|
||||
@ -38,8 +33,7 @@ module Locomotive
|
||||
parts = request.host.split('.')
|
||||
parts[0..-(tld_length+2)]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,17 +1,13 @@
|
||||
module Locomotive
|
||||
|
||||
module Routing
|
||||
|
||||
module Routing
|
||||
module SiteDispatcher
|
||||
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
include Locomotive::Routing::SiteDispatcher::InstanceMethods
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_filter :fetch_site
|
||||
|
||||
before_filter :fetch_site
|
||||
|
||||
helper_method :current_site
|
||||
end
|
||||
helper_method :current_site
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
@ -42,8 +38,6 @@ module Locomotive
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,9 +1,11 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
var updateContentsOrder = function() {
|
||||
var list = $('ul#contents-list.sortable');
|
||||
var ids = jQuery.map(list.sortable('toArray'), function(e) {
|
||||
return e.match(/content-(\w+)/)[1];
|
||||
var lists = $('ul#contents-list.sortable');
|
||||
var ids = jQuery.map(lists, function(list) {
|
||||
return(jQuery.map($(list).sortable('toArray'), function(el) {
|
||||
return el.match(/content-(\w+)/)[1];
|
||||
}).join(','));
|
||||
}).join(',');
|
||||
$('#order').val(ids || '');
|
||||
}
|
||||
|
33
spec/lib/locomotive/liquid/drops/contents_spec.rb
Normal file
33
spec/lib/locomotive/liquid/drops/contents_spec.rb
Normal file
@ -0,0 +1,33 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Locomotive::Liquid::Drops::Contents do
|
||||
|
||||
before(:each) do
|
||||
@site = Factory.build(:site)
|
||||
@content_type = Factory.build(:content_type, :site => @site, :slug => 'projects')
|
||||
end
|
||||
|
||||
it 'retrieves a content type from a slug' do
|
||||
@site.content_types.expects(:where).with(:slug => 'projects')
|
||||
render_template '{{ contents.projects }}'
|
||||
end
|
||||
|
||||
context '#group_by' do
|
||||
|
||||
it 'orders contents' do
|
||||
@site.content_types.stubs(:where).returns([@content_type])
|
||||
@content_type.contents.klass.expects(:group_by_category).with(:ordered_contents)
|
||||
render_template '{% for group in contents.projects.group_by_category %} {{ group.name }} {% endfor %}'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def render_template(template = '', assigns = {})
|
||||
assigns = {
|
||||
'contents' => Locomotive::Liquid::Drops::Contents.new(@site)
|
||||
}.merge(assigns)
|
||||
|
||||
Liquid::Template.parse(template).render assigns
|
||||
end
|
||||
|
||||
end
|
@ -16,13 +16,22 @@ describe 'Locomotive rendering system' do
|
||||
@controller.send(:prepare_and_set_response, 'Hello world !')
|
||||
end
|
||||
|
||||
it 'should have a html content type' do
|
||||
@controller.response.headers["Content-Type"].should == 'text/html; charset=utf-8'
|
||||
it 'sets the content type to html' do
|
||||
@controller.response.headers['Content-Type'].should == 'text/html; charset=utf-8'
|
||||
end
|
||||
|
||||
it 'should display the output' do
|
||||
it 'displays the output' do
|
||||
@controller.output.should == 'Hello world !'
|
||||
end
|
||||
|
||||
it 'does not set the cache' do
|
||||
@controller.response.headers['Cache-Control'].should be_nil
|
||||
end
|
||||
|
||||
it 'sets the cache' do
|
||||
@controller.send(:prepare_and_set_response, 'Hello world !', 3600)
|
||||
@controller.response.headers['Cache-Control'].should == 'public, max-age=3600'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
2
vendor/plugins/custom_fields/Gemfile
vendored
2
vendor/plugins/custom_fields/Gemfile
vendored
@ -3,7 +3,7 @@ source "http://gemcutter.org"
|
||||
gem "bson_ext", ">= 1.0.1"
|
||||
gem "mongo_ext"
|
||||
gem "mongoid", ">= 2.0.0.beta6"
|
||||
gem "activesupport", ">= 3.0.0.beta4"
|
||||
gem "activesupport", ">= 3.0.0.beta3"
|
||||
|
||||
group :test do
|
||||
gem 'rspec', '>= 2.0.0.beta.10'
|
||||
|
@ -18,6 +18,14 @@ module CustomFields
|
||||
self.category_items.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
||||
end
|
||||
|
||||
def category_names
|
||||
self.category_items.collect(&:name)
|
||||
end
|
||||
|
||||
def category_ids
|
||||
self.category_items.collect(&:_id)
|
||||
end
|
||||
|
||||
def apply_category_type(klass)
|
||||
klass.cattr_accessor :"#{self.safe_alias}_items"
|
||||
|
||||
@ -28,11 +36,13 @@ module CustomFields
|
||||
self.#{self.safe_alias}_items.collect(&:name)
|
||||
end
|
||||
|
||||
def self.group_by_#{self.safe_alias}
|
||||
def self.group_by_#{self.safe_alias}(list_method = nil)
|
||||
groups = (if self.embedded?
|
||||
self._parent.send(self.association_name).all
|
||||
list_method ||= self.association_name
|
||||
self._parent.send(list_method)
|
||||
else
|
||||
self.all
|
||||
list_method ||= :all
|
||||
self.send(list_method)
|
||||
end).to_a.group_by(&:#{self._name})
|
||||
|
||||
self.#{self.safe_alias}_items.collect do |category|
|
||||
|
@ -13,4 +13,6 @@ class Project
|
||||
custom_fields_for :people
|
||||
custom_fields_for :tasks
|
||||
|
||||
named_scope :ordered, :order_by => [[:name, :asc]]
|
||||
|
||||
end
|
@ -67,6 +67,11 @@ describe CustomFields::Types::Category do
|
||||
@groups[2][:items].size.should == 2
|
||||
end
|
||||
|
||||
it 'passes method to retrieve items' do
|
||||
@project.class.expects(:ordered)
|
||||
@project.class.group_by_global_category(:ordered)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user