geothird_friendly_id 4.0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +12 -0
  4. data/.travis.yml +20 -0
  5. data/.yardopts +4 -0
  6. data/Changelog.md +86 -0
  7. data/Gemfile +15 -0
  8. data/Guide.rdoc +553 -0
  9. data/MIT-LICENSE +19 -0
  10. data/README.md +150 -0
  11. data/Rakefile +108 -0
  12. data/WhatsNew.md +95 -0
  13. data/bench.rb +63 -0
  14. data/friendly_id.gemspec +43 -0
  15. data/gemfiles/Gemfile.rails-3.0.rb +21 -0
  16. data/gemfiles/Gemfile.rails-3.1.rb +22 -0
  17. data/gemfiles/Gemfile.rails-3.2.rb +22 -0
  18. data/geothird_friendly_id.gemspec +43 -0
  19. data/lib/friendly_id/base.rb +291 -0
  20. data/lib/friendly_id/configuration.rb +80 -0
  21. data/lib/friendly_id/finder_methods.rb +35 -0
  22. data/lib/friendly_id/globalize.rb +115 -0
  23. data/lib/friendly_id/history.rb +134 -0
  24. data/lib/friendly_id/migration.rb +18 -0
  25. data/lib/friendly_id/object_utils.rb +50 -0
  26. data/lib/friendly_id/reserved.rb +68 -0
  27. data/lib/friendly_id/scoped.rb +149 -0
  28. data/lib/friendly_id/simple_i18n.rb +95 -0
  29. data/lib/friendly_id/slug.rb +14 -0
  30. data/lib/friendly_id/slug_generator.rb +80 -0
  31. data/lib/friendly_id/slugged.rb +329 -0
  32. data/lib/friendly_id.rb +114 -0
  33. data/lib/generators/friendly_id_generator.rb +17 -0
  34. data/test/base_test.rb +72 -0
  35. data/test/compatibility/ancestry/Gemfile +8 -0
  36. data/test/compatibility/ancestry/ancestry_test.rb +34 -0
  37. data/test/compatibility/threading/Gemfile +8 -0
  38. data/test/compatibility/threading/Gemfile.lock +37 -0
  39. data/test/compatibility/threading/threading.rb +45 -0
  40. data/test/configuration_test.rb +48 -0
  41. data/test/core_test.rb +48 -0
  42. data/test/databases.yml +19 -0
  43. data/test/generator_test.rb +20 -0
  44. data/test/globalize_test.rb +57 -0
  45. data/test/helper.rb +87 -0
  46. data/test/history_test.rb +149 -0
  47. data/test/object_utils_test.rb +28 -0
  48. data/test/reserved_test.rb +40 -0
  49. data/test/schema.rb +79 -0
  50. data/test/scoped_test.rb +83 -0
  51. data/test/shared.rb +156 -0
  52. data/test/simple_i18n_test.rb +133 -0
  53. data/test/slugged_test.rb +280 -0
  54. data/test/sti_test.rb +77 -0
  55. metadata +247 -0
