# encoding: utf-8 require 'spec_helper' describe DataMapper::Is::Slug do before :all do class ::User include DataMapper::Resource property :id, Serial property :email, String has n, :posts has n, :todos def slug_for_email email.split("@").first end is :slug, :source => :slug_for_email, :length => 80, :permanent_slug => false end class ::Post include DataMapper::Resource property :id, Serial property :title, String, :length => 30 property :content, Text belongs_to :user is :slug, :source => :title end class ::Todo include DataMapper::Resource property :id, Serial property :title, String belongs_to :user end class ::Task include DataMapper::Resource property :id, Serial property :title, String property :description, String property :category, String is :slug, :source => :title, :scope => :category end class ::SlugKey include DataMapper::Resource property :title, String is :slug, :source => :title, :key => true end class ::Post2 include DataMapper::Resource property :id, Serial property :title, String, :length => 30 property :content, Text is :slug, :source => :title, :permanent_slug => false end end supported_by :in_memory, :yaml, :sqlite, :mysql, :postgres do before :all do DataMapper.repository do puts ">>> #{DataMapper.repository.adapter.inspect}" DataMapper.logger.set_log STDOUT, :debug, ' ~ ', true DataMapper.logger << 'boo!' @u1 = User.create(:email => "john@ekohe.com") @p1 = Post.create(:user => @u1, :title => "My first shinny blog post") @p2 = Post.create(:user => @u1, :title => "My second shinny blog post") @p3 = Post.create(:user => @u1, :title => "My third shinny blog post") @u2 = User.create(:email => "john@someotherplace.com") @p4 = Post.create(:user => @u2, :title => "My first Shinny blog post") @p5 = Post.create(:user => @u2, :title => "i heart merb and dm") @p6 = Post.create(:user => @u2, :title => "A fancy café") @p7 = Post.create(:user => @u2, :title => "你好") (1..10).each do |i| instance_variable_set "@p1_#{i}".to_sym, Post.create(:user => @u2, :title => "another productive day!!") end (1..10).each do |i| instance_variable_set "@p2_#{i}".to_sym, Post.create(:user => @u2, :title => "DM tricks") end @sk = SlugKey.create(:title => 'slug key') @post1 = Post.create :user => @u1, :title => 'a' * Post.slug_property.length @post2 = Post.create :user => @u1, :title => 'a' * Post.slug_property.length end end it "should raise error if :source option is not specified" do lambda { class BadUsage include DataMapper::Resource property :id, Serial is :slug, {} end }.should raise_error(DataMapper::Is::Slug::InvalidSlugSourceError) end it "should display obsolete warning if :size option is used" do module M class Thingy end end M::Thingy.stub!(:warn) M::Thingy.should_receive(:warn).with("Slug with :size option is deprecated, use :length instead") lambda { class M::Thingy include DataMapper::Resource property :id, Serial property :title, String is :slug, :source => :title, :size => 20 end }.should_not raise_error M.const_set 'Thingy', nil end it "should generate slugs" do User.all.each do |u| u.slug.should_not be_nil end Post.all.each do |p| p.slug.should_not be_nil end end it "should generate unique slugs" do @u1.slug.should_not == @u2.slug @p1.slug.should_not == @p4.slug end it "should generate correct slug for user" do @u1.slug.should == "john" @u2.slug.should == "john-2" end it "should generate correct slug for post" do @p1.slug.should == "my-first-shinny-blog-post" @p2.slug.should == "my-second-shinny-blog-post" @p3.slug.should == "my-third-shinny-blog-post" @p4.slug.should == "my-first-shinny-blog-post-2" @p5.slug.should == "i-heart-merb-and-dm" @p1_1.slug.should == "another-productive-day" (2..10).each do |i| instance_variable_get("@p1_#{i}".to_sym).slug.should == "another-productive-day-#{i}" end @p2_1.slug.should == 'dm-tricks' (2..10).each do |i| instance_variable_get("@p2_#{i}".to_sym).slug.should == "dm-tricks-#{i}" end end it "should update slug if :permanent_slug => :false is specified" do user = User.create(:email => "a_person@ekohe.com") user.slug.should == "a_person" user.should_not be_permanent_slug user.email = "changed@ekohe.com" user.should be_dirty user.save.should be_true user.slug.should == "changed" user.destroy end it "should not update slug if :permanent_slug => :true or not specified" do post = Post.create(:user => @u1, :title => "hello world!") post.slug.should == "hello-world" post.should be_permanent_slug post.title = "hello universe!" post.should be_dirty post.save.should be_true post.slug.should == "hello-world" post.destroy end it "should have the right size for properties" do user_slug_property = User.properties[:slug] user_slug_property.should_not be_nil user_slug_property.should be_an_instance_of(DataMapper::Property::String) user_slug_property.length.should == 80 post_title_property = Post.properties[:title] post_title_property.should be_an_instance_of(DataMapper::Property::String) post_title_property.length.should == 30 post_slug_property = Post.properties[:slug] post_slug_property.should be_an_instance_of(DataMapper::Property::String) post_slug_property.should_not be_nil post_slug_property.length.should == 30 end it "should output slug with to_param method" do @u1.to_param.should == ["john"] @p1.to_param.should == ["my-first-shinny-blog-post"] end it "should find model using get method using id" do u = User.get(@u1.id) u.should_not be_nil u.should == @u1 end it "should find model using get method using id with non-slug models" do todo = Todo.create(:user => @u1, :title => "blabla") todo.should_not be_nil Todo.get(todo.id).should == todo @u1.todos.get(todo.id).should == todo end it 'should unidecode latin characters from the slug' do @p6.slug.should == 'a-fancy-cafe' end it 'should unidecode chinese characters from the slug' do @p7.slug.should == 'ni-hao' end it 'should have slug_property on instance' do @p1.slug_property.should == @p1.class.properties.detect{|p| p.name == :slug} end it 'should properly increment slug suffix' do @p2_10.slug.should == 'dm-tricks-10' end it 'should work with key on slug and validations' do @sk.title.should == 'slug key' @sk.slug.should == 'slug-key' end it 'should have slug no longer than slug_property.length' do @post1.slug.length.should == @post1.slug_property.length end it 'should have suffixed slug no longer than slug_property.length' do @post2.slug.length.should == @post2.class.slug_property.length end it 'should generate right slug for long sources' do @post1.slug.should == 'a' * @post1.class.slug_property.length @post2.slug.should == ('a' * (@post2.class.slug_property.length - 2) + '-2') end describe 'editing' do before :each do Post2.all.destroy! @post = Post2.create :title => 'The Post', :content => 'The content.' end it 'should not change slug if source is not changed' do @post.update(:content => 'The other content.').should be_true @post.reload @post.slug.should == 'the-post' end it 'should change slug if source is changed' do @post.update :title => 'The Other Post' post = Post2.first post.slug.should == 'the-other-post' end end describe 'scoping' do before :each do Task.all.destroy! end it 'should allow duplicate slugs within different scopes' do t1 = Task.create :category => 'programming', :title => 'fix' t1.slug.should == 'fix' t2 = Task.create :category => 'plumbing', :title => 'fix' t2.slug.should == 'fix' end it 'should not allow dupliate slugs within same scope' do t1 = Task.create :category => 'programming', :title => 'fix' t1.slug.should == 'fix' t2 = Task.create :category => 'programming', :title => 'fix' t2.slug.should == 'fix-2' end it 'should recalculate slug upon change of scope' do t1 = Task.create :category => 'programming', :title => 'fix' t1.slug.should == 'fix' t2 = Task.create :category => 'plumbing', :title => 'fix' t2.slug.should == 'fix' t2.category = 'programming' t2.save t2.slug.should == 'fix-2' end it 'should keep slug if scope did not change' do t1 = Task.create :category => 'programming', :title => 'fix' t1.slug.should == 'fix' t2 = Task.create :category => 'plumbing', :title => 'fix' t2.slug.should == 'fix' t2.description = 'copper pipes are good' t2.save t2.slug.should == 'fix' end end end end