Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don’t worry, you can still create the pull request.
  • 2 commits
  • 18 files changed
  • 0 commit comments
  • 1 contributor
View
13 .project
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>custom_fields</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ <nature>org.radrails.rails.core.railsnature</nature>
+ <nature>com.aptana.ruby.core.rubynature</nature>
+ </natures>
+</projectDescription>
View
4 Gemfile
@@ -18,4 +18,8 @@ platforms :mri_19 do
unless ENV['CI']
gem 'ruby-debug19', :require => 'ruby-debug', :platforms => :mri_19 if RUBY_VERSION < '1.9.3'
end
+end
+
+group :test do
+ gem "database_cleaner"
end
View
19 Gemfile.lock
@@ -1,9 +1,9 @@
PATH
remote: .
specs:
- custom_fields (2.0.0.rc13)
+ custom_fields (2.0.0.rc14)
activesupport (~> 3.2.8)
- carrierwave-mongoid (~> 0.1.3)
+ carrierwave-mongoid (~> 0.2.1)
mongoid (~> 2.4.12)
GEM
@@ -19,16 +19,17 @@ GEM
multi_json (~> 1.0)
bson (1.3.1)
bson_ext (1.3.1)
- builder (3.0.0)
- carrierwave (0.5.8)
- activesupport (~> 3.0)
- carrierwave-mongoid (0.1.7)
- carrierwave (~> 0.5.6)
+ builder (3.0.3)
+ carrierwave (0.6.2)
+ activemodel (>= 3.2.0)
+ activesupport (>= 3.2.0)
+ carrierwave-mongoid (0.2.1)
+ carrierwave (~> 0.6.1)
mongoid (~> 2.1)
columnize (0.3.6)
database_cleaner (0.6.7)
diff-lcs (1.1.3)
- i18n (0.6.0)
+ i18n (0.6.1)
linecache (0.46)
rbx-require-relative (> 0.0.4)
mocha (0.9.12)
@@ -70,7 +71,7 @@ DEPENDENCIES
bson (~> 1.3.1)
bson_ext (~> 1.3.1)
custom_fields!
- database_cleaner (~> 0.6.7)
+ database_cleaner
mocha (~> 0.9.12)
mongo (~> 1.3.1)
rake
View
3 config/locales/de.yml
@@ -6,4 +6,5 @@ de:
select: Auswahlbox
boolean: Checkbox
date: Datum
- file: Datei
+ file: Datei
+ tag_set: Tags
View
3 config/locales/en.yml
@@ -9,4 +9,5 @@ en:
file: File
belongs_to: Belongs to
has_many: Has many
- many_to_many: Many To Many
+ many_to_many: Many To Many
+ tag_set: Tags
View
1 config/locales/fr.yml
@@ -10,6 +10,7 @@ fr:
belongs_to: Appartient à
has_many: A plusieurs
many_to_many: A plusieurs et appartient à
+ tag_set: Tags
text_formatting:
none: Aucun
html: HTML
View
3 config/locales/pt-BR.yml
@@ -6,4 +6,5 @@ pt-BR:
category: Caixa de Seleção
boolean: Checkbox
date: Data
- file: Arquivo
+ file: Arquivo
+ tag_set: Tags
View
2 custom_fields.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
s.add_dependency 'mongoid', '~> 2.4.12'
s.add_dependency 'activesupport', '~> 3.2.8'
- s.add_dependency 'carrierwave-mongoid', '~> 0.1.3'
+ s.add_dependency 'carrierwave-mongoid', '~> 0.2.1'
s.add_development_dependency('yard', ['~> 0.7.3'])
s.add_development_dependency('bson', ['~> 1.3.1'])
View
1 lib/custom_fields.rb
@@ -38,6 +38,7 @@ def self.options
require 'custom_fields/types/belongs_to'
require 'custom_fields/types/has_many'
require 'custom_fields/types/many_to_many'
+require 'custom_fields/types/tag_set'
require 'custom_fields/field'
require 'custom_fields/source'
require 'custom_fields/target_helpers'
View
2 lib/custom_fields/field.rb
@@ -6,7 +6,7 @@ class Field
include ::Mongoid::Timestamps
## types ##
- %w(default string text date boolean file select relationship_default belongs_to has_many many_to_many).each do |type|
+ %w(default string text date boolean file select relationship_default belongs_to has_many many_to_many tag_set).each do |type|
include "CustomFields::Types::#{type.classify}::Field".constantize
end
View
2 lib/custom_fields/target.rb
@@ -7,7 +7,7 @@ module Target
included do
## types ##
- %w(default string text date boolean file select belongs_to has_many many_to_many).each do |type|
+ %w(default string text date boolean file select belongs_to has_many many_to_many tag_set).each do |type|
include "CustomFields::Types::#{type.classify}::Target".constantize
end
View
9 lib/custom_fields/target_helpers.rb
@@ -89,6 +89,15 @@ def many_to_many_custom_fields
group_custom_fields('many_to_many') { |rule| [rule['name'], "#{rule['name'].singularize}_ids"] }
end
+ # Returns the names of all the tag_set custom_fields of this object.
+ #
+ # @returns [ Array ] List of names
+ #
+ def tag_set_custom_fields
+ group_custom_fields('tag_set')
+ end
+
+
protected
# Gets the names of the getter methods for a field.
View
265 lib/custom_fields/types/tag_set.rb
@@ -0,0 +1,265 @@
+module CustomFields
+
+ module Types
+
+ module TagSet
+
+ class Tag
+
+ include Mongoid::Document
+
+ field :name, :localize => true
+ field :_slug, :localize => false
+
+ before_validation :set_slug
+
+ validates_presence_of :name
+ validates_uniqueness_of :name, :_slug
+
+ def as_json(options = nil)
+ super :methods => %w(_id name _slug)
+ end
+
+
+ def self.available_tags
+ locale = Mongoid::Fields::I18n.locale.to_s
+
+ Tag.all().asc("name.#{locale}".to_sym).to_ary
+ end
+
+ def self.find_tag_by_name(tag_name, locale = Mongoid::Fields::I18n.locale.to_s)
+ Tag.where("name.#{locale}" => /^#{tag_name.strip}$/i ).first
+ end
+
+ def self.find_tag_by_slug(slug)
+ Tag.where("_slug" => slug ).first
+ end
+
+ def self.class_str_to_field_name(klass)
+ klass.to_s.gsub("::", "_")
+ end
+
+ def self.make_inverse_field(klass, name)
+ class_str_to_field_name(klass)+"__#{name}"
+ end
+
+ def self.field_name_to_class_str(field_name)
+ field_name.split("__")[0].to_s.gsub("_","::")
+ end
+
+ def self.slugify_name(tag_name)
+ tag_name.parameterize('-')
+ end
+
+ def get_relation_collection(klass_id)
+ klass_methods = self.methods.grep(/#{klass_id.to_s}/)
+ return [] if klass_methods.empty?
+ klass_methods.select! {|x| !( x.to_s.match(/_ids/) || x.to_s.match(/=/) ) }
+ collection = Array.new
+ klass_methods.each {|meth| collection << self.send(meth)}
+ collection.flatten.uniq
+ end
+
+ protected
+
+ # Sets the slug of the instance by using the value of the highlighted field
+ # (if available). If a sibling content instance has the same permalink then a
+ # unique one will be generated
+ def set_slug
+ self._slug = Tag.slugify_name(self.name) if self._slug.blank?
+
+ if self._slug.present?
+ self._slug = self.next_unique_slug if self.slug_already_taken?
+ end
+ end
+
+ # Return the next available unique slug as a string
+ def next_unique_slug
+ slug = self._slug.gsub(/-\d*$/, '')
+ last_slug = self.class.where(:_id.ne => self._id, :_slug => /^#{slug}-?\d*?$/i).order_by(:_slug).last._slug
+ next_number = last_slug.scan(/-(\d)$/).flatten.first.to_i + 1
+ [slug, next_number].join('-')
+ end
+
+ def slug_already_taken?
+ self.class.where(:_id.ne => self._id, :_slug => self._slug).any?
+ end
+
+
+ end
+
+ module Field
+
+ extend ActiveSupport::Concern
+
+ included do
+
+
+ end
+
+ def tag_class
+ Tag
+ end
+
+ def ordered_available_tags
+ available_tags
+ end
+
+ def available_tags
+ Tag.available_tags
+ end
+
+
+
+ end
+
+ module Target
+
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+
+
+
+
+ def get_localized_name(tag_hash)
+
+ locale = Mongoid::Fields::I18n.locale.to_s
+
+ if !tag_hash['name'].respond_to?(:merge)
+ tag_hash['name']
+ elsif Mongoid::Fields::I18n.fallbacks?
+ tag_hash['name'][Mongoid::Fields::I18n.fallbacks[locale.to_sym].map(&:to_s).find { |loc| !tag_hash['name'][loc].nil? }]
+ else
+ tag_hash['name'][locale.to_s]
+ end
+ end
+
+ # Adds a tags field
+ #
+ # @param [ Class ] klass The class to modify
+ # @param [ Hash ] rule It contains the name of the field and if it is required or not
+ #
+ def apply_tag_set_custom_field(klass, rule)
+ name, base_collection_name = rule['name'], "#{rule['name']}_available_tags".to_sym
+ inverse_name =Tag.make_inverse_field(klass,name)
+ raw_name = "raw_#{name}"
+
+
+ Tag.has_and_belongs_to_many inverse_name, :class_name => klass.to_s, :inverse_of => raw_name
+
+ klass.has_and_belongs_to_many raw_name, :class_name => "CustomFields::Types::TagSet::Tag", :inverse_of => inverse_name
+
+ # other methods
+ klass.send(:define_method, name.to_sym) { _get_tags(name) }
+ klass.send(:define_method, :"#{name}=") { |value| _set_tags(name, value) }
+ klass.class_eval("alias :#{name.singularize}_ids :raw_#{name.singularize}_ids")
+ klass.class_eval("alias :#{name.singularize}_ids= :raw_#{name.singularize}_ids=")
+
+
+ klass.class_eval <<-EOV
+
+ def self.#{base_collection_name}
+ self._available_tags('#{name}')
+ end
+
+ def self.tag_inverse_relation_#{name}
+ "#{inverse_name}"
+ end
+
+ EOV
+
+ if rule['required']
+ klass.validates_length_of name, :minimum => 1
+ end
+ end
+
+ # Returns a list of documents groups by select values defined in the custom fields recipe
+ #
+ # @param [ Class ] klass The class to modify
+ # @return [ Array ] An array of hashes (keys: select option and related documents)
+ #
+ def group_by_tag(name, order_by = nil)
+ ids_field = "raw_#{name.to_s.singularize}_ids"
+ groups = self.only(ids_field.to_sym).group
+
+ Tag.available_tags.map do |tag|
+ group = groups.select { |g| g[ids_field].include?(tag['_id']) }
+ list = group ? group.collect{|g| g['group'][0]} : []
+
+ groups.delete(group) if group
+
+ { :name => get_localized_name(tag), :entries => self._order_tagged_entries(list, order_by) }.with_indifferent_access
+ end.tap do |array|
+ empty_group = groups.select { |g| g[ids_field].empty? }
+
+ if not empty_group.empty? # orphan entries ?
+ empty = { :name => nil, :entries => [] }.with_indifferent_access
+ list = empty_group.collect{|g| g['group'][0]}
+ empty[:entries] = self._order_tagged_entries(list, order_by)
+ array << empty
+ end
+ end
+ end
+
+ def _available_tags(name)
+ Tag.available_tags.map do |tag|
+ tag_name = get_localized_name(tag)
+ { '_id' => tag['_id'], 'name' => tag_name }
+ end.sort_by{ |x| x['name']}
+ end
+
+ def _order_tagged_entries(list, order_by = nil)
+ return list if order_by.nil?
+
+ column, direction = order_by.flatten
+
+ list = list.sort { |a, b| (a.send(column) && b.send(column)) ? (a.send(column) || 0) <=> (b.send(column) || 0) : 0 }
+
+ direction == 'asc' ? list : list.reverse
+
+ list
+ end
+
+ end
+
+ def _tags_ids(name)
+ self.send(:"raw_#{name.singularize}_ids")
+ end
+
+ #finds tags based on their names, or create it if it doesn't exist
+ def _find_tags(names)
+ names.collect{|tag_name| Tag.find_or_create_by(name: tag_name)}
+ end
+
+ #gets an array of tag names based on the how the object is tagged
+ def _get_tags(field_name)
+ _tags_ids(field_name).collect { |id| Tag.where(:_id => id).first.name}
+
+ end
+
+ #sets the tags (and makes new ones!) based on the value given.. ?
+ def _set_tags(field_name, value)
+ if(value.blank?)
+ tag_name_array = []
+ else
+ tag_name_array = value.kind_of?(Array) ? value : value.split(",")
+ tag_name_array.map!(&:strip).reject!(&:blank?)
+ end
+ self.send(:"raw_#{field_name}").clear
+ locale = Mongoid::Fields::I18n.locale.to_s
+
+ tag_name_array.each do |tag_name|
+ tag = Tag.find_tag_by_name(tag_name, locale)
+ self.send(:"raw_#{field_name}") << (tag.nil? ? Tag.create(:name => tag_name) : tag)
+ end
+ end
+
+
+ end
+
+ end
+
+ end
+
+end
View
1 spec/integration/localize_spec.rb
@@ -7,6 +7,7 @@
before(:each) do
@blog = create_blog
@blog = Blog.find(@blog._id)
+ Mongoid::Fields::I18n.locale = 'en'
end
it 'mimics the original I18n class' do
View
63 spec/integration/performance_spec.rb
@@ -4,6 +4,8 @@
occurences = 1000
+ available_tags = %w(some tags picked at random)
+
context 'with custom fields' do
before(:each) do
@@ -54,6 +56,40 @@
end
+ context 'with custom fields including tags' do
+
+ before(:each) do
+ @blog = create_blog_with_tags
+ create_posts_with_tags(@blog, occurences, available_tags)
+ @blog = Blog.find(@blog._id)
+ end
+
+ it "retrieves #{occurences} posts" do
+ MyBenchmark.measure("retrieving #{occurences} posts") do
+ @blog.posts.all.collect(&:title)
+ end
+ end
+
+ it "retrieves #{occurences} posts and trigger methods" do
+ MyBenchmark.measure("retrieving #{occurences} posts") do
+ @blog.posts.all.each do |entry|
+ entry.main_author = 'john'
+ entry.location = 'chicago'
+ end
+ end
+ end
+
+ it "retrieves #{occurences} posts via tags" do
+ MyBenchmark.measure("retrieving #{occurences} posts") do
+ groups = @blog.posts.group_by_tag(:topics)
+ groups.class.should == Array
+ end
+ end
+
+
+ end
+
+
def create_blog(custom_fields = true)
Blog.new(:name => 'My personal blog').tap do |blog|
if custom_fields
@@ -72,4 +108,31 @@ def create_posts(blog, n)
end
end
+ def create_blog_with_tags(custom_fields = true)
+ Blog.new(:name => 'My personal blog').tap do |blog|
+ if custom_fields
+ blog.posts_custom_fields.build :label => 'Main Author', :type => 'string'
+ blog.posts_custom_fields.build :label => 'Location', :type => 'string'
+ blog.posts_custom_fields.build :label => 'Posted at', :type => 'date'
+ blog.posts_custom_fields.build :label => 'Published', :type => 'boolean'
+ blog.posts_custom_fields.build :label => 'Topics', :type => 'tag_set'
+ end
+ blog.save
+ end
+ end
+
+ def create_posts_with_tags(blog, n, available_tags)
+ number_available_tags = available_tags.length;
+
+ n.times do |i|
+ number_of_tags_to_use = rand(number_available_tags)
+ instance_tag_list = []
+
+ for i in 0..number_of_tags_to_use
+ instance_tag_list << available_tags[rand(number_available_tags)]
+ end
+ blog.posts.create :title => "Hello world #{i}", :body => 'Lorem ipsum...', :topics => instance_tag_list
+ end
+ end
+
end
View
225 spec/integration/types/tag_set_spec.rb
@@ -0,0 +1,225 @@
+require 'spec_helper'
+
+
+describe CustomFields::Types::TagSet do
+
+ before(:each) do
+ @blog = create_blog
+ end
+
+ describe 'a new post' do
+
+ before(:each) do
+ @post = @blog.posts.build :title => 'Hello world', :body => 'Lorem ipsum...'
+ end
+
+ it 'sets the tags' do
+ @post.topics = 'locomotive'
+ @post.save
+ @post.topic_ids.should include(@locomotive_tag._id)
+ end
+
+ it 'adds a new tag to the list of used tags' do
+ @post.topics = "cms, ruby"
+ @post.topics.should include("ruby","cms")
+ end
+
+ it 'removes extra white space from tags' do
+ @post.topics = "cms, ruby, rails , a b c"
+ @post.topics.should include("ruby","cms", "rails", "a b c")
+ end
+
+ it 'can have no tags' do
+ @post.topics = ""
+ @post.topics.should == []
+ end
+
+ it 'can be set via an array' do
+ @post.topics = ['hello', ' world', 'carpe diem']
+ @post.topics.should include("hello", "carpe diem", "world")
+ end
+
+ it 'returns the name of the tag' do
+ @post.topics = ""
+ @post.topic_ids.append(@locomotive_tag._id)
+ @post.save
+ @post.topics.should include('locomotive')
+ end
+
+ it 'ignores the case of tags' do
+ @post.topics = 'LocomOtive'
+ @post.topic_ids.should include(@locomotive_tag._id)
+ end
+
+ it 'can have a tag field that is not named topics' do
+ @post.stuff = 'hello, world'
+ @post.stuff.length.should == 2
+ end
+
+ it 'ignores empty tags' do
+ @post.topics = 'this,is,,not,blank'
+ @post.topic_ids.length.should == 4
+ end
+
+ end
+
+ describe 'an existing post' do
+
+ before(:each) do
+ @post = @blog.posts.create :title => 'Hello world', :body => 'Lorem ipsum...', :raw_topic_ids => [@beach_tag._id, @castle_tag._id]
+ @post = Post.find(@post._id)
+ end
+
+ it 'returns the tags' do
+ @post.topics.should include("beach", "castle")
+ end
+
+ it 'assigns a new tag' do
+ @post.topic_ids.append(@lego_tag._id)
+ @post.save
+ @post = Post.find(@post._id)
+ @post.topics.should include("lego")
+ end
+
+ it 'create a new tag and assigns it' do
+ tag = @blog.posts_custom_fields.detect {|f| f[:label] == "Topics"}.tag_class.create :name => 'new_tag'
+ @blog.save
+ @post = Post.find(@post._id)
+ @post.topics = 'new_tag'
+ @post.attributes['raw_topic_ids'].should include(tag._id)
+ @post.save
+ @post = Post.find(@post._id)
+ @post.topics.should include( 'new_tag')
+ end
+
+ end
+
+ describe 'an saved post' do
+
+ before(:each) do
+ post = @blog.posts.create :title => 'Hello world', :body => 'Lorem ipsum...'
+ post.topics = "topic1, topic2"
+ post.save
+ @post = Post.find(post._id)
+ end
+
+ it 'has the correct tags' do
+ @post.topics.should include("topic2", "topic1")
+ @post.topics.length.should == 2
+ @post.class.topics_available_tags.find_all{|x| x['name'] == 'topic1' || x['name'] == 'topic2'}.length.should == 2
+
+ end
+
+ end
+
+ describe 'slugs and inverse' do
+
+ before(:each) do
+ post = @blog.posts.create :title => 'Hello world', :body => 'Lorem ipsum...'
+ post.topics = "locomotive, Hello World!"
+ post.save
+ @post = Post.find(post._id)
+ end
+
+ it 'gives slugs to tags' do
+ @post.raw_topics[0]._slug.should == "locomotive"
+ @post.raw_topics[1]._slug.should == "hello-world"
+
+ end
+
+ it 'can find a tag by a slug' do
+ CustomFields::Types::TagSet::Tag.find_tag_by_slug("locomotive").should == @post.raw_topics[0]
+ end
+
+ it 'can find the class after making the inverse relation' do
+ CustomFields::Types::TagSet::Tag.field_name_to_class_str(@post.class.tag_inverse_relation_topics).should == @post.class.to_s
+ end
+
+ it 'inverse relations work with Namespaced classes' do
+ namespaced_class_str = "HelloWorld::This:Is:A::NamespacedModule"
+ CustomFields::Types::TagSet::Tag.field_name_to_class_str(CustomFields::Types::TagSet::Tag.class_str_to_field_name(namespaced_class_str)).should == namespaced_class_str
+ end
+
+ it 'can give a collection based on klass id' do
+ my_tag = CustomFields::Types::TagSet::Tag.find_tag_by_slug('hello-world')
+ my_tag.get_relation_collection(@blog.id).size.should == 1
+ end
+
+ end
+
+
+
+ describe 'group_by' do
+
+ before(:each) do
+ p1 = @blog.posts.create :title => 'Hello world 1(sun, beach)', :body => 'Lorem ipsum...'
+ p2 = @blog.posts.create :title => 'Hello world 2(castle, lego)', :body => 'Lorem ipsum...'
+ p3 = @blog.posts.create :title => 'Hello world 3 (locomotive)', :body => 'Lorem ipsum...'
+ p4 = @blog.posts.create :title => 'Hello world 4 (beach, castle, locomotive)', :body => 'Lorem ipsum...'
+ p5 = @blog.posts.create :title => 'Hello world 5 (castle)', :body => 'Lorem ipsum...'
+ p6 = @blog.posts.create :title => 'Hello world (_none_)', :body => 'Lorem ipsum...'
+
+ p1.raw_topics.concat([@sun_tag, @beach_tag])
+ p1.save
+
+ p2.raw_topics.concat([@castle_tag, @lego_tag])
+ p2.save
+
+ p3.raw_topics << @locomotive_tag
+ p3.save
+
+ p4.raw_topics.concat([@locomotive_tag, @beach_tag, @castle_tag])
+ p4.save
+
+ p5.raw_topics.concat([@castle_tag])
+ p5.save
+
+ klass = @blog.klass_with_custom_fields(:posts)
+ @groups = klass.group_by_tag(:topics)
+ end
+
+ it 'is an non empty array' do
+ @groups.class.should == Array
+ @groups.size.should == 6
+ end
+
+ it 'is an array of hashes composed of a name' do
+ @groups.map { |g| g[:name].to_s }.should == ["beach", "castle", "lego", "locomotive", "sun", ""]
+ end
+
+ it 'is an array of hashes composed of a list of documents' do
+ @groups[0][:entries].size.should == 2
+ @groups[1][:entries].size.should == 3
+ @groups[2][:entries].size.should == 1
+ @groups[3][:entries].size.should == 2
+ @groups[4][:entries].size.should == 1
+ @groups[5][:entries].size.should == 1
+ end
+
+ it 'can be accessed from the parent document' do
+ blog = Blog.find(@blog._id)
+ blog.posts.group_by_tag(:topics).class.should == Array
+ end
+
+ end
+
+
+ def create_blog
+ CustomFields::Types::TagSet::Tag.delete_all
+ Blog.new(:name => 'My personal blog').tap do |blog|
+ blog.posts_custom_fields.build :label => 'stuff', :type => 'tag_set'
+ field = blog.posts_custom_fields.build :label => 'Topics', :type => 'tag_set'
+
+ Mongoid::Fields::I18n.locale = :en
+
+ @sun_tag = field.tag_class.create(name: 'sun')
+ @beach_tag = field.tag_class.create(name: 'beach')
+ @lego_tag = field.tag_class.create(name: 'lego')
+ @locomotive_tag = field.tag_class.create(name: 'locomotive' )
+ @castle_tag = field.tag_class.create(name: 'castle')
+
+ blog.save & blog.reload
+ end
+ end
+
+end
View
7 spec/unit/target_helpers_spec.rb
@@ -32,6 +32,10 @@
@post.many_to_many_custom_fields.should == [%w(contributors contributor_ids)]
end
+ it 'groups tag_set fields ' do
+ @post.tag_set_custom_fields.should == %w(tags)
+ end
+
end
context '#returning safe attributes' do
@@ -135,7 +139,8 @@ def build_post_with_rules
{ 'name' => 'author_picture', 'type' => 'file', 'required' => false, 'localized' => false },
{ 'name' => 'contributors', 'type' => 'many_to_many', 'class_name' => 'Person', 'inverse_of' => 'posts', 'required' => false, 'localized' => false },
{ 'name' => 'projects', 'type' => 'has_many', 'class_name' => 'Project', 'inverse_of' => 'project', 'required' => false, 'localized' => false },
- { 'name' => 'illustrations', 'type' => 'has_many', 'class_name' => 'PostImage', 'inverse_of' => 'project', 'required' => false, 'localized' => false }
+ { 'name' => 'illustrations', 'type' => 'has_many', 'class_name' => 'PostImage', 'inverse_of' => 'project', 'required' => false, 'localized' => false },
+ { 'name' => 'tags', 'type' => 'tag_set', 'required' => false, 'localized' => false }
]})
end
end
View
78 spec/unit/types/tag_set_spec.rb
@@ -0,0 +1,78 @@
+require 'spec_helper'
+
+describe CustomFields::Types::TagSet do
+
+ before(:each) do
+ @blog = build_blog
+ @post = @blog.posts.build :title => 'Hello world', :body => 'Lorem ipsum...'
+ end
+
+ it 'is not considered as a relationship field type' do
+ @blog.posts_custom_fields.first.is_relationship?.should be_false
+ end
+
+ it 'stores the list of tags' do
+ @field.respond_to?(:available_tags).should be_true
+ end
+
+ it 'sets a value' do
+ @post.topics = 'Test'
+ @post.topics.should == ['Test']
+ end
+
+ describe 'validation' do
+
+ [nil, ''].each do |value|
+ it "should not be valid if the value is #{value.inspect}" do
+ @post.topics = value
+ @post.valid?.should be_false
+ @post.errors[:topics].should_not be_blank
+ end
+ end
+
+ end
+
+
+ context '#localize' do
+
+ before(:each) do
+ field = @blog.posts_custom_fields.build :label => 'Taxonomy', :type => 'tag_set', :localized => true
+ Mongoid::Fields::I18n.locale = :en
+ @option_1 = field.tag_class.create :name => 'Item #1 in English'
+ @option_2 = field.tag_class.create :name => 'Item #2 in English'
+ Mongoid::Fields::I18n.locale = :fr
+ @option_1.name = 'Item #1 in French'
+ @option_2.name = 'Item #2 in French'
+ @option_1.save
+ @option_2.save
+
+ field.valid?
+ Mongoid::Fields::I18n.locale = :en
+ @blog.bump_custom_fields_version(:posts)
+ end
+
+ it 'serializes / deserializes' do
+ post = @blog.posts.build :taxonomy => 'Item #1 in English'
+ post.taxonomy.should == ['Item #1 in English']
+ end
+
+ it 'serializes / deserializes in a different locale' do
+ post = @blog.posts.build :taxonomy => 'Item #1 in English'
+ Mongoid::Fields::I18n.locale = :fr
+ post.taxonomy = 'Item #2 in French'
+ post.taxonomy_ids.should include(@option_2._id)
+ post.taxonomy_ids.length.should == 1
+ post.taxonomy.should == [@option_2.name]
+ end
+
+ end
+
+ def build_blog
+ Blog.new(:name => 'My personal blog').tap do |blog|
+ @field = blog.posts_custom_fields.build :label => 'Topics', :type => 'tag_set', :required => true
+ @field.tag_class.create :name => 'Test'
+ @field.valid?
+ end
+ end
+
+end

No commit comments for this range

Something went wrong with that request. Please try again.