# encoding: utf-8 require File.dirname(__FILE__) + '/test_helper' class SluggedModelTest < Test::Unit::TestCase context "A slugged model with default FriendlyId options" do setup do Post.friendly_id_options = FriendlyId::DEFAULT_FRIENDLY_ID_OPTIONS.merge(:column => :title, :use_slug => true) Post.delete_all Person.delete_all Slug.delete_all Thing.delete_all @post = Post.new :title => "Test post", :content => "Test content", :published => true @post.save! end should "have friendly_id options" do assert_not_nil Post.friendly_id_options end should "have a slug" do assert_not_nil @post.slug end should "be findable by its friendly_id" do assert Post.find(@post.friendly_id) end should "be findable by its regular id" do assert Post.find(@post.id) end should "generate slug text" do post = Post.new :title => "Test post", :content => "Test content" assert_not_nil @post.slug_text end should "respect finder conditions" do assert_raises ActiveRecord::RecordNotFound do Post.find(@post.friendly_id, :conditions => "1 = 2") end end should "raise an error if the friendly_id text is reserved" do assert_raises(FriendlyId::SlugGenerationError) do Post.create!(:title => "new") end end should "raise an error if the friendly_id text is blank" do assert_raises(FriendlyId::SlugGenerationError) do Post.create(:title => "") end end should "raise an error if the normalized friendly id becomes blank" do assert_raises(FriendlyId::SlugGenerationError) do post = Post.create!(:title => "-.-") end end should "not make a new slug unless the friendly_id method value has changed" do @post.content = "Changed content" @post.save! assert_equal 1, @post.slugs.size end should "make a new slug if the friendly_id method value has changed" do @post.title = "Changed title" @post.save! assert_equal 2, @post.slugs.size end should "have a slug sequence of 1 by default" do assert_equal 1, @post.slug.sequence end should "increment sequence for duplicate slug names" do @post2 = Post.create! :title => @post.title, :content => "Test content for post2" assert_equal 2, @post2.slug.sequence end should "have a friendly_id that terminates with -- and the slug sequence if the sequence is greater than 1" do @post2 = Post.create! :title => @post.title, :content => "Test content for post2" assert_match(/--2\z/, @post2.friendly_id) end should "allow datetime columns to be used as slugs" do assert Event.create(:name => "Test", :event_date => DateTime.now) end should "not strip diacritics" do @post = Post.new(:title => "¡Feliz año!") assert_match(/#{'ñ'}/, @post.slug_text) end should "not convert to ASCII" do @post = Post.new(:title => "katakana: ゲコゴサザシジ") assert_equal "katakana-ゲコゴサザシジ", @post.slug_text end should "allow the same friendly_id across models" do @person = Person.create!(:name => @post.title) assert_equal @person.friendly_id, @post.friendly_id end should "truncate slug text longer than the max length" do @post = Post.new(:title => "a" * (Post.friendly_id_options[:max_length] + 1)) assert_equal @post.slug_text.length, Post.friendly_id_options[:max_length] end should "be able to reuse an old friendly_id without incrementing the sequence" do old_title = @post.title old_friendly_id = @post.friendly_id @post.title = "A changed title" @post.save! @post.title = old_title @post.save! assert_equal old_friendly_id, @post.friendly_id end should "allow eager loading of slugs" do assert_nothing_raised do Post.find(@post.friendly_id, :include => :slugs) end end # This emulates a fairly common issue where id's generated by fixtures are very high. should "continue to admit very large ids" do Thing.connection.execute("INSERT INTO things (id, name) VALUES (2147483647, 'big')") assert Thing.find(2147483647) end context "and configured to strip diacritics" do setup do Post.friendly_id_options = Post.friendly_id_options.merge(:strip_diacritics => true) end should "strip diacritics from Roman alphabet based characters" do @post = Post.new(:title => "¡Feliz año!") assert_no_match(/#{'ñ'}/, @post.slug_text) end end context "and configured to convert to ASCII" do setup do Post.friendly_id_options = Post.friendly_id_options.merge(:strip_non_ascii => true) end should "strip non-ascii characters" do @post = Post.new(:title => "katakana: ゲコゴサザシジ") assert_equal "katakana", @post.slug_text end end context "that doesn't have a slug" do setup do @post.slug.destroy @post = Post.find(@post.id) end should "have a to_param method that returns the id cast to a string" do assert_equal @post.id.to_s, @post.to_param end end context "when found using its friendly_id" do setup do @post = Post.find(@post.friendly_id) end should "indicate that it was found using the friendly_id" do assert @post.found_using_friendly_id? end should "not indicate that it has a better id" do assert !@post.has_better_id? end should "not indicate that it was found using its numeric id" do assert !@post.found_using_numeric_id? end should "have a finder slug" do assert_not_nil @post.finder_slug end end context "when found using its regular id" do setup do @post = Post.find(@post.id) end should "indicate that it was not found using the friendly id" do assert !@post.found_using_friendly_id? end should "indicate that it has a better id" do assert @post.has_better_id? end should "indicate that it was found using its numeric id" do assert @post.found_using_numeric_id? end should "not have a finder slug" do assert_nil @post.finder_slug end end context "when found using an outdated friendly id" do setup do old_id = @post.friendly_id @post.title = "Title changed" @post.save! @post = Post.find(old_id) end should "indicate that it was found using a friendly_id" do assert @post.found_using_friendly_id? end should "indicate that it has a better id" do assert @post.has_better_id? end should "not indicate that it was found using its numeric id" do assert !@post.found_using_numeric_id? end should "should have a finder slug different from its default slug" do assert_not_equal @post.slug, @post.finder_slug end end context "when using an array as the find argument" do setup do @post2 = Post.create!(:title => "another post", :content => "more content", :published => true) end should "return results when passed an array of non-friendly ids" do assert_equal 2, Post.find([@post.id, @post2.id]).size end should "return results when passed an array of friendly ids" do assert_equal 2, Post.find([@post.friendly_id, @post2.friendly_id]).size end should "return results when searching using a named scope" do assert_equal 2, Post.published.find([@post.id, @post2.id]).size end should "return results when passed a mixed array of friendly and non-friendly ids" do assert_equal 2, Post.find([@post.friendly_id, @post2.id]).size end should "return results when passed an array of non-friendly ids, of which one represents a record with multiple slugs" do @post2.update_attributes(:title => 'another post [updated]') assert_equal 2, Post.find([@post.id, @post2.id]).size end should "indicate that the results were found using a friendly_id" do @posts = Post.find [@post.friendly_id, @post2.friendly_id] @posts.each { |p| assert p.found_using_friendly_id? } end should "raise an error when all records are not found" do assert_raises(ActiveRecord::RecordNotFound) do Post.find([@post.friendly_id, 'non-existant-slug-record']) end end should "allow eager loading of slugs" do assert_nothing_raised do Post.find([@post.friendly_id, @post2.friendly_id], :include => :slugs) end end end end end