@@ -0,0 +1,48 @@
1
+ require "helper"
2
+
3
+ class ConfigurationTest < MiniTest::Unit::TestCase
4
+
5
+ include FriendlyId::Test
6
+
7
+ def setup
8
+ @model_class = Class.new(ActiveRecord::Base) do
9
+ self.abstract_class = true
10
+ end
11
+ end
12
+
13
+ test "should set model class on initialization" do
14
+ config = FriendlyId::Configuration.new @model_class
15
+ assert_equal @model_class, config.model_class
16
+ end
17
+
18
+ test "should set options on initialization if present" do
19
+ config = FriendlyId::Configuration.new @model_class, :base => "hello"
20
+ assert_equal "hello", config.base
21
+ end
22
+
23
+ test "should raise error if passed unrecognized option" do
24
+ assert_raises NoMethodError do
25
+ FriendlyId::Configuration.new @model_class, :foo => "bar"
26
+ end
27
+ end
28
+
29
+ test "#use should accept a name that resolves to a module" do
30
+ refute @model_class < FriendlyId::Slugged
31
+ @model_class.class_eval do
32
+ extend FriendlyId
33
+ friendly_id :hello, :use => :slugged
34
+ end
35
+ assert @model_class < FriendlyId::Slugged
36
+ end
37
+
38
+ test "#use should accept a module" do
39
+ my_module = Module.new
40
+ refute @model_class < my_module
41
+ @model_class.class_eval do
42
+ extend FriendlyId
43
+ friendly_id :hello, :use => my_module
44
+ end
45
+ assert @model_class < my_module
46
+ end
47
+
48
+ end
data/test/core_test.rb ADDED
@@ -0,0 +1,48 @@
1
+ require "helper"
2
+
3
+ class Book < ActiveRecord::Base
4
+ extend FriendlyId
5
+ friendly_id :name
6
+ end
7
+
8
+ class Author < ActiveRecord::Base
9
+ extend FriendlyId
10
+ friendly_id :name
11
+ has_many :books
12
+ end
13
+
14
+ class CoreTest < MiniTest::Unit::TestCase
15
+
16
+ include FriendlyId::Test
17
+ include FriendlyId::Test::Shared::Core
18
+
19
+ def model_class
20
+ Author
21
+ end
22
+
23
+ test "models don't use friendly_id by default" do
24
+ assert !Class.new(ActiveRecord::Base) {
25
+ self.abstract_class = true
26
+ }.respond_to?(:friendly_id)
27
+ end
28
+
29
+ test "model classes should have a friendly id config" do
30
+ assert model_class.friendly_id(:name).friendly_id_config
31
+ end
32
+
33
+ test "instances should have a friendly id" do
34
+ with_instance_of(model_class) {|record| assert record.friendly_id}
35
+ end
36
+
37
+ test "instances can be marshaled when a relationship is used" do
38
+ transaction do
39
+ author = Author.create :name => 'Philip'
40
+ author.books.create :name => 'my book'
41
+ begin
42
+ assert Marshal.load(Marshal.dump(author))
43
+ rescue TypeError => e
44
+ flunk(e.to_s)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,19 @@
1
+ mysql:
2
+ adapter: mysql2
3
+ database: friendly_id_test
4
+ username: root
5
+ hostname: localhost
6
+ encoding: utf8
7
+
8
+ postgres:
9
+ adapter: postgresql
10
+ host: localhost
11
+ port: 5432
12
+ username: postgres
13
+ database: friendly_id_test
14
+ encoding: utf8
15
+
16
+ sqlite3:
17
+ adapter: sqlite3
18
+ database: ":memory:"
19
+ encoding: utf8
@@ -0,0 +1,20 @@
1
+ require "helper"
2
+ require "rails/generators"
3
+ require "generators/friendly_id_generator"
4
+
5
+ class FriendlyIdGeneratorTest < Rails::Generators::TestCase
6
+
7
+ tests FriendlyIdGenerator
8
+ destination File.expand_path("../../tmp", __FILE__)
9
+
10
+ setup :prepare_destination
11
+
12
+ test "should generate a migration" do
13
+ begin
14
+ run_generator
15
+ assert_migration "db/migrate/create_friendly_id_slugs"
16
+ ensure
17
+ FileUtils.rm_rf self.destination_root
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+
3
+ require "helper"
4
+
5
+ class TranslatedArticle < ActiveRecord::Base
6
+ translates :slug, :title
7
+ extend FriendlyId
8
+ friendly_id :title, :use => :globalize
9
+ end
10
+
11
+ class GlobalizeTest < MiniTest::Unit::TestCase
12
+ include FriendlyId::Test
13
+
14
+ def setup
15
+ I18n.locale = :en
16
+ end
17
+
18
+ test "should find slug in current locale if locale is set, otherwise in default locale" do
19
+ transaction do
20
+ I18n.default_locale = :en
21
+ article_en = I18n.with_locale(:en) { TranslatedArticle.create(:title => 'a title') }
22
+ article_de = I18n.with_locale(:de) { TranslatedArticle.create(:title => 'titel') }
23
+
24
+ I18n.with_locale(:de) {
25
+ assert_equal TranslatedArticle.find("titel"), article_de
26
+ assert_equal TranslatedArticle.find("a-title"), article_en
27
+ }
28
+ end
29
+ end
30
+
31
+ test "should set friendly id for locale" do
32
+ transaction do
33
+ article = TranslatedArticle.create!(:title => "War and Peace")
34
+ article.set_friendly_id("Guerra y paz", :es)
35
+ article.save!
36
+ article = TranslatedArticle.find('war-and-peace')
37
+ I18n.with_locale(:es) { assert_equal "guerra-y-paz", article.friendly_id }
38
+ I18n.with_locale(:en) { assert_equal "war-and-peace", article.friendly_id }
39
+ end
40
+ end
41
+
42
+ # https://github.com/svenfuchs/globalize3/blob/master/test/globalize3/dynamic_finders_test.rb#L101
43
+ # see: https://github.com/svenfuchs/globalize3/issues/100
44
+ test "record returned by friendly_id should have all translations" do
45
+ transaction do
46
+ I18n.with_locale(:en) do
47
+ article = TranslatedArticle.create(:title => 'a title')
48
+ Globalize.with_locale(:ja) { article.update_attributes(:title => 'タイトル') }
49
+ article_by_friendly_id = TranslatedArticle.find("a-title")
50
+ article.translations.each do |translation|
51
+ assert_includes article_by_friendly_id.translations, translation
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,87 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require "minitest/unit"
4
+ require "mocha"
5
+ require "active_record"
6
+ require 'active_support/core_ext/time/conversions'
7
+
8
+
9
+ if ENV["COVERAGE"]
10
+ require 'simplecov'
11
+ SimpleCov.start do
12
+ add_filter "test/"
13
+ add_filter "friendly_id/migration"
14
+ end
15
+ end
16
+
17
+ require "friendly_id"
18
+
19
+ # If you want to see the ActiveRecord log, invoke the tests using `rake test LOG=true`
20
+ if ENV["LOG"]
21
+ require "logger"
22
+ ActiveRecord::Base.logger = Logger.new($stdout)
23
+ end
24
+
25
+ module FriendlyId
26
+ module Test
27
+
28
+ def self.included(base)
29
+ MiniTest::Unit.autorun
30
+ end
31
+
32
+ def transaction
33
+ ActiveRecord::Base.transaction { yield ; raise ActiveRecord::Rollback }
34
+ end
35
+
36
+ def with_instance_of(*args)
37
+ model_class = args.shift
38
+ args[0] ||= {:name => "a b c"}
39
+ transaction { yield model_class.create!(*args) }
40
+ end
41
+
42
+ module Database
43
+ extend self
44
+
45
+ def connect
46
+ version = ActiveRecord::VERSION::STRING
47
+ driver = FriendlyId::Test::Database.driver
48
+ engine = RUBY_ENGINE rescue "ruby"
49
+
50
+ ActiveRecord::Base.establish_connection config[driver]
51
+ message = "Using #{engine} #{RUBY_VERSION} AR #{version} with #{driver}"
52
+
53
+ puts "-" * 72
54
+ if in_memory?
55
+ ActiveRecord::Migration.verbose = false
56
+ Schema.up
57
+ puts "#{message} (in-memory)"
58
+ else
59
+ puts message
60
+ end
61
+ end
62
+
63
+ def config
64
+ @config ||= YAML::load(File.open(File.expand_path("../databases.yml", __FILE__)))
65
+ end
66
+
67
+ def driver
68
+ (ENV["DB"] or "sqlite3").downcase
69
+ end
70
+
71
+ def in_memory?
72
+ config[driver]["database"] == ":memory:"
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ class Module
79
+ def test(name, &block)
80
+ define_method("test_#{name.gsub(/[^a-z0-9']/i, "_")}".to_sym, &block)
81
+ end
82
+ end
83
+
84
+ require "schema"
85
+ require "shared"
86
+ FriendlyId::Test::Database.connect
87
+ at_exit {ActiveRecord::Base.connection.disconnect!}
@@ -0,0 +1,149 @@
1
+ require "helper"
2
+
3
+ class Manual < ActiveRecord::Base
4
+ extend FriendlyId
5
+ friendly_id :name, :use => :history
6
+ end
7
+
8
+ class HistoryTest < MiniTest::Unit::TestCase
9
+
10
+ include FriendlyId::Test
11
+ include FriendlyId::Test::Shared::Core
12
+
13
+ def model_class
14
+ Manual
15
+ end
16
+
17
+ test "should insert record in slugs table on create" do
18
+ with_instance_of(model_class) {|record| assert record.slugs.any?}
19
+ end
20
+
21
+ test "should not create new slug record if friendly_id is not changed" do
22
+ with_instance_of(model_class) do |record|
23
+ record.active = true
24
+ record.save!
25
+ assert_equal 1, FriendlyId::Slug.count
26
+ end
27
+ end
28
+
29
+ test "should create new slug record when friendly_id changes" do
30
+ with_instance_of(model_class) do |record|
31
+ record.name = record.name + "b"
32
+ record.save!
33
+ assert_equal 2, FriendlyId::Slug.count
34
+ end
35
+ end
36
+
37
+ test "should be findable by old slugs" do
38
+ with_instance_of(model_class) do |record|
39
+ old_friendly_id = record.friendly_id
40
+ record.name = record.name + "b"
41
+ record.save!
42
+ begin
43
+ assert model_class.find(old_friendly_id)
44
+ assert model_class.exists?(old_friendly_id), "should exist? by old id"
45
+ rescue ActiveRecord::RecordNotFound
46
+ flunk "Could not find record by old id"
47
+ end
48
+ end
49
+ end
50
+
51
+ test "should create slug records on each change" do
52
+ transaction do
53
+ record = model_class.create! :name => "hello"
54
+ assert_equal 1, FriendlyId::Slug.count
55
+ record = model_class.find("hello")
56
+ record.name = "hello again"
57
+ record.save!
58
+ assert_equal 2, FriendlyId::Slug.count
59
+ end
60
+ end
61
+
62
+ test "should not be read only when found by old slug" do
63
+ with_instance_of(model_class) do |record|
64
+ old_friendly_id = record.friendly_id
65
+ record.name = record.name + "b"
66
+ record.save!
67
+ assert !model_class.find(old_friendly_id).readonly?
68
+ end
69
+ end
70
+
71
+ test "should create correct sequence numbers even when some conflicted slugs have changed" do
72
+ transaction do
73
+ record1 = model_class.create! :name => 'hello'
74
+ record2 = model_class.create! :name => 'hello!'
75
+ record2.update_attributes :name => 'goodbye'
76
+ record3 = model_class.create! :name => 'hello!'
77
+ assert_equal 'hello--3', record3.slug
78
+ end
79
+ end
80
+
81
+
82
+ test "should raise error if used with scoped" do
83
+ model_class = Class.new(ActiveRecord::Base) do
84
+ self.abstract_class = true
85
+ extend FriendlyId
86
+ end
87
+ assert_raises RuntimeError do
88
+ model_class.friendly_id :name, :use => [:history, :scoped]
89
+ end
90
+ end
91
+
92
+ test "should handle renames" do
93
+ with_instance_of(model_class) do |record|
94
+ record.name = 'x'
95
+ assert record.save
96
+ record.name = 'y'
97
+ assert record.save
98
+ record.name = 'x'
99
+ assert record.save
100
+ end
101
+ end
102
+
103
+ test "should not create new slugs that match old slugs" do
104
+ transaction do
105
+ first_record = model_class.create! :name => "foo"
106
+ first_record.name = "bar"
107
+ first_record.save!
108
+ second_record = model_class.create! :name => "foo"
109
+ assert second_record.slug != "foo"
110
+ assert second_record.slug == "foo--2"
111
+ end
112
+ end
113
+
114
+ test 'should increment the sequence by one for each historic slug' do
115
+ transaction do
116
+ previous_record = model_class.create! :name => "foo"
117
+ first_record = model_class.create! :name => 'another'
118
+ second_record = model_class.create! :name => 'another'
119
+ assert second_record.slug == "another--2"
120
+ end
121
+ end
122
+
123
+ test 'should not fail when updating historic slugs' do
124
+ transaction do
125
+ first_record = model_class.create! :name => "foo"
126
+ second_record = model_class.create! :name => 'another'
127
+
128
+ second_record.update_attributes :name => 'foo'
129
+ assert second_record.slug == "foo--2"
130
+ first_record.update_attributes :name => 'another'
131
+ assert first_record.slug == "another--2"
132
+ end
133
+ end
134
+
135
+ end
136
+
137
+ class HistoryTestWithSti < HistoryTest
138
+ class Journalist < ActiveRecord::Base
139
+ extend FriendlyId
140
+ friendly_id :name, :use => [:slugged, :history]
141
+ end
142
+
143
+ class Editorialist < Journalist
144
+ end
145
+
146
+ def model_class
147
+ Editorialist
148
+ end
149
+ end
@@ -0,0 +1,28 @@
1
+ require "helper"
2
+
3
+
4
+ class ObjectUtilsTest < MiniTest::Unit::TestCase
5
+
6
+ include FriendlyId::Test
7
+
8
+ test "strings with letters are friendly_ids" do
9
+ assert "a".friendly_id?
10
+ end
11
+
12
+ test "integers should be unfriendly ids" do
13
+ assert 1.unfriendly_id?
14
+ end
15
+
16
+ test "numeric strings are neither friendly nor unfriendly" do
17
+ assert_equal nil, "1".friendly_id?
18
+ assert_equal nil, "1".unfriendly_id?
19
+ end
20
+
21
+ test "ActiveRecord::Base instances should be unfriendly_ids" do
22
+ model_class = Class.new(ActiveRecord::Base) do
23
+ self.abstract_class = true
24
+ self.table_name = "authors"
25
+ end
26
+ assert model_class.new.unfriendly_id?
27
+ end
28
+ end
@@ -0,0 +1,40 @@
1
+ require "helper"
2
+
3
+ class ReservedTest < MiniTest::Unit::TestCase
4
+
5
+ include FriendlyId::Test
6
+
7
+ class Journalist < ActiveRecord::Base
8
+ extend FriendlyId
9
+ friendly_id :name
10
+
11
+ after_validation :move_friendly_id_error_to_name
12
+
13
+ def move_friendly_id_error_to_name
14
+ errors.add :name, *errors.delete(:friendly_id) if errors[:friendly_id].present?
15
+ end
16
+ end
17
+
18
+ def model_class
19
+ Journalist
20
+ end
21
+
22
+ test "should reserve 'new' and 'edit' by default" do
23
+ %w(new edit).each do |word|
24
+ transaction do
25
+ assert_raises(ActiveRecord::RecordInvalid) {model_class.create! :name => word}
26
+ end
27
+ end
28
+ end
29
+
30
+ test "should move friendly_id error to name" do
31
+ with_instance_of(model_class) do |record|
32
+ record.errors.add :name, "xxx"
33
+ record.errors.add :friendly_id, "yyy"
34
+ record.move_friendly_id_error_to_name
35
+ assert record.errors[:name].present? && record.errors[:friendly_id].blank?
36
+ assert_equal 2, record.errors.count
37
+ end
38
+ end
39
+
40
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,79 @@
1
+ require "friendly_id/migration"
2
+ require "globalize3"
3
+
4
+ class TranslatedArticle < ActiveRecord::Base
5
+ translates :slug, :title
6
+ end
7
+
8
+ module FriendlyId
9
+ module Test
10
+ class Schema < ActiveRecord::Migration
11
+ class << self
12
+ def down
13
+ CreateFriendlyIdSlugs.down
14
+ tables.each do |name|
15
+ drop_table name
16
+ end
17
+ TranslatedArticle.drop_translation_table!
18
+ end
19
+
20
+ def up
21
+ # TODO: use schema version to avoid ugly hacks like this
22
+ return if @done
23
+ CreateFriendlyIdSlugs.up
24
+
25
+ tables.each do |table_name|
26
+ create_table table_name do |t|
27
+ t.string :name
28
+ t.boolean :active
29
+ end
30
+ end
31
+
32
+ slugged_tables.each do |table_name|
33
+ add_column table_name, :slug, :string
34
+ add_index table_name, :slug, :unique => true
35
+ end
36
+
37
+ # This will be used to test scopes
38
+ add_column :novels, :novelist_id, :integer
39
+ add_column :novels, :publisher_id, :integer
40
+ remove_index :novels, :slug
41
+ add_index :novels, [:slug, :publisher_id, :novelist_id], :unique => true
42
+
43
+ # This will be used to test column name quoting
44
+ add_column :journalists, "strange name", :string
45
+
46
+ # This will be used to test STI
47
+ add_column :journalists, "type", :string
48
+
49
+ # These will be used to test i18n
50
+ add_column :journalists, "slug_en", :string
51
+ add_column :journalists, "slug_es", :string
52
+ add_column :journalists, "slug_de", :string
53
+
54
+ # This will be used to test globalize translations
55
+ TranslatedArticle.create_translation_table! :slug => :string, :title => :string
56
+
57
+ # This will be used to test relationships
58
+ add_column :books, :author_id, :integer
59
+
60
+ @done = true
61
+ end
62
+
63
+ private
64
+
65
+ def slugged_tables
66
+ %w[journalists articles novelists novels manuals translated_articles]
67
+ end
68
+
69
+ def simple_tables
70
+ %w[authors books publishers]
71
+ end
72
+
73
+ def tables
74
+ simple_tables + slugged_tables
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,83 @@
1
+ require "helper"
2
+
3
+ class Novelist < ActiveRecord::Base
4
+ extend FriendlyId
5
+ friendly_id :name, :use => :slugged
6
+ end
7
+
8
+ class Novel < ActiveRecord::Base
9
+ extend FriendlyId
10
+ belongs_to :novelist
11
+ belongs_to :publisher
12
+ friendly_id :name, :use => :scoped, :scope => [:publisher, :novelist]
13
+ end
14
+
15
+ class Publisher < ActiveRecord::Base
16
+ has_many :novels
17
+ end
18
+
19
+ class ScopedTest < MiniTest::Unit::TestCase
20
+
21
+ include FriendlyId::Test
22
+ include FriendlyId::Test::Shared::Core
23
+
24
+ def model_class
25
+ Novel
26
+ end
27
+
28
+ test "should detect scope column from belongs_to relation" do
29
+ assert_equal ["publisher_id", "novelist_id"], Novel.friendly_id_config.scope_columns
30
+ end
31
+
32
+ test "should detect scope column from explicit column name" do
33
+ model_class = Class.new(ActiveRecord::Base) do
34
+ self.abstract_class = true
35
+ extend FriendlyId
36
+ friendly_id :empty, :use => :scoped, :scope => :dummy
37
+ end
38
+ assert_equal ["dummy"], model_class.friendly_id_config.scope_columns
39
+ end
40
+
41
+ test "should allow duplicate slugs outside scope" do
42
+ transaction do
43
+ novel1 = Novel.create! :name => "a", :novelist => Novelist.create!(:name => "a")
44
+ novel2 = Novel.create! :name => "a", :novelist => Novelist.create!(:name => "b")
45
+ assert_equal novel1.friendly_id, novel2.friendly_id
46
+ end
47
+ end
48
+
49
+ test "should not allow duplicate slugs inside scope" do
50
+ with_instance_of Novelist do |novelist|
51
+ novel1 = Novel.create! :name => "a", :novelist => novelist
52
+ novel2 = Novel.create! :name => "a", :novelist => novelist
53
+ assert novel1.friendly_id != novel2.friendly_id
54
+ end
55
+ end
56
+
57
+ test "should raise error if used with history" do
58
+ model_class = Class.new(ActiveRecord::Base) do
59
+ self.abstract_class = true
60
+ extend FriendlyId
61
+ end
62
+
63
+ assert_raises RuntimeError do
64
+ model_class.friendly_id :name, :use => [:scoped, :history]
65
+ end
66
+ end
67
+
68
+ test "should apply scope with multiple columns" do
69
+ transaction do
70
+ novelist = Novelist.create! :name => "a"
71
+ publisher = Publisher.create! :name => "b"
72
+
73
+ novel1 = Novel.create! :name => "c", :novelist => novelist, :publisher => publisher
74
+ novel2 = Novel.create! :name => "c", :novelist => novelist, :publisher => Publisher.create(:name => "d")
75
+ novel3 = Novel.create! :name => "c", :novelist => Novelist.create(:name => "e"), :publisher => publisher
76
+ novel4 = Novel.create! :name => "c", :novelist => novelist, :publisher => publisher
77
+
78
+ assert_equal novel1.friendly_id, novel2.friendly_id
79
+ assert_equal novel2.friendly_id, novel3.friendly_id
80
+ assert novel3.friendly_id != novel4.friendly_id
81
+ end
82
+ end
83
+ end