custom field validation is more robust + editing new fields for assets works now

This commit is contained in:
dinedine 2010-05-22 16:46:32 +02:00
parent 10ffc2e8bb
commit 1ed613ede8
9 changed files with 104 additions and 28 deletions

View File

@ -35,11 +35,7 @@ class AssetCollection
def assets_order=(order)
@assets_order = order
end
def ordered_asset_custom_fields # FIXME (custom fields)
self.asset_custom_fields.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
end
protected
def normalize_slug

View File

@ -1,4 +1,4 @@
= f.foldable_inputs :name => :custom_fields, :class => 'editable-list fields off' do
= f.foldable_inputs :name => :custom_fields, :class => 'editable-list fields' do
- f.object.ordered_asset_custom_fields.each do |field|
= f.fields_for :asset_custom_fields, field, :child_index => field._index do |g|
%li{ :class => "item added #{'error' unless field.errors.empty?}"}

View File

@ -2,6 +2,14 @@
= f.input :name
= f.input :source
- unless @asset.custom_fields.empty?
= f.inputs :name => :other_fields do
- @asset.custom_fields.each do |field|
- if field.string?
= f.input field._alias.to_sym, :label => field.label
- elsif field.text?
= f.input field._alias.to_sym, :label => field.label, :as => :text
- if @asset.image?
= f.foldable_inputs :name => "#{t('formtastic.titles.preview')} #{image_dimensions_and_size(@asset)}", :class => 'preview' do
%li

View File

@ -155,6 +155,7 @@ en:
preview: Preview
options: Advanced options
custom_fields: Custom fields
other_fields: Other information
labels:
theme_asset:
new:

View File

@ -55,16 +55,16 @@ x domain scoping when authenticating
x ui
x field position
x rename asset_field
- apply in asset_field
- nested attributes
- keep tracks of all custom fields (adding / editing assets)
- custom fields -> metadata keys
- duplicate fields
x nested attributes
x keep tracks of all custom fields (adding / editing assets) + order them
x duplicate fields
- apply in asset_field (in order to handle Date, File, ...etc)
BACKLOG:
- liquid rendering engine
- theme assets
- assets collection
- custom models
- devise messages in French
- localize devise emails

View File

@ -9,10 +9,52 @@ describe AssetCollection do
describe 'custom fields (beta)' do
before(:each) do
@collection = Factory.build(:asset_collection, :site => nil)
site = Factory.build(:site)
Site.stubs(:find).returns(site)
@collection = Factory.build(:asset_collection, :site => site)
@collection.asset_custom_fields.build :label => 'My Description', :_alias => 'description', :kind => 'Text'
@collection.asset_custom_fields.build :label => 'Active', :kind => 'Boolean'
puts "first field index = #{@collection.asset_custom_fields.first._index}"
end
context 'unit' do
before(:each) do
@field = CustomFields::CustomField.new(:kind => 'String')
end
it 'should tell if it is a String' do
@field.string?.should be_true
end
it 'should tell if it is a Text' do
@field.kind = 'Text'
@field.text?.should be_true
end
end
context 'validation' do
%w{label kind}.each do |key|
it "should validate presence of #{key}" do
field = @collection.asset_custom_fields.build({ :label => 'Shortcut', :kind => 'String' }.merge(key.to_sym => nil))
field.should_not be_valid
field.errors[key.to_sym].should == ["can't be blank"]
end
end
it 'should not have unique label' do
field = @collection.asset_custom_fields.build :label => 'Active', :kind => 'Boolean'
field.should_not be_valid
field.errors[:label].should == ["is already taken"]
end
it 'should invalidate parent if custom field is not valid' do
field = @collection.asset_custom_fields.build
@collection.should_not be_valid
@collection.asset_custom_fields.last.errors[:label].should == ["can't be blank"]
end
end
context 'define core attributes' do
@ -36,6 +78,7 @@ describe AssetCollection do
lambda {
asset.description
asset.active
asset.custom_fields.size.should == 2
}.should_not raise_error
end
@ -97,11 +140,11 @@ describe AssetCollection do
context 'managing from hash' do
before(:each) do
site = Factory.build(:site)
Site.stubs(:find).returns(site)
@collection.site = site
end
# before(:each) do
# site = Factory.build(:site)
# Site.stubs(:find).returns(site)
# @collection.site = site
# end
it 'should add new field' do
@collection.asset_custom_fields.clear

View File

@ -13,8 +13,15 @@ module CustomFields
## validations ##
validates_presence_of :label, :kind
validate :uniqueness_of_label
## methods ##
%w{String Text Email Boolean Date File}.each do |kind|
define_method "#{kind.downcase}?" do
self.kind == kind
end
end
def field_type
case self.kind
@ -25,7 +32,10 @@ module CustomFields
end
def apply(object, association_name)
return unless self.valid?
object.class.send(:set_field, self._name, { :type => self.field_type })
object.class_eval <<-EOF
alias :#{self.safe_alias} :#{self._name}
alias :#{self.safe_alias}= :#{self._name}=
@ -38,6 +48,13 @@ module CustomFields
end
protected
def uniqueness_of_label
duplicate = self.siblings.detect { |f| f.label == self.label && f._id != self._id }
if not duplicate.nil?
self.errors.add(:label, :taken)
end
end
def set_unique_name!
self._name ||= "custom_field_#{self.increment_counter!}"
@ -56,7 +73,7 @@ module CustomFields
end
def siblings
self._parent.associations[self.association_name]
self._parent.send(self.association_name)
end
end

View File

@ -8,19 +8,19 @@ module CustomFields
# Enhance an embedded collection by providing methods to manage custom fields
#
# class Person
# embeds_many :addresses
# custom_fields_for :addresses
# class Company
# embeds_many :employees
# custom_fields_for :employees
# end
#
# class Address
# embedded_in :person, :inverse_of => :addresses
# field :street, String
# class Employee
# embedded_in :company, :inverse_of => :employees
# field :name, String
# end
#
# person.address_fields.build :label => 'Floor', :kind => 'String'
# company.employee_custom_fields.build :label => 'His/her position', :_alias => 'position', :kind => 'String'
#
# person.addresses.build :street => 'Laflin Street', :floor => '42'
# company.employees.build :name => 'Mickael Scott', :position => 'Regional manager'
#
module ClassMethods
@ -34,7 +34,13 @@ module CustomFields
embeds_many :#{singular_name}_custom_fields, :class_name => "::CustomFields::CustomField"
validates_associated :#{singular_name}_custom_fields
accepts_nested_attributes_for :#{singular_name}_custom_fields, :allow_destroy => true
def ordered_#{singular_name}_custom_fields
self.#{singular_name}_custom_fields.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
end
EOV
end

View File

@ -6,6 +6,11 @@ module Mongoid #:nodoc:
parentize_without_custom_fields(object, association_name)
if self.custom_fields?(object, association_name)
self.class.send(:define_method, :custom_fields) do
fields = object.send(self.custom_fields_association_name(association_name))
fields.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
end
object.send(self.custom_fields_association_name(association_name)).each do |field|
field.apply(self, association_name)
end
@ -20,7 +25,7 @@ module Mongoid #:nodoc:
def custom_fields?(object, association_name)
object.respond_to?(custom_fields_association_name(association_name)) &&
object.associations[association_name]
object.associations[association_name]
end
end
end