geothird_friendly_id 4.0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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