rename CustomFields::CustomField into CustomFields::Field + create a dynamic class when we have an object with custom fields (optimization) + create a new type of custom field: categories + fix minor bugs + add ui to rename the alias of a custom field
This commit is contained in:
parent
3e7f18e8e3
commit
fc690d8a0b
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,3 +14,4 @@ pkg
|
||||
*.gemspec
|
||||
rails_3_gems
|
||||
doc/performance.txt
|
||||
doc/production.sh
|
||||
|
10
Gemfile
10
Gemfile
@ -11,20 +11,14 @@ gem "mongoid", ">= 2.0.0.beta6"
|
||||
gem "mongoid_acts_as_tree", ">= 0.1.2"
|
||||
gem "warden"
|
||||
gem "devise", ">= 1.1.rc0"
|
||||
gem "haml", '>= 3.0.1'
|
||||
# gem "rmagick"
|
||||
gem "haml", ">= 3.0.1"
|
||||
gem "rmagick", "2.12.2"
|
||||
gem "aws"
|
||||
gem "jeweler"
|
||||
gem "mimetype-fu", :require => "mimetype_fu"
|
||||
gem "formtastic-rails3", :require => "formtastic"
|
||||
gem "carrierwave-rails3", :require => "carrierwave"
|
||||
|
||||
# gem 'formtastic-rails3', :require => 'formtastic', :path => 'rails_3_gems/formtastic'
|
||||
# gem "formtastic", :git => 'git://github.com/justinfrench/formtastic.git', :branch => 'rails3'
|
||||
# gem "carrierwave", :git => "http://github.com/jnicklas/carrierwave.git"
|
||||
# gem "carrierwave", :path => 'rails_3_gems/carrierwave'
|
||||
|
||||
|
||||
# Development environment
|
||||
group :development do
|
||||
# Using mongrel instead of webrick (default server)
|
||||
|
@ -45,7 +45,7 @@ module Admin
|
||||
flash[:error] = e.to_s
|
||||
end
|
||||
|
||||
redirect_to admin_content_types_url
|
||||
redirect_to admin_pages_url
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -2,7 +2,7 @@ module Admin::CustomFieldsHelper
|
||||
|
||||
def options_for_field_kind(selected = nil)
|
||||
# %w{String Text Boolean Email File Date}
|
||||
options = %w{String Text}.map do |kind|
|
||||
options = %w{String Text Select}.map do |kind|
|
||||
[t("admin.custom_fields.kind.#{kind.downcase}"), kind]
|
||||
end
|
||||
end
|
||||
|
@ -5,6 +5,7 @@ class Asset
|
||||
|
||||
## Extensions ##
|
||||
include Models::Extensions::Asset::Vignette
|
||||
include CustomFields::ProxyClassEnabler
|
||||
|
||||
## fields ##
|
||||
field :name, :type => String
|
||||
|
@ -53,6 +53,8 @@ class ThemeAsset
|
||||
end
|
||||
|
||||
def performing_plain_text?
|
||||
return true if !self.new_record? && !self.image? && self.errors.empty?
|
||||
|
||||
!(self.performing_plain_text.blank? || self.performing_plain_text == 'false' || self.performing_plain_text == false)
|
||||
end
|
||||
|
||||
|
@ -35,8 +35,8 @@ class AssetUploader < CarrierWave::Uploader::Base
|
||||
self.class.content_types.each_pair do |type, rules|
|
||||
rules.each do |rule|
|
||||
case rule
|
||||
when String then value = type if file.content_type == rule
|
||||
when Regexp then value = type if (file.content_type =~ rule) == 0
|
||||
when String then value = type if content_type == rule
|
||||
when Regexp then value = type if (content_type =~ rule) == 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,13 +1,15 @@
|
||||
- content_for :head do
|
||||
= javascript_include_tag 'admin/custom_fields'
|
||||
= javascript_include_tag 'admin/plugins/fancybox', 'admin/custom_fields'
|
||||
= stylesheet_link_tag 'admin/plugins/fancybox', 'admin/box'
|
||||
|
||||
= f.inputs :name => :information do
|
||||
= f.input :name
|
||||
= f.input :slug
|
||||
= f.input :description
|
||||
|
||||
= render 'admin/shared/custom_fields', :f => f, :collection_name => 'contents'
|
||||
= render 'admin/custom_fields/index', :f => f, :collection_name => 'contents'
|
||||
|
||||
= f.foldable_inputs :name => :options, :class => 'switchable' do
|
||||
= f.input :highlighted_field_name, :as => :select, :collection => options_for_highlighted_field(f.object, 'contents'), :include_blank => false
|
||||
= f.input :order_by, :as => :select, :collection => options_for_order_by(f.object, 'contents'), :include_blank => false
|
||||
|
||||
|
@ -14,3 +14,5 @@
|
||||
= render 'form', :f => form
|
||||
|
||||
= render 'admin/shared/form_actions', :back_url => admin_contents_url(@content_type.slug), :button_label => :update
|
||||
|
||||
= render 'admin/custom_fields/edit'
|
8
app/views/admin/custom_fields/_edit.html.haml
Normal file
8
app/views/admin/custom_fields/_edit.html.haml
Normal file
@ -0,0 +1,8 @@
|
||||
.box-wrapper
|
||||
#edit-custom-field
|
||||
%h2= t('.title')
|
||||
|
||||
= form_tag '#', :class => 'formtastic' do
|
||||
= fields_for CustomFields::Field.new, :builder => Formtastic::SemanticFormHelper.builder do |g|
|
||||
= g.inputs :name => :information do
|
||||
= g.input :_alias
|
53
app/views/admin/custom_fields/_index.html.haml
Normal file
53
app/views/admin/custom_fields/_index.html.haml
Normal file
@ -0,0 +1,53 @@
|
||||
- collection_name = "#{collection_name.singularize}_custom_fields"
|
||||
- custom_fields = f.object.send(collection_name.to_sym)
|
||||
- ordered_custom_fields = f.object.send(:"ordered_#{collection_name}")
|
||||
|
||||
= f.foldable_inputs :name => :custom_fields, :class => 'editable-list fields off' do
|
||||
- ordered_custom_fields.each do |field|
|
||||
= f.fields_for collection_name.to_sym, field, :child_index => field._index do |g|
|
||||
%li{ :class => "item added #{'error' unless field.errors.empty?}"}
|
||||
%span.handle
|
||||
= image_tag 'admin/form/icons/drag.png'
|
||||
|
||||
= g.hidden_field :position, :class => 'position'
|
||||
|
||||
= g.hidden_field :_alias, :class => 'alias'
|
||||
|
||||
= g.text_field :label
|
||||
|
||||
—
|
||||
|
||||
%em= t("admin.custom_fields.kind.#{field.kind.downcase}")
|
||||
|
||||
= g.select :kind, options_for_field_kind
|
||||
|
||||
|
||||
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/pen.png'), '#edit-custom-field', :class => 'edit first'
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
|
||||
|
||||
= f.fields_for collection_name.to_sym, custom_fields.build(:label => 'field name'), :child_index => '-1' do |g|
|
||||
%li{ :class => 'item template' }
|
||||
%span.handle
|
||||
= image_tag 'admin/form/icons/drag.png'
|
||||
|
||||
= g.hidden_field :position, :class => 'position'
|
||||
|
||||
= g.hidden_field :_alias, :class => 'alias'
|
||||
|
||||
= g.text_field :label, :class => 'string label void'
|
||||
|
||||
—
|
||||
|
||||
%em
|
||||
|
||||
= g.select :kind, options_for_field_kind
|
||||
|
||||
|
||||
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/pen.png'), '#edit-custom-field', :class => 'edit first'
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
|
||||
%button{ :class => 'button light add', :type => 'button' }
|
||||
%span= t('admin.buttons.new_item')
|
@ -11,6 +11,8 @@
|
||||
|
||||
= g.hidden_field :position, :class => 'position'
|
||||
|
||||
= g.hidden_field :_alias, :class => 'alias'
|
||||
|
||||
= g.text_field :label
|
||||
|
||||
—
|
||||
@ -22,7 +24,8 @@
|
||||
|
||||
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
|
||||
= link_to image_tag('admin/form/pen.png'), '#', :class => 'edit first'
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
|
||||
|
||||
= f.fields_for collection_name.to_sym, custom_fields.build(:label => 'field name'), :child_index => '-1' do |g|
|
||||
%li{ :class => 'item template' }
|
||||
@ -31,6 +34,8 @@
|
||||
|
||||
= g.hidden_field :position, :class => 'position'
|
||||
|
||||
= g.hidden_field :_alias, :class => 'alias'
|
||||
|
||||
= g.text_field :label, :class => 'string label void'
|
||||
|
||||
—
|
||||
@ -42,6 +47,9 @@
|
||||
|
||||
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
|
||||
= link_to image_tag('admin/form/pen.png'), '#', :class => 'edit first'
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
|
||||
%button{ :class => 'button light add', :type => 'button' }
|
||||
%span= t('admin.buttons.new_item')
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('admin.messages.confirm')
|
||||
|
||||
%li.item.new
|
||||
%li.item.template
|
||||
%em
|
||||
http://
|
||||
= text_field_tag 'label', t('formtastic.hints.site.domain_name'), :class => 'string label void'
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
- if @image_assets.empty?
|
||||
%p.no-items= t('.no_items')
|
||||
- else
|
||||
|
||||
%ul.assets
|
||||
= render 'asset', :asset => current_site.theme_assets.build, :edit => false
|
||||
|
||||
|
@ -5,6 +5,7 @@ require File.expand_path('../boot', __FILE__)
|
||||
require "action_controller/railtie"
|
||||
require "action_mailer/railtie"
|
||||
require "active_resource/railtie"
|
||||
require "mongoid/railtie"
|
||||
|
||||
# Auto-require default libraries and those for the current Rails environment.
|
||||
Bundler.require :default, Rails.env
|
||||
|
@ -1,20 +0,0 @@
|
||||
defaults: &defaults
|
||||
host: localhost
|
||||
|
||||
development:
|
||||
<<: *defaults
|
||||
database: locomotive_dev
|
||||
|
||||
test: &test
|
||||
<<: *defaults
|
||||
database: locomotive_test
|
||||
|
||||
production:
|
||||
<<: *defaults
|
||||
host: db.mongohq.com
|
||||
username: user
|
||||
password: pass
|
||||
database: fanboy
|
||||
|
||||
cucumber:
|
||||
<<: *test
|
@ -31,15 +31,3 @@ Locomotive::Application.configure do
|
||||
# Enable threaded mode
|
||||
# config.threadsafe!
|
||||
end
|
||||
|
||||
config.action_mailer.delivery_method = :smtp
|
||||
|
||||
config.action_mailer.smtp_settings = {
|
||||
:enable_starttls_auto => true,
|
||||
:address => "smtp.gmail.com",
|
||||
:port => 587,
|
||||
:domain => "nocoffee.fr",
|
||||
:authentication => :plain,
|
||||
:user_name => "didier@nocoffee.fr",
|
||||
:password => "pepscou"
|
||||
}
|
@ -1,11 +1,5 @@
|
||||
require 'mongoid'
|
||||
|
||||
File.open(File.join(Rails.root, 'config/database.yml'), 'r') do |f|
|
||||
@settings = YAML.load(f)[Rails.env]
|
||||
end
|
||||
|
||||
Mongoid::Config.instance.from_hash(@settings)
|
||||
|
||||
## various patches
|
||||
module Mongoid #:nodoc:
|
||||
|
||||
|
@ -33,9 +33,12 @@ en:
|
||||
update: Update
|
||||
|
||||
custom_fields:
|
||||
edit:
|
||||
title: Editing custom field
|
||||
kind:
|
||||
string: Simple Input
|
||||
text: Text
|
||||
select: Select
|
||||
|
||||
sessions:
|
||||
new:
|
||||
@ -173,7 +176,6 @@ en:
|
||||
edit:
|
||||
title: '{{type}} — editing item'
|
||||
|
||||
|
||||
formtastic:
|
||||
titles:
|
||||
information: General information
|
||||
@ -196,6 +198,10 @@ en:
|
||||
source: File
|
||||
edit:
|
||||
source: Replace file
|
||||
custom_fields:
|
||||
custom_field:
|
||||
_alias: Alias
|
||||
|
||||
hints:
|
||||
page:
|
||||
keywords: "Meta keywords used within the head tag of the page. They are separeted by an empty space. Required for SEO."
|
||||
|
24
config/mongoid.yml
Normal file
24
config/mongoid.yml
Normal file
@ -0,0 +1,24 @@
|
||||
defaults: &defaults
|
||||
host: localhost
|
||||
# slaves:
|
||||
# - host: slave1.local
|
||||
# port: 27018
|
||||
# - host: slave2.local
|
||||
# port: 27019
|
||||
|
||||
development:
|
||||
<<: *defaults
|
||||
database: locomotive_dev
|
||||
|
||||
test:
|
||||
<<: *defaults
|
||||
database: locomotive_test
|
||||
|
||||
# set these environment variables on your prod server
|
||||
production:
|
||||
<<: *defaults
|
||||
host: <%= ENV['MONGOID_HOST'] %>
|
||||
port: <%= ENV['MONGOID_PORT'] %>
|
||||
username: <%= ENV['MONGOID_USERNAME'] %>
|
||||
password: <%= ENV['MONGOID_PASSWORD'] %>
|
||||
database: <%= ENV['MONGOID_DATABASE'] %>
|
@ -49,6 +49,7 @@ Rails.application.routes.draw do |map|
|
||||
resources :contents, :path => "content_types/:slug/contents" do
|
||||
put :sort, :on => :collection
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# magic urls
|
||||
|
20
doc/TODO
20
doc/TODO
@ -6,13 +6,10 @@ x make an engine:
|
||||
|
||||
- deploy on Heroku
|
||||
|
||||
- refactoring: CustomFields::CustomField => CustomFields::Field
|
||||
- new types for custom field
|
||||
- file
|
||||
- boolean
|
||||
- date
|
||||
- optimization custom_fields: use dynamic class for a collection instead of modifying the metaclass each time we build an item
|
||||
|
||||
x refactoring: CustomFields::CustomField => CustomFields::Field
|
||||
- new custom field type
|
||||
- category
|
||||
x optimization custom_fields: use dynamic class for a collection instead of modifying the metaclass each time we build an item
|
||||
|
||||
BACKLOG:
|
||||
|
||||
@ -24,9 +21,16 @@ BACKLOG:
|
||||
|
||||
- theme assets: disable version if not image
|
||||
|
||||
- new custom field types
|
||||
- file
|
||||
- boolean
|
||||
- date
|
||||
|
||||
- refactor slugify method (use parameterize + create a module)
|
||||
|
||||
BUGS:
|
||||
- when assigning new layout, disabled parts show up :-( (js problem)
|
||||
- password resets
|
||||
- password resets (url is not handled correctly)
|
||||
|
||||
NICE TO HAVE:
|
||||
- asset collections: custom resizing if image
|
||||
|
@ -32,4 +32,13 @@ class MiscFormBuilder < Formtastic::SemanticFormBuilder
|
||||
end
|
||||
end
|
||||
|
||||
def normalize_model_name(name)
|
||||
if name =~ /(.+)\/(.+)/
|
||||
[$1, $2]
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
BIN
public/images/admin/form/footer-small.png
Normal file
BIN
public/images/admin/form/footer-small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 287 B |
BIN
public/images/admin/form/header-small.png
Normal file
BIN
public/images/admin/form/header-small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 525 B |
BIN
public/images/admin/form/icons/edit.png
Normal file
BIN
public/images/admin/form/icons/edit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 221 B |
BIN
public/images/admin/list/none-small.png
Normal file
BIN
public/images/admin/list/none-small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
@ -19,15 +19,16 @@ $.growl.settings.dockCss = {
|
||||
/* ___ codemirror ___ */
|
||||
|
||||
var addCodeMirrorEditor = function(type, el, parser) {
|
||||
if (type == 'liquid') type = 'xml';
|
||||
var parserfile = "parse" + type + ".js";
|
||||
if (parser != undefined) parserfile = parser;
|
||||
// if (type == 'liquid') type = 'xml';
|
||||
|
||||
var editor = CodeMirror.fromTextArea(el.attr('id'), {
|
||||
height: "400px",
|
||||
parserfile: parserfile,
|
||||
stylesheet: [
|
||||
"/stylesheets/admin/plugins/codemirror/csscolors.css",
|
||||
"/stylesheets/admin/plugins/codemirror/xmlcolors.css",
|
||||
"/stylesheets/admin/plugins/codemirror/javascriptcolors.css",
|
||||
"/stylesheets/admin/plugins/codemirror/liquidcolors.css"],
|
||||
path: "/javascripts/admin/plugins/codemirror/",
|
||||
|
@ -110,4 +110,25 @@ $(document).ready(function() {
|
||||
axis: 'y',
|
||||
update: refreshPosition
|
||||
});
|
||||
|
||||
// edit in depth custom field
|
||||
$('fieldset.fields li.item span.actions a.edit').click(function() {
|
||||
var link = $(this);
|
||||
$.fancybox({
|
||||
titleShow: false,
|
||||
content: $(link.attr('href')).parent().html(),
|
||||
onComplete: function() {
|
||||
$('#fancybox-wrap form').submit(function(e) {
|
||||
$.fancybox.close();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$('#fancybox-wrap #custom_fields_custom_field__alias').val(link.parent().prevAll('.alias').val());
|
||||
},
|
||||
onCleanup: function() {
|
||||
link.parent().prevAll('.alias').val($('#fancybox-wrap #custom_fields_custom_field__alias').val());
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
@ -7,7 +7,7 @@ $(document).ready(function() {
|
||||
|
||||
if (!slug.hasClass('filled')) {
|
||||
setTimeout(function() {
|
||||
slug.val(input.val().replace(/\s/g, '_').toLowerCase());
|
||||
slug.val(input.val().replace(/[\s']/g, '_').toLowerCase());
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
|
@ -71,6 +71,8 @@ var setupUploader = function() {
|
||||
|
||||
asset.removeClass('new-asset');
|
||||
|
||||
$('.asset-picker p.no-items').hide();
|
||||
|
||||
$('.asset-picker ul').scrollTo($('li.asset:last'), 400);
|
||||
}
|
||||
});
|
||||
|
@ -1,8 +1,10 @@
|
||||
/* custom styles for fancybox */
|
||||
|
||||
div.asset-picker { width: 470px; position: relative; }
|
||||
div.asset-picker .actions { position: absolute; right: 4px; top: 0px; }
|
||||
div.asset-picker h2 {
|
||||
/* ___ common ___ */
|
||||
|
||||
.box-wrapper { display: none; }
|
||||
|
||||
#fancybox-inner h2 {
|
||||
border-bottom:1px dotted #BBBBBD;
|
||||
color:#1E1F26;
|
||||
font-size:1.1em;
|
||||
@ -10,5 +12,28 @@ div.asset-picker h2 {
|
||||
padding-bottom:10px;
|
||||
}
|
||||
|
||||
#fancybox-inner form.formtastic legend span {
|
||||
background-image: url("/images/admin/form/header-small.png");
|
||||
width: 450px;
|
||||
}
|
||||
|
||||
#fancybox-inner form.formtastic ol {
|
||||
background-image: url("/images/admin/form/footer-small.png");
|
||||
}
|
||||
|
||||
|
||||
/* ___ asset picker ___ */
|
||||
|
||||
div.asset-picker { width: 470px; position: relative; }
|
||||
div.asset-picker .actions { position: absolute; right: 4px; top: 0px; }
|
||||
|
||||
div.asset-picker p.no-items { background-image: url("/images/admin/list/none-small.png"); }
|
||||
|
||||
div.asset-picker ul { overflow: auto; height: 471px; }
|
||||
div.asset-picker ul li.new-asset { display: none; }
|
||||
|
||||
/* ___ custom fields ___ */
|
||||
|
||||
#edit-custom-field {
|
||||
width: 470px;
|
||||
}
|
@ -226,8 +226,9 @@ form.formtastic fieldset ol li.item span.actions {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 10px;
|
||||
width: 16px;
|
||||
width: 50px;
|
||||
height: 16px;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
/* ___ editable-list (content type fields and validations) ___ */
|
||||
@ -338,6 +339,10 @@ form.formtastic fieldset.editable-list ol li.template span.actions {
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
form.formtastic fieldset.editable-list ol li.template span.actions a.edit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
form.formtastic fieldset.editable-list ol li.template span.actions a.remove {
|
||||
display: none;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ describe AssetCollection do
|
||||
context 'unit' do
|
||||
|
||||
before(:each) do
|
||||
@field = CustomFields::CustomField.new(:kind => 'String')
|
||||
@field = CustomFields::Field.new(:kind => 'String')
|
||||
end
|
||||
|
||||
it 'should tell if it is a String' do
|
||||
@ -75,6 +75,7 @@ describe AssetCollection do
|
||||
context 'build and save' do
|
||||
|
||||
it 'should build asset' do
|
||||
puts "___ TEST #1 ___"
|
||||
asset = @collection.assets.build
|
||||
lambda {
|
||||
asset.description
|
||||
@ -84,12 +85,14 @@ describe AssetCollection do
|
||||
end
|
||||
|
||||
it 'should assign values to newly built asset' do
|
||||
puts "___ TEST #2 ___"
|
||||
asset = build_asset(@collection)
|
||||
asset.description.should == 'Lorem ipsum'
|
||||
asset.active.should == true
|
||||
end
|
||||
|
||||
it 'should save asset' do
|
||||
puts "___ TEST #3 ___"
|
||||
asset = build_asset(@collection)
|
||||
asset.save and @collection.reload
|
||||
asset = @collection.assets.first
|
||||
@ -98,6 +101,7 @@ describe AssetCollection do
|
||||
end
|
||||
|
||||
it 'should not modify assets from another collection' do
|
||||
puts "___ TEST #4 ___"
|
||||
asset = build_asset(@collection)
|
||||
asset.save and @collection.reload
|
||||
new_collection = AssetCollection.new
|
||||
|
3
vendor/plugins/custom_fields/.rspec
vendored
Normal file
3
vendor/plugins/custom_fields/.rspec
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
--colour
|
||||
--format nested
|
||||
--backtrace
|
11
vendor/plugins/custom_fields/Gemfile
vendored
Normal file
11
vendor/plugins/custom_fields/Gemfile
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
source "http://gemcutter.org"
|
||||
|
||||
gem "bson_ext", ">= 1.0.1"
|
||||
gem "mongo_ext"
|
||||
gem "mongoid", ">= 2.0.0.beta6"
|
||||
gem "activesupport", ">= 3.0.0.beta3"
|
||||
|
||||
group :test do
|
||||
gem 'rspec', '>= 2.0.0.beta.10'
|
||||
gem 'mocha', :git => 'git://github.com/floehopper/mocha.git'
|
||||
end
|
4
vendor/plugins/custom_fields/README
vendored
4
vendor/plugins/custom_fields/README
vendored
@ -1,4 +1,4 @@
|
||||
CustomField
|
||||
CustomFields
|
||||
===========
|
||||
|
||||
Introduction goes here.
|
||||
@ -10,4 +10,4 @@ Example
|
||||
Example goes here.
|
||||
|
||||
|
||||
Copyright (c) 2010 [name of plugin creator], released under the MIT license
|
||||
Copyright (c) 2010 [Didier Lafforgue], released under the MIT license
|
||||
|
42
vendor/plugins/custom_fields/Rakefile
vendored
42
vendor/plugins/custom_fields/Rakefile
vendored
@ -1,23 +1,33 @@
|
||||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
require "rubygems"
|
||||
require "rake"
|
||||
require "rake/rdoctask"
|
||||
require "rspec"
|
||||
require "rspec/core/rake_task"
|
||||
|
||||
desc 'Default: run unit tests.'
|
||||
task :default => :test
|
||||
|
||||
desc 'Test the custom_field plugin.'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.libs << 'test'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
desc 'Generate documentation for the custom_field plugin.'
|
||||
desc 'Generate documentation for the custom_fields plugin.'
|
||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = 'CustomField'
|
||||
rdoc.title = 'CustomFields'
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.rdoc_files.include('README')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
|
||||
# Spec::Rake::SpecTask.new(:rcov) do |spec|
|
||||
# spec.libs << 'lib' << 'spec'
|
||||
# spec.pattern = 'spec/**/*_spec.rb'
|
||||
# spec.rcov = true
|
||||
# end
|
||||
|
||||
Rspec::Core::RakeTask.new('spec:unit') do |spec|
|
||||
spec.pattern = "spec/unit/**/*_spec.rb"
|
||||
# spec.pattern = "spec/unit/custom_fields_for_spec.rb"
|
||||
end
|
||||
|
||||
Rspec::Core::RakeTask.new('spec:integration') do |spec|
|
||||
spec.pattern = "spec/integration/**/*_spec.rb"
|
||||
end
|
||||
|
||||
task :spec => [:check_dependencies, 'spec:unit', 'spec:integration']
|
||||
|
||||
task :default => :spec
|
1
vendor/plugins/custom_fields/install.rb
vendored
1
vendor/plugins/custom_fields/install.rb
vendored
@ -1 +0,0 @@
|
||||
# Install hook code here
|
@ -1,7 +1,15 @@
|
||||
$:.unshift File.expand_path(File.dirname(__FILE__))
|
||||
|
||||
require 'active_support'
|
||||
|
||||
require 'custom_fields/extensions/mongoid/associations/proxy'
|
||||
require 'custom_fields/extensions/mongoid/associations/has_many_related'
|
||||
require 'custom_fields/extensions/mongoid/associations/embeds_many'
|
||||
require 'custom_fields/extensions/mongoid/document'
|
||||
require 'custom_fields/types/default'
|
||||
require 'custom_fields/types/category'
|
||||
require 'custom_fields/proxy_class_enabler'
|
||||
require 'custom_fields/field'
|
||||
require 'custom_fields/custom_fields_for'
|
||||
|
||||
module Mongoid
|
||||
|
@ -30,7 +30,7 @@ module CustomFields
|
||||
class_eval <<-EOV
|
||||
field :#{singular_name}_custom_fields_counter, :type => Integer, :default => 0
|
||||
|
||||
embeds_many :#{singular_name}_custom_fields, :class_name => "::CustomFields::CustomField"
|
||||
embeds_many :#{singular_name}_custom_fields, :class_name => "::CustomFields::Field"
|
||||
|
||||
validates_associated :#{singular_name}_custom_fields
|
||||
|
||||
@ -39,6 +39,7 @@ module CustomFields
|
||||
def ordered_#{singular_name}_custom_fields
|
||||
self.#{singular_name}_custom_fields.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
||||
end
|
||||
|
||||
EOV
|
||||
end
|
||||
|
||||
|
@ -2,6 +2,27 @@
|
||||
module Mongoid #:nodoc:
|
||||
module Associations #:nodoc:
|
||||
class EmbedsMany < Proxy
|
||||
def initialize_with_custom_fields(parent, options, target_array = nil)
|
||||
if custom_fields?(parent, options.name)
|
||||
options = options.clone # 2 parent instances should not share the exact same option instance
|
||||
|
||||
custom_fields = parent.send(:"ordered_#{custom_fields_association_name(options.name)}")
|
||||
|
||||
klass = options.klass.to_klass_with_custom_fields(custom_fields)
|
||||
|
||||
options.instance_eval <<-EOF
|
||||
def klass=(klass); @klass = klass; end
|
||||
def klass; @klass || class_name.constantize; end
|
||||
EOF
|
||||
|
||||
options.klass = klass
|
||||
end
|
||||
|
||||
initialize_without_custom_fields(parent, options, target_array)
|
||||
end
|
||||
|
||||
alias_method_chain :initialize, :custom_fields
|
||||
|
||||
def build_with_custom_field_settings(attrs = {}, type = nil)
|
||||
document = build_without_custom_field_settings(attrs, type)
|
||||
|
||||
@ -19,6 +40,5 @@ module Mongoid #:nodoc:
|
||||
|
||||
alias_method_chain :build, :custom_field_settings
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -0,0 +1,31 @@
|
||||
# encoding: utf-8
|
||||
module Mongoid #:nodoc:
|
||||
module Associations #:nodoc:
|
||||
# Represents an relational one-to-many association with an object in a
|
||||
# separate collection or database.
|
||||
class HasManyRelated < Proxy
|
||||
|
||||
def initialize_with_custom_fields(parent, options, target_array = nil)
|
||||
if custom_fields?(parent, options.name)
|
||||
options = options.clone # 2 parent instances should not share the exact same option instance
|
||||
|
||||
custom_fields = parent.send(:"ordered_#{custom_fields_association_name(options.name)}")
|
||||
|
||||
klass = options.klass.to_klass_with_custom_fields(custom_fields)
|
||||
|
||||
options.instance_eval <<-EOF
|
||||
def klass=(klass); @klass = klass; end
|
||||
def klass; @klass || class_name.constantize; end
|
||||
EOF
|
||||
|
||||
options.klass = klass
|
||||
end
|
||||
|
||||
initialize_without_custom_fields(parent, options, target_array)
|
||||
end
|
||||
|
||||
alias_method_chain :initialize, :custom_fields
|
||||
|
||||
end
|
||||
end
|
||||
end
|
16
vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/proxy.rb
vendored
Normal file
16
vendor/plugins/custom_fields/lib/custom_fields/extensions/mongoid/associations/proxy.rb
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
# encoding: utf-8
|
||||
module Mongoid #:nodoc
|
||||
module Associations #:nodoc
|
||||
class Proxy #:nodoc
|
||||
|
||||
def custom_fields_association_name(association_name)
|
||||
"#{association_name.to_s.singularize}_custom_fields".to_sym
|
||||
end
|
||||
|
||||
def custom_fields?(object, association_name)
|
||||
object.respond_to?(custom_fields_association_name(association_name))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -2,34 +2,34 @@
|
||||
module Mongoid #:nodoc:
|
||||
module Document
|
||||
module InstanceMethods
|
||||
def parentize_with_custom_fields(object, association_name)
|
||||
parentize_without_custom_fields(object, association_name)
|
||||
|
||||
if self.custom_fields?(object, association_name)
|
||||
# puts "[parentize_with_custom_fields] association_name = #{association_name} / #{self.custom_fields_association_name(association_name)}"
|
||||
object.send(self.custom_fields_association_name(association_name)).each do |field|
|
||||
field.apply(self, association_name)
|
||||
end
|
||||
|
||||
self.instance_eval <<-EOV
|
||||
def custom_fields
|
||||
fields = self._parent.send(:#{self.custom_fields_association_name(association_name)})
|
||||
fields.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
||||
end
|
||||
EOV
|
||||
end
|
||||
end
|
||||
|
||||
alias_method_chain :parentize, :custom_fields
|
||||
|
||||
def custom_fields_association_name(association_name)
|
||||
"#{association_name.to_s.singularize}_custom_fields".to_sym
|
||||
end
|
||||
|
||||
def custom_fields?(object, association_name)
|
||||
object.respond_to?(custom_fields_association_name(association_name)) &&
|
||||
object.associations[association_name]
|
||||
end
|
||||
# def parentize_with_custom_fields(object, association_name)
|
||||
# parentize_without_custom_fields(object, association_name)
|
||||
#
|
||||
# if self.custom_fields?(object, association_name)
|
||||
# # puts "[parentize_with_custom_fields] association_name = #{association_name} / #{self.custom_fields_association_name(association_name)}"
|
||||
# object.send(self.custom_fields_association_name(association_name)).each do |field|
|
||||
# field.apply(self)
|
||||
# end
|
||||
#
|
||||
# self.instance_eval <<-EOV
|
||||
# def custom_fields
|
||||
# fields = self._parent.send(:#{self.custom_fields_association_name(association_name)})
|
||||
# fields.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
||||
# end
|
||||
# EOV
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# alias_method_chain :parentize, :custom_fields
|
||||
#
|
||||
# def custom_fields_association_name(association_name)
|
||||
# "#{association_name.to_s.singularize}_custom_fields".to_sym
|
||||
# end
|
||||
#
|
||||
# def custom_fields?(object, association_name)
|
||||
# object.respond_to?(custom_fields_association_name(association_name)) &&
|
||||
# object.associations[association_name]
|
||||
# end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,8 +1,12 @@
|
||||
module CustomFields
|
||||
|
||||
class CustomField
|
||||
include Mongoid::Document
|
||||
include Mongoid::Timestamps
|
||||
class Field
|
||||
include ::Mongoid::Document
|
||||
include ::Mongoid::Timestamps
|
||||
|
||||
# types ##
|
||||
include Types::Default
|
||||
include Types::Category
|
||||
|
||||
## fields ##
|
||||
field :label, :type => String
|
||||
@ -17,7 +21,7 @@ module CustomFields
|
||||
|
||||
## methods ##
|
||||
|
||||
%w{String Text Email Boolean Date File}.each do |kind|
|
||||
%w{String Text Category}.each do |kind|
|
||||
define_method "#{kind.downcase}?" do
|
||||
self.kind == kind
|
||||
end
|
||||
@ -25,26 +29,41 @@ module CustomFields
|
||||
|
||||
def field_type
|
||||
case self.kind
|
||||
when 'String', 'Text', 'Email' then String
|
||||
when 'String', 'Text', 'Category' then String
|
||||
else
|
||||
self.kind.constantize
|
||||
end
|
||||
end
|
||||
|
||||
def apply(object, association_name)
|
||||
def apply(klass)
|
||||
return unless self.valid?
|
||||
|
||||
# trick mongoid
|
||||
object.class_eval { def meta; (class << self; self; end); end }
|
||||
object.meta.fields = object.fields.clone
|
||||
object.meta.send(:define_method, :fields) { self.meta.fields }
|
||||
klass.field self._name, :type => self.field_type
|
||||
|
||||
object.meta.field self._name, :type => self.field_type
|
||||
object.class_eval <<-EOF
|
||||
alias :#{self.safe_alias} :#{self._name}
|
||||
alias :#{self.safe_alias}= :#{self._name}=
|
||||
EOF
|
||||
case self.kind
|
||||
when 'Category'
|
||||
apply_category_type(klass)
|
||||
else
|
||||
apply_default_type(klass)
|
||||
end
|
||||
end
|
||||
|
||||
# def apply_to_object(object)
|
||||
# return unless self.valid?
|
||||
#
|
||||
# # trick mongoid: fields are now on a the singleton class level also called metaclass
|
||||
# self.singleton_class.fields = self.fields.clone
|
||||
# self.singleton_class.send(:define_method, :fields) { self.singleton_class.fields }
|
||||
#
|
||||
# object.singleton_class.field self._name, :type => self.field_type
|
||||
#
|
||||
# case self.kind
|
||||
# when 'Category'
|
||||
# apply_category_type(object)
|
||||
# else
|
||||
# apply_default_type(object)
|
||||
# end
|
||||
# end
|
||||
|
||||
def safe_alias
|
||||
self.set_alias
|
||||
@ -66,8 +85,7 @@ module CustomFields
|
||||
|
||||
def set_alias
|
||||
return if self.label.blank? && self._alias.blank?
|
||||
self._alias ||= self.label.clone
|
||||
self._alias.slugify!(:downcase => true, :underscore => true)
|
||||
self._alias = (self._alias || self.label).parameterize('_').downcase
|
||||
end
|
||||
|
||||
def increment_counter!
|
37
vendor/plugins/custom_fields/lib/custom_fields/proxy_class_enabler.rb
vendored
Normal file
37
vendor/plugins/custom_fields/lib/custom_fields/proxy_class_enabler.rb
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
module CustomFields
|
||||
module ProxyClassEnabler
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
|
||||
cattr_accessor :klass_with_custom_fields
|
||||
|
||||
def self.to_klass_with_custom_fields(fields)
|
||||
return klass_with_custom_fields unless klass_with_custom_fields.nil?
|
||||
|
||||
klass = Class.new(self)
|
||||
klass.class_eval <<-EOF
|
||||
cattr_accessor :custom_fields
|
||||
|
||||
def self.model_name
|
||||
@_model_name ||= ActiveModel::Name.new(self.superclass)
|
||||
end
|
||||
|
||||
def custom_fields
|
||||
self.class.custom_fields
|
||||
end
|
||||
EOF
|
||||
|
||||
klass.hereditary = false
|
||||
klass.custom_fields = fields
|
||||
|
||||
[*fields].each { |field| field.apply(klass) }
|
||||
|
||||
klass_with_custom_fields = klass
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
52
vendor/plugins/custom_fields/lib/custom_fields/types/category.rb
vendored
Normal file
52
vendor/plugins/custom_fields/lib/custom_fields/types/category.rb
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
module CustomFields
|
||||
module Types
|
||||
module Category
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
embeds_many :category_items, :class_name => 'CustomFields::Types::Category::Item'
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def ordered_category_items
|
||||
self.category_items.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
||||
end
|
||||
|
||||
def apply_category_type(klass)
|
||||
klass.cattr_accessor :"#{self.safe_alias}_items"
|
||||
|
||||
klass.send("#{self.safe_alias}_items=", self.category_items)
|
||||
|
||||
klass.class_eval <<-EOF
|
||||
def self.#{self.safe_alias}_names
|
||||
#{self.safe_alias}_items.collect(&:name)
|
||||
end
|
||||
|
||||
def #{self.safe_alias}=(name)
|
||||
category_id = self.class.#{self.safe_alias}_items.where(:name => name).first._id rescue nil
|
||||
write_attribute(:#{self._name}, category_id)
|
||||
end
|
||||
|
||||
def #{self.safe_alias}
|
||||
category_id = read_attribute(:#{self._name})
|
||||
self.class.#{self.safe_alias}_items.find(category_id).name rescue nil
|
||||
end
|
||||
EOF
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Item
|
||||
|
||||
include Mongoid::Document
|
||||
|
||||
field :name
|
||||
field :position, :type => Integer, :default => 0
|
||||
|
||||
embedded_in :custom_field, :inverse_of => :category_items
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
18
vendor/plugins/custom_fields/lib/custom_fields/types/default.rb
vendored
Normal file
18
vendor/plugins/custom_fields/lib/custom_fields/types/default.rb
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
module CustomFields
|
||||
module Types
|
||||
module Default
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def apply_default_type(klass)
|
||||
klass.class_eval <<-EOF
|
||||
alias :#{self.safe_alias} :#{self._name}
|
||||
alias :#{self.safe_alias}= :#{self._name}=
|
||||
EOF
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
10
vendor/plugins/custom_fields/spec/models/person.rb
vendored
Normal file
10
vendor/plugins/custom_fields/spec/models/person.rb
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
class Person
|
||||
|
||||
include Mongoid::Document
|
||||
include CustomFields::ProxyClassEnabler
|
||||
|
||||
field :full_name
|
||||
|
||||
embedded_in :project, :inverse_of => :people
|
||||
|
||||
end
|
16
vendor/plugins/custom_fields/spec/models/project.rb
vendored
Normal file
16
vendor/plugins/custom_fields/spec/models/project.rb
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
class Project
|
||||
|
||||
include Mongoid::Document
|
||||
include CustomFields::ProxyClassEnabler
|
||||
include CustomFields::CustomFieldsFor
|
||||
|
||||
field :name
|
||||
field :description
|
||||
|
||||
has_many_related :people
|
||||
embeds_many :tasks
|
||||
|
||||
custom_fields_for :people
|
||||
custom_fields_for :tasks
|
||||
|
||||
end
|
10
vendor/plugins/custom_fields/spec/models/task.rb
vendored
Normal file
10
vendor/plugins/custom_fields/spec/models/task.rb
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
class Task
|
||||
|
||||
include Mongoid::Document
|
||||
include CustomFields::ProxyClassEnabler
|
||||
|
||||
field :title
|
||||
|
||||
embedded_in :project, :inverse_of => :tasks
|
||||
|
||||
end
|
30
vendor/plugins/custom_fields/spec/spec_helper.rb
vendored
Normal file
30
vendor/plugins/custom_fields/spec/spec_helper.rb
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
||||
|
||||
MODELS = File.join(File.dirname(__FILE__), "models")
|
||||
$LOAD_PATH.unshift(MODELS)
|
||||
|
||||
require 'rubygems'
|
||||
require 'bundler'
|
||||
Bundler.setup
|
||||
Bundler.require
|
||||
|
||||
require 'mongoid'
|
||||
require 'mocha'
|
||||
require 'rspec'
|
||||
require 'custom_fields'
|
||||
|
||||
Dir[ File.join(MODELS, "*.rb") ].sort.each { |file| require File.basename(file) }
|
||||
|
||||
Mongoid.configure do |config|
|
||||
name = "custom_fields_test"
|
||||
host = "localhost"
|
||||
config.master = Mongo::Connection.new.db(name)
|
||||
end
|
||||
|
||||
Rspec.configure do |config|
|
||||
config.mock_with :mocha
|
||||
config.after :suite do
|
||||
Mongoid.master.collections.each(&:drop)
|
||||
end
|
||||
end
|
42
vendor/plugins/custom_fields/spec/unit/custom_field_spec.rb
vendored
Normal file
42
vendor/plugins/custom_fields/spec/unit/custom_field_spec.rb
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::Field do
|
||||
|
||||
it 'is initialized' do
|
||||
lambda { CustomFields::Field.new }.should_not raise_error
|
||||
end
|
||||
|
||||
context '#mongoid' do
|
||||
|
||||
before(:each) do
|
||||
@field = CustomFields::Field.new(:label => 'manager', :_name => 'field_1', :kind => 'String', :_alias => 'manager')
|
||||
@field.stubs(:valid?).returns(true)
|
||||
@project = Project.to_klass_with_custom_fields(@field).new
|
||||
end
|
||||
|
||||
it 'is added to the list of mongoid fields' do
|
||||
@project.fields['field_1'].should_not be_nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'on target class' do
|
||||
|
||||
before(:each) do
|
||||
@field = CustomFields::Field.new(:label => 'manager', :_name => 'field_1', :kind => 'String', :_alias => 'manager')
|
||||
@field.stubs(:valid?).returns(true)
|
||||
@project = Project.to_klass_with_custom_fields(@field).new
|
||||
end
|
||||
|
||||
it 'has a new field' do
|
||||
@project.respond_to?(:manager).should be_true
|
||||
end
|
||||
|
||||
it 'sets / retrieves a value' do
|
||||
@project.manager = 'Mickael Scott'
|
||||
@project.manager.should == 'Mickael Scott'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
85
vendor/plugins/custom_fields/spec/unit/custom_fields_for_spec.rb
vendored
Normal file
85
vendor/plugins/custom_fields/spec/unit/custom_fields_for_spec.rb
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::CustomFieldsFor do
|
||||
|
||||
context 'with embedded collection' do
|
||||
|
||||
context '#association' do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new
|
||||
end
|
||||
|
||||
it 'has custom fields for embedded collection' do
|
||||
@project.respond_to?(:task_custom_fields).should be_true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context '#building' do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new
|
||||
@project.task_custom_fields.build :label => 'Short summary', :_alias => 'summary', :kind => 'String'
|
||||
@task = @project.tasks.build
|
||||
end
|
||||
|
||||
it 'returns a new document whose Class is different from the original one' do
|
||||
@task.class.should_not == Task
|
||||
end
|
||||
|
||||
it 'returns a new document with custom field' do
|
||||
@project.tasks.build
|
||||
@project.tasks.build
|
||||
@task.respond_to?(:summary).should be_true
|
||||
end
|
||||
|
||||
it 'sets/gets custom attributes' do
|
||||
@task.summary = 'Lorem ipsum...'
|
||||
@task.summary.should == 'Lorem ipsum...'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with related collection' do
|
||||
|
||||
context '#association' do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new
|
||||
end
|
||||
|
||||
it 'has custom fields for related collections' do
|
||||
@project.respond_to?(:person_custom_fields).should be_true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context '#building' do
|
||||
|
||||
before(:each) do
|
||||
@project = Project.new
|
||||
@project.person_custom_fields.build :label => 'Position in the project', :_alias => 'position', :kind => 'String'
|
||||
@person = @project.people.build
|
||||
end
|
||||
|
||||
it 'returns a new document whose Class is different from the original one' do
|
||||
@person.class.should_not == Task
|
||||
end
|
||||
|
||||
it 'returns a new document with custom field' do
|
||||
@person.respond_to?(:position).should be_true
|
||||
end
|
||||
|
||||
it 'sets/gets custom attributes' do
|
||||
@person.position = 'Designer'
|
||||
@person.position.should == 'Designer'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
25
vendor/plugins/custom_fields/spec/unit/proxy_class_enabler_spec.rb
vendored
Normal file
25
vendor/plugins/custom_fields/spec/unit/proxy_class_enabler_spec.rb
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::ProxyClassEnabler do
|
||||
|
||||
context '#proxy klass' do
|
||||
|
||||
before(:each) do
|
||||
@klass = Task.to_klass_with_custom_fields([])
|
||||
end
|
||||
|
||||
it 'does not be flagged as a inherited document' do
|
||||
@klass.new.hereditary?.should be_false
|
||||
end
|
||||
|
||||
it 'has a list of custom fields' do
|
||||
@klass.custom_fields.should == []
|
||||
end
|
||||
|
||||
it 'has the exact same model name than its parent' do
|
||||
@klass.model_name.should == 'Task'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
58
vendor/plugins/custom_fields/spec/unit/types/category_spec.rb
vendored
Normal file
58
vendor/plugins/custom_fields/spec/unit/types/category_spec.rb
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe CustomFields::Types::Category do
|
||||
|
||||
context 'on field class' do
|
||||
|
||||
before(:each) do
|
||||
@field = CustomFields::Field.new
|
||||
end
|
||||
|
||||
it 'has the category items field' do
|
||||
@field.respond_to?(:category_items).should be_true
|
||||
end
|
||||
|
||||
it 'has the apply method used for the target object' do
|
||||
@field.respond_to?(:apply_category_type).should be_true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'on target class' do
|
||||
|
||||
before(:each) do
|
||||
@project = build_project_with_category
|
||||
end
|
||||
|
||||
it 'has getter/setter' do
|
||||
@project.respond_to?(:global_category).should be_true
|
||||
@project.respond_to?(:global_category=).should be_true
|
||||
end
|
||||
|
||||
it 'has the values of this category' do
|
||||
@project.class.global_category_names.should == %w{Development Design Maintenance}
|
||||
end
|
||||
|
||||
it 'sets the category from a name' do
|
||||
@project.global_category = 'Design'
|
||||
@project.global_category.should == 'Design'
|
||||
@project.field_1.should_not be_nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def build_project_with_category
|
||||
field = build_category
|
||||
Project.to_klass_with_custom_fields(field).new
|
||||
end
|
||||
|
||||
def build_category
|
||||
field = CustomFields::Field.new(:label => 'global_category', :_name => 'field_1', :kind => 'Category')
|
||||
field.stubs(:valid?).returns(true)
|
||||
field.category_items.build :name => 'Development'
|
||||
field.category_items.build :name => 'Design'
|
||||
field.category_items.build :name => 'Maintenance'
|
||||
field
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue
Block a user