friendly_id 5.2.0.beta.1 → 5.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d11cd5a5fc78a05718add4cf44e44f4425700f02
4
- data.tar.gz: 581623a3a24eff70d1e0ee307bdcaf814631a80c
3
+ metadata.gz: 606af0800382602b2f88d11be3a839a3e8c23255
4
+ data.tar.gz: a501dd78829d595fe897475bdf4a6c6d98caee9c
5
5
  SHA512:
6
- metadata.gz: 9068ff6f4efaab2c47673eb31b5f700898d5fad4f3d6f3fa754e7b9f9264ee1b02689637af319995c83a2b0771a40d7c70ce422b112e8337b0281ba42a5e41bb
7
- data.tar.gz: 5726a377bc4573bfb59cbfdc0d0d4abe224516bd691017299809da5304abd51477da9c8c7bb0f48916afd44b4de9b77ddc81716e0e9be69e24427018eb7abe51
6
+ metadata.gz: cb2afe89084b532541152c46056649ec6bfca0a2fe51493706f7f996ee233bae010a248a735fb55451e89b1918b29e60b5471e78c0272f29a5c5c410220eacc8
7
+ data.tar.gz: 8a527f735585ce88c1627bc54f206745f69a826d27574f6d306ee4a29dff23421e82225b0b9e9751cdd5a3a9911f3dba755d10d7a9951758052a3bd869b26441
data/.travis.yml CHANGED
@@ -2,11 +2,11 @@ language: ruby
2
2
  cache: bundler
3
3
 
4
4
  rvm:
5
+ - 2.3.0
5
6
  - 2.2.0
6
- - 2.0.0
7
7
  - 2.1.0
8
- - jruby-19mode
9
- - rbx-2
8
+ - 2.0.0
9
+ - jruby-9.0.4.0
10
10
 
11
11
  env:
12
12
  - DB=postgres
@@ -16,15 +16,26 @@ gemfile:
16
16
  - gemfiles/Gemfile.rails-4.0.rb
17
17
  - gemfiles/Gemfile.rails-4.1.rb
18
18
  - gemfiles/Gemfile.rails-4.2.rb
19
+ - gemfiles/Gemfile.rails-5.0.rb
19
20
 
20
21
  matrix:
21
22
  allow_failures:
22
23
  - rvm: jruby-19mode
23
24
  gemfile: gemfiles/Gemfile.rails-4.2.rb
24
25
  env: DB=postgres
26
+ - rvm: jruby-9.0.4.0
27
+ gemfile: gemfiles/Gemfile.rails-5.0.rb
28
+ exclude:
29
+ - rvm: 2.0.0
30
+ gemfile: gemfiles/Gemfile.rails-5.0.rb
31
+ - rvm: 2.1.0
32
+ gemfile: gemfiles/Gemfile.rails-5.0.rb
33
+ - rvm: 2.2.0
34
+ gemfile: gemfiles/Gemfile.rails-5.0.rb
25
35
 
26
36
  sudo: false
27
37
 
28
- before_script: 'bundle exec rake db:create db:up'
38
+ before_script:
39
+ - bundle exec rake db:create db:up
29
40
 
30
41
  script: 'COVERALLS=true bundle exec rake test'
data/CONTRIBUTING.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Please ask questions on [Stack
4
4
  Overflow](http://stackoverflow.com/questions/tagged/friendly-id) using the
5
5
  "friendly_id" or "friendly-id" tag. Prior to asking, search and see if your
6
- question has already been anwered.
6
+ question has already been answered.
7
7
 
8
8
  Please only post issues in Github issues for actual bugs.
9
9
 
data/Changelog.md CHANGED
@@ -1,15 +1,19 @@
1
1
  # FriendlyId Changelog
2
2
 
3
- We would like to think our many {file:Contributors contributors} for
3
+ We would like to think our many [contributors](https://github.com/norman/friendly_id/graphs/contributors) for
4
4
  suggestions, ideas and improvements to FriendlyId.
5
5
 
6
- ## 5.2.0 (NOT RELEASED YET)
6
+ ## 5.2.0 (2016-12-01)
7
7
 
8
8
  * Add sequential slug module for FriendlyId 4.x-style sequential slugs. ([#644](https://github.com/norman/friendly_id/pull/644)).
9
9
  * Make Candidates#each iterable without block ([#651](https://github.com/norman/friendly_id/pull/651)).
10
10
  * Ensure slug history prefers the record that most recently used the slug ([#663](https://github.com/norman/friendly_id/pull/663)).
11
11
  * Don't calculate all changes just to check if the param field has changed ([#667](https://github.com/norman/friendly_id/pull/667)).
12
12
  * Don't set or change slug when unrelated validation failures block the record from being saved ([#642](https://github.com/norman/friendly_id/issues/642)).
13
+ * Fix order dependence bug between history and finders modules ([#718](https://github.com/norman/friendly_id/pull/718))
14
+ * Added ability to conditionally turn off :dependent => :destory on FriendlyId::Slugs([#724](https://github.com/norman/friendly_id/pull/724))
15
+ * Add support for Rails 5. ([#728](https://github.com/norman/friendly_id/pull/728))
16
+ * Allow per-model conditional disabling of friendly path generation using a :routes option to friendly_id ([#735](https://github.com/norman/friendly_id/pull/735))
13
17
 
14
18
  ## 5.1.0 (2015-01-15)
15
19
 
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008-2014 Norman Clarke, Adrian Mugnolo and Emilio Tagua.
1
+ Copyright (c) 2008-2016 Norman Clarke, Adrian Mugnolo and Emilio Tagua.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -16,7 +16,7 @@ over and over and over again in the issues.
16
16
 
17
17
  # FriendlyId
18
18
 
19
- <em>For the most complete, user-friendly documentation, see the [FriendlyId Guide](http://norman.github.io/friendly_id/file.Guide.html).</em>
19
+ **For the most complete, user-friendly documentation, see the [FriendlyId Guide](http://norman.github.io/friendly_id/file.Guide.html).**
20
20
 
21
21
  FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins for
22
22
  Active Record. It lets you create pretty URLs and work with human-friendly
@@ -236,7 +236,7 @@ volunteers](https://github.com/norman/friendly_id/contributors).
236
236
 
237
237
  ## License
238
238
 
239
- Copyright (c) 2008-2014 Norman Clarke and contributors, released under the MIT
239
+ Copyright (c) 2008-2016 Norman Clarke and contributors, released under the MIT
240
240
  license.
241
241
 
242
242
  Permission is hereby granted, free of charge, to any person obtaining a copy of
data/Rakefile CHANGED
@@ -36,6 +36,16 @@ task :bench => :load_path do
36
36
  require File.expand_path("../bench", __FILE__)
37
37
  end
38
38
 
39
+ desc "Run benchmarks on finders"
40
+ task :bench_finders => :load_path do
41
+ require File.expand_path("../test/benchmarks/finders", __FILE__)
42
+ end
43
+
44
+ desc "Run benchmarks on ObjectUtils"
45
+ task :bench_object_utils => :load_path do
46
+ require File.expand_path("../test/benchmarks/object_utils", __FILE__)
47
+ end
48
+
39
49
  desc "Generate Guide.md"
40
50
  task :guide do
41
51
  load File.expand_path('../guide.rb', __FILE__)
data/bench.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require File.expand_path("../test/helper", __FILE__)
2
2
  require "ffaker"
3
3
 
4
- N = 1000
4
+ N = 10000
5
5
 
6
6
  def transaction
7
7
  ActiveRecord::Base.transaction { yield ; raise ActiveRecord::Rollback }
@@ -37,7 +37,7 @@ MANUALS = []
37
37
  RESTAURANTS = []
38
38
 
39
39
  100.times do
40
- name = Faker::Name.name
40
+ name = FFaker::Name.name
41
41
  BOOKS << (Book.create! :name => name).id
42
42
  JOURNALISTS << (Journalist.create! :name => name).friendly_id
43
43
  MANUALS << (Manual.create! :name => name).friendly_id
@@ -64,18 +64,18 @@ Benchmark.bmbm do |x|
64
64
  end
65
65
 
66
66
  x.report 'insert (without FriendlyId)' do
67
- N.times {transaction {Book.create :name => Faker::Name.name}}
67
+ N.times {transaction {Book.create :name => FFaker::Name.name}}
68
68
  end
69
69
 
70
70
  x.report 'insert (in-table-slug)' do
71
- N.times {transaction {Journalist.create :name => Faker::Name.name}}
71
+ N.times {transaction {Journalist.create :name => FFaker::Name.name}}
72
72
  end
73
73
 
74
74
  x.report 'insert (in-table-slug; using finders module)' do
75
- N.times {transaction {Restaurant.create :name => Faker::Name.name}}
75
+ N.times {transaction {Restaurant.create :name => FFaker::Name.name}}
76
76
  end
77
77
 
78
78
  x.report 'insert (external slug)' do
79
- N.times {transaction {Manual.create :name => Faker::Name.name}}
79
+ N.times {transaction {Manual.create :name => FFaker::Name.name}}
80
80
  end
81
81
  end
data/friendly_id.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.version = FriendlyId::VERSION
7
7
  s.authors = ["Norman Clarke", "Philip Arndt"]
8
8
  s.email = ["norman@njclarke.com", "p@arndt.io"]
9
- s.homepage = "http://github.com/norman/friendly_id"
9
+ s.homepage = "https://github.com/norman/friendly_id"
10
10
  s.summary = "A comprehensive slugging and pretty-URL plugin."
11
11
  s.rubyforge_project = "friendly_id"
12
12
  s.files = `git ls-files`.split("\n")
@@ -17,7 +17,7 @@ group :development, :test do
17
17
 
18
18
  platforms :ruby, :rbx do
19
19
  gem 'sqlite3'
20
- gem 'mysql2'
20
+ gem 'mysql2', '~> 0.3.10'
21
21
  gem 'pg'
22
22
  gem 'redcarpet'
23
23
  end
@@ -16,7 +16,7 @@ group :development, :test do
16
16
 
17
17
  platforms :ruby, :rbx do
18
18
  gem 'sqlite3'
19
- gem 'mysql2'
19
+ gem 'mysql2', '~> 0.3.13'
20
20
  gem 'pg'
21
21
  gem 'redcarpet'
22
22
  end
@@ -0,0 +1,28 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+
5
+ gem 'activerecord', '~> 5.0.0'
6
+ gem 'railties', '~> 5.0.0'
7
+ gem 'i18n', '~> 0.7.0'
8
+
9
+ # Database Configuration
10
+ group :development, :test do
11
+ platforms :jruby do
12
+ gem 'activerecord-jdbcmysql-adapter', '~> 1.3.14'
13
+ gem 'activerecord-jdbcpostgresql-adapter', '~> 1.3.14'
14
+ gem 'kramdown'
15
+ end
16
+
17
+ platforms :ruby, :rbx do
18
+ gem 'sqlite3'
19
+ gem 'mysql2'
20
+ gem 'pg'
21
+ gem 'redcarpet'
22
+ end
23
+
24
+ platforms :rbx do
25
+ gem 'rubysl', '~> 2.0'
26
+ gem 'rubinius-developer_tools'
27
+ end
28
+ end
data/lib/friendly_id.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ require 'active_record'
2
3
  require "friendly_id/base"
3
4
  require "friendly_id/object_utils"
4
5
  require "friendly_id/configuration"
@@ -51,19 +52,6 @@ module FriendlyId
51
52
  autoload :Finders, "friendly_id/finders"
52
53
  autoload :SequentiallySlugged, "friendly_id/sequentially_slugged"
53
54
 
54
- # Instances of these classes will never be considered a friendly id.
55
- # @see FriendlyId::ObjectUtils#friendly_id
56
- UNFRIENDLY_CLASSES = [
57
- ActiveRecord::Base,
58
- Array,
59
- FalseClass,
60
- Hash,
61
- NilClass,
62
- Numeric,
63
- Symbol,
64
- TrueClass
65
- ]
66
-
67
55
  # FriendlyId takes advantage of `extended` to do basic model setup, primarily
68
56
  # extending {FriendlyId::Base} to add {FriendlyId::Base#friendly_id
69
57
  # friendly_id} as a class method.
@@ -187,9 +187,22 @@ often better and easier to use {FriendlyId::Slugged slugs}.
187
187
  # allows an alternate configuration syntax, and conditional configuration
188
188
  # logic.
189
189
  #
190
+ # @option options [Symbol,Boolean] :dependent Available when using `:history`.
191
+ # Sets the value used for the slugged association's dependent option. Use
192
+ # `false` if you do not want to dependently destroy the associated slugged
193
+ # record. Defaults to `:destroy`.
194
+ #
195
+ # @option options [Symbol] :routes When set to anything other than :friendly,
196
+ # ensures that all routes generated by default do *not* use the slug. This
197
+ # allows `form_for` and `polymorphic_path` to continue to generate paths like
198
+ # `/team/1` instead of `/team/number-one`. You can still generate paths
199
+ # like the latter using: team_path(team.slug). When set to :friendly, or
200
+ # omitted, the default friendly_id behavior is maintained.
201
+ #
190
202
  # @yieldparam config The model class's {FriendlyId::Configuration friendly_id_config}.
191
203
  def friendly_id(base = nil, options = {}, &block)
192
204
  yield friendly_id_config if block_given?
205
+ friendly_id_config.dependent = options.delete :dependent
193
206
  friendly_id_config.use options.delete :use
194
207
  friendly_id_config.send :set, base ? options.merge(:base => base) : options
195
208
  include Model
@@ -244,11 +257,15 @@ often better and easier to use {FriendlyId::Slugged slugs}.
244
257
 
245
258
  # Either the friendly_id, or the numeric id cast to a string.
246
259
  def to_param
247
- if attribute_changed?(friendly_id_config.query_field)
248
- diff = changes[friendly_id_config.query_field]
249
- diff.first || diff.second
260
+ if friendly_id_config.routes == :friendly
261
+ if attribute_changed?(friendly_id_config.query_field)
262
+ diff = changes[friendly_id_config.query_field]
263
+ diff.first || diff.second
264
+ else
265
+ friendly_id.presence.to_param || super
266
+ end
250
267
  else
251
- friendly_id.presence.to_param || super
268
+ super
252
269
  end
253
270
  end
254
271
 
@@ -18,11 +18,18 @@ module FriendlyId
18
18
  # The module to use for finders
19
19
  attr_accessor :finder_methods
20
20
 
21
+ # The value used for the slugged association's dependent option
22
+ attr_accessor :dependent
23
+
24
+ # Route generation preferences
25
+ attr_accessor :routes
26
+
21
27
  def initialize(model_class, values = nil)
22
28
  @model_class = model_class
23
29
  @defaults = {}
24
30
  @modules = []
25
31
  @finder_methods = FriendlyId::FinderMethods
32
+ self.routes = :friendly
26
33
  set values
27
34
  end
28
35
 
@@ -20,7 +20,7 @@ module FriendlyId
20
20
  return super if args.count != 1 || id.unfriendly_id?
21
21
  first_by_friendly_id(id).tap {|result| return result unless result.nil?}
22
22
  return super if potential_primary_key?(id)
23
- raise ActiveRecord::RecordNotFound
23
+ raise ActiveRecord::RecordNotFound, "can't find record with friendly id: #{id.inspect}"
24
24
  end
25
25
 
26
26
  # Returns true if a record with the given id exists.
@@ -33,7 +33,7 @@ module FriendlyId
33
33
  # `find`.
34
34
  # @raise ActiveRecord::RecordNotFound
35
35
  def find_by_friendly_id(id)
36
- first_by_friendly_id(id) or raise ActiveRecord::RecordNotFound
36
+ first_by_friendly_id(id) or raise ActiveRecord::RecordNotFound, "can't find record with friendly id: #{id.inspect}"
37
37
  end
38
38
 
39
39
  def exists_by_friendly_id?(id)
@@ -54,8 +54,8 @@ module FriendlyId
54
54
  end
55
55
 
56
56
  def first_by_friendly_id(id)
57
- where(friendly_id_config.query_field => id).first
57
+ find_by(friendly_id_config.query_field => id)
58
58
  end
59
59
 
60
60
  end
61
- end
61
+ end
@@ -76,17 +76,14 @@ for models that use FriendlyId with something similar to the following:
76
76
  def self.setup(model_class)
77
77
  model_class.instance_eval do
78
78
  relation.class.send(:include, friendly_id_config.finder_methods)
79
- if ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR == 2
79
+ if (ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR == 2) || ActiveRecord::VERSION::MAJOR == 5
80
80
  model_class.send(:extend, friendly_id_config.finder_methods)
81
81
  end
82
82
  end
83
- end
84
-
85
- def self.included(model_class)
86
- model_class.extend(ClassMethods)
87
83
 
88
84
  # Support for friendly finds on associations for Rails 4.0.1 and above.
89
85
  if ::ActiveRecord.const_defined?('AssociationRelation')
86
+ model_class.extend(ClassMethods)
90
87
  association_relation_delegate_class = model_class.relation_delegate_class(::ActiveRecord::AssociationRelation)
91
88
  association_relation_delegate_class.send(:include, model_class.friendly_id_config.finder_methods)
92
89
  end
@@ -41,7 +41,7 @@ method.
41
41
  ...
42
42
 
43
43
  def find_post
44
- @post = Post.find params[:id]
44
+ @post = Post.friendly.find params[:id]
45
45
 
46
46
  # If an old id or a numeric id was used to find the record, then
47
47
  # the request path will not match the post_path, and we should do
@@ -54,16 +54,18 @@ method.
54
54
  =end
55
55
  module History
56
56
 
57
+ module Configuration
58
+ def dependent_value
59
+ dependent.nil? ? :destroy : dependent
60
+ end
61
+ end
62
+
57
63
  def self.setup(model_class)
58
64
  model_class.instance_eval do
59
65
  friendly_id_config.use :slugged
66
+ friendly_id_config.class.send :include, History::Configuration
60
67
  friendly_id_config.finder_methods = FriendlyId::History::FinderMethods
61
- if friendly_id_config.uses? :finders
62
- relation.class.send(:include, friendly_id_config.finder_methods)
63
- if ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR == 2
64
- model_class.send(:extend, friendly_id_config.finder_methods)
65
- end
66
- end
68
+ FriendlyId::Finders.setup(model_class) if friendly_id_config.uses? :finders
67
69
  end
68
70
  end
69
71
 
@@ -72,7 +74,7 @@ method.
72
74
  model_class.class_eval do
73
75
  has_many :slugs, -> {order("#{Slug.quoted_table_name}.id DESC")}, {
74
76
  :as => :sluggable,
75
- :dependent => :destroy,
77
+ :dependent => @friendly_id_config.dependent_value,
76
78
  :class_name => Slug.to_s
77
79
  }
78
80
 
@@ -84,7 +86,7 @@ method.
84
86
  include ::FriendlyId::FinderMethods
85
87
 
86
88
  def exists_by_friendly_id?(id)
87
- joins(:slugs).where(arel_table[friendly_id_config.query_field].eq(id)).exists? || joins(:slugs).where(slug_history_clause(id)).exists?
89
+ where(arel_table[friendly_id_config.query_field].eq(id)).exists? || joins(:slugs).where(slug_history_clause(id)).exists?
88
90
  end
89
91
 
90
92
  private
@@ -111,7 +113,7 @@ method.
111
113
  def scope_for_slug_generator
112
114
  relation = super
113
115
  return relation if new_record?
114
- relation = relation.merge(Slug.where('sluggable_id <> ?', id))
116
+ relation = relation.joins(:slugs).merge(Slug.where('sluggable_id <> ?', id))
115
117
  if friendly_id_config.uses?(:scoped)
116
118
  relation = relation.where(Slug.arel_table[:scope].eq(serialized_scope))
117
119
  end
@@ -8,8 +8,8 @@ class CreateFriendlyIdSlugs < ActiveRecord::Migration
8
8
  t.datetime :created_at
9
9
  end
10
10
  add_index :friendly_id_slugs, :sluggable_id
11
- add_index :friendly_id_slugs, [:slug, :sluggable_type]
12
- add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], :unique => true
11
+ add_index :friendly_id_slugs, [:slug, :sluggable_type], length: { slug: 140, sluggable_type: 50 }
12
+ add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], length: { slug: 70, sluggable_type: 50, scope: 70 }, unique: true
13
13
  add_index :friendly_id_slugs, :sluggable_type
14
14
  end
15
15
  end
@@ -1,4 +1,17 @@
1
1
  module FriendlyId
2
+ # Instances of these classes will never be considered a friendly id.
3
+ # @see FriendlyId::ObjectUtils#friendly_id
4
+ UNFRIENDLY_CLASSES = [
5
+ ActiveRecord::Base,
6
+ Array,
7
+ FalseClass,
8
+ Hash,
9
+ NilClass,
10
+ Numeric,
11
+ Symbol,
12
+ TrueClass
13
+ ]
14
+
2
15
  # Utility methods for determining whether any object is a friendly id.
3
16
  #
4
17
  # Monkey-patching Object is a somewhat extreme measure not to be taken lightly
@@ -27,13 +40,7 @@ module FriendlyId
27
40
  # "123".friendly_id? #=> nil
28
41
  # "abc123".friendly_id? #=> true
29
42
  def friendly_id?
30
- # Considered unfriendly if this is an instance of an unfriendly class or
31
- # one of its descendants.
32
- if FriendlyId::UNFRIENDLY_CLASSES.detect {|klass| self.class <= klass}
33
- false
34
- elsif respond_to?(:to_i) && to_i.to_s != to_s
35
- true
36
- end
43
+ true if respond_to?(:to_i) && to_i.to_s != to_s
37
44
  end
38
45
 
39
46
  # True if the id is definitely unfriendly, false if definitely friendly,
@@ -42,6 +49,21 @@ module FriendlyId
42
49
  val = friendly_id? ; !val unless val.nil?
43
50
  end
44
51
  end
52
+
53
+ module UnfriendlyUtils
54
+ def friendly_id?
55
+ false
56
+ end
57
+
58
+ def unfriendly_id?
59
+ true
60
+ end
61
+ end
45
62
  end
46
63
 
47
64
  Object.send :include, FriendlyId::ObjectUtils
65
+
66
+ # Considered unfriendly if object is an instance of an unfriendly class or
67
+ # one of its descendants.
68
+
69
+ FriendlyId::UNFRIENDLY_CLASSES.each { |klass| klass.send(:include, FriendlyId::UnfriendlyUtils) }
@@ -4,13 +4,11 @@ module FriendlyId
4
4
  model_class.friendly_id_config.use :slugged
5
5
  end
6
6
 
7
- def should_generate_new_friendly_id?
8
- send(friendly_id_config.base).present? && super
9
- end
10
-
11
7
  def resolve_friendly_id_conflict(candidate_slugs)
8
+ candidate = candidate_slugs.first
9
+ return if candidate.nil?
12
10
  SequentialSlugCalculator.new(scope_for_slug_generator,
13
- candidate_slugs.first,
11
+ candidate,
14
12
  friendly_id_config.slug_column,
15
13
  friendly_id_config.sequence_separator).next_slug
16
14
  end
@@ -37,15 +37,15 @@ friendly_id_globalize gem instead.
37
37
  Finds will take into consideration the current locale:
38
38
 
39
39
  I18n.locale = :es
40
- Post.find("la-guerra-de-las-galaxias")
40
+ Post.friendly.find("la-guerra-de-las-galaxias")
41
41
  I18n.locale = :en
42
- Post.find("star-wars")
42
+ Post.friendly.find("star-wars")
43
43
 
44
44
  To find a slug by an explicit locale, perform the find inside a block
45
45
  passed to I18n's `with_locale` method:
46
46
 
47
47
  I18n.with_locale(:es) do
48
- Post.find("la-guerra-de-las-galaxias")
48
+ Post.friendly.find("la-guerra-de-las-galaxias")
49
49
  end
50
50
 
51
51
  ### Creating Records
@@ -263,6 +263,7 @@ Github issue](https://github.com/norman/friendly_id/issues/185) for discussion.
263
263
  # ### Example
264
264
  #
265
265
  # class Person < ActiveRecord::Base
266
+ # extend FriendlyId
266
267
  # friendly_id :name_and_location
267
268
  #
268
269
  # def name_and_location
@@ -1,3 +1,3 @@
1
1
  module FriendlyId
2
- VERSION = "5.2.0.beta.1"
2
+ VERSION = "5.2.0"
3
3
  end
@@ -0,0 +1,88 @@
1
+ require File.expand_path("../../helper", __FILE__)
2
+ require "ffaker"
3
+
4
+ # This benchmark tests ActiveRecord and FriendlyId methods for performing a find
5
+ #
6
+ # ActiveRecord: where.first 8.970000 0.040000 9.010000 ( 9.029544)
7
+ # ActiveRecord: where.take 8.100000 0.030000 8.130000 ( 8.157024)
8
+ # ActiveRecord: find 2.720000 0.010000 2.730000 ( 2.733527)
9
+ # ActiveRecord: find_by(:id) 2.920000 0.000000 2.920000 ( 2.926318)
10
+ # ActiveRecord: find_by(:slug) 2.650000 0.020000 2.670000 ( 2.662677)
11
+ # FriendlyId: find (in-table slug w/ finders) 9.820000 0.030000 9.850000 ( 9.873358)
12
+ # FriendlyId: friendly.find (in-table slug) 12.890000 0.050000 12.940000 ( 12.951156)
13
+
14
+ N = 50000
15
+
16
+ def transaction
17
+ ActiveRecord::Base.transaction { yield ; raise ActiveRecord::Rollback }
18
+ end
19
+
20
+ class Array
21
+ def rand
22
+ self[Kernel.rand(length)]
23
+ end
24
+ end
25
+
26
+ Book = Class.new ActiveRecord::Base
27
+
28
+ class Journalist < ActiveRecord::Base
29
+ extend FriendlyId
30
+ friendly_id :name, :use => :slugged
31
+ end
32
+
33
+ class Manual < ActiveRecord::Base
34
+ extend FriendlyId
35
+ friendly_id :name, :use => :history
36
+ end
37
+
38
+ class Restaurant < ActiveRecord::Base
39
+ extend FriendlyId
40
+ friendly_id :name, :use => :finders
41
+ end
42
+
43
+
44
+ BOOKS = []
45
+ JOURNALISTS = []
46
+ MANUALS = []
47
+ RESTAURANTS = []
48
+
49
+ 100.times do
50
+ name = FFaker::Name.name
51
+ BOOKS << (Book.create! :name => name).id
52
+ JOURNALISTS << (Journalist.create! :name => name).friendly_id
53
+ MANUALS << (Manual.create! :name => name).friendly_id
54
+ RESTAURANTS << (Restaurant.create! :name => name).friendly_id
55
+ end
56
+
57
+ ActiveRecord::Base.connection.execute "UPDATE manuals SET slug = NULL"
58
+
59
+ Benchmark.bmbm do |x|
60
+ x.report 'ActiveRecord: where.first' do
61
+ N.times {Book.where(:id=>BOOKS.rand).first}
62
+ end
63
+
64
+ x.report 'ActiveRecord: where.take' do
65
+ N.times {Book.where(:id=>BOOKS.rand).take}
66
+ end
67
+
68
+ x.report 'ActiveRecord: find' do
69
+ N.times {Book.find BOOKS.rand}
70
+ end
71
+
72
+ x.report 'ActiveRecord: find_by(:id)' do
73
+ N.times {Book.find_by(:id=>BOOKS.rand)}
74
+ end
75
+
76
+ x.report 'ActiveRecord: find_by(:slug)' do
77
+ N.times {Restaurant.find_by(:slug=>RESTAURANTS.rand)}
78
+ end
79
+
80
+ x.report 'FriendlyId: find (in-table slug w/ finders)' do
81
+ N.times {Restaurant.find RESTAURANTS.rand}
82
+ end
83
+
84
+ x.report 'FriendlyId: friendly.find (in-table slug)' do
85
+ N.times {Restaurant.friendly.find RESTAURANTS.rand}
86
+ end
87
+
88
+ end
@@ -0,0 +1,56 @@
1
+ require File.expand_path("../../helper", __FILE__)
2
+
3
+ # This benchmark compares the timings of the friendly_id? and unfriendly_id? on various objects
4
+ #
5
+ # integer friendly_id? 6.370000 0.000000 6.370000 ( 6.380925)
6
+ # integer unfriendly_id? 6.640000 0.010000 6.650000 ( 6.646057)
7
+ # AR::Base friendly_id? 2.340000 0.000000 2.340000 ( 2.340743)
8
+ # AR::Base unfriendly_id? 2.560000 0.000000 2.560000 ( 2.560039)
9
+ # hash friendly_id? 5.090000 0.010000 5.100000 ( 5.097662)
10
+ # hash unfriendly_id? 5.430000 0.000000 5.430000 ( 5.437160)
11
+ # nil friendly_id? 5.610000 0.010000 5.620000 ( 5.611487)
12
+ # nil unfriendly_id? 5.870000 0.000000 5.870000 ( 5.880484)
13
+ # numeric string friendly_id? 9.270000 0.030000 9.300000 ( 9.308452)
14
+ # numeric string unfriendly_id? 9.190000 0.040000 9.230000 ( 9.252890)
15
+ # test_string friendly_id? 8.380000 0.010000 8.390000 ( 8.411762)
16
+ # test_string unfriendly_id? 8.450000 0.010000 8.460000 ( 8.463662)
17
+
18
+ # From the ObjectUtils docs...
19
+ # 123.friendly_id? #=> false
20
+ # :id.friendly_id? #=> false
21
+ # {:name => 'joe'}.friendly_id? #=> false
22
+ # ['name = ?', 'joe'].friendly_id? #=> false
23
+ # nil.friendly_id? #=> false
24
+ # "123".friendly_id? #=> nil
25
+ # "abc123".friendly_id? #=> true
26
+
27
+ Book = Class.new ActiveRecord::Base
28
+
29
+ test_integer = 123
30
+ test_active_record_object = Book.new
31
+ test_hash = {:name=>'joe'}
32
+ test_nil = nil
33
+ test_numeric_string = "123"
34
+ test_string = "abc123"
35
+
36
+ N = 5_000_000
37
+
38
+ Benchmark.bmbm do |x|
39
+ x.report('integer friendly_id?') { N.times {test_integer.friendly_id?} }
40
+ x.report('integer unfriendly_id?') { N.times {test_integer.unfriendly_id?} }
41
+
42
+ x.report('AR::Base friendly_id?') { N.times {test_active_record_object.friendly_id?} }
43
+ x.report('AR::Base unfriendly_id?') { N.times {test_active_record_object.unfriendly_id?} }
44
+
45
+ x.report('hash friendly_id?') { N.times {test_hash.friendly_id?} }
46
+ x.report('hash unfriendly_id?') { N.times {test_hash.unfriendly_id?} }
47
+
48
+ x.report('nil friendly_id?') { N.times {test_nil.friendly_id?} }
49
+ x.report('nil unfriendly_id?') { N.times {test_nil.unfriendly_id?} }
50
+
51
+ x.report('numeric string friendly_id?') { N.times {test_numeric_string.friendly_id?} }
52
+ x.report('numeric string unfriendly_id?') { N.times {test_numeric_string.unfriendly_id?} }
53
+
54
+ x.report('test_string friendly_id?') { N.times {test_string.friendly_id?} }
55
+ x.report('test_string unfriendly_id?') { N.times {test_string.unfriendly_id?} }
56
+ end
data/test/history_test.rb CHANGED
@@ -1,15 +1,15 @@
1
1
  require "helper"
2
2
 
3
- class Manual < ActiveRecord::Base
4
- extend FriendlyId
5
- friendly_id :name, :use => [:slugged, :history]
6
- end
7
-
8
3
  class HistoryTest < TestCaseClass
9
4
 
10
5
  include FriendlyId::Test
11
6
  include FriendlyId::Test::Shared::Core
12
7
 
8
+ class Manual < ActiveRecord::Base
9
+ extend FriendlyId
10
+ friendly_id :name, :use => [:slugged, :history]
11
+ end
12
+
13
13
  def model_class
14
14
  Manual
15
15
  end
@@ -172,6 +172,45 @@ class HistoryTestWithAutomaticSlugRegeneration < HistoryTest
172
172
  end
173
173
  end
174
174
 
175
+ class DependentDestroyTest < HistoryTest
176
+
177
+ include FriendlyId::Test
178
+
179
+ class FalseManual < ActiveRecord::Base
180
+ self.table_name = 'manuals'
181
+
182
+ extend FriendlyId
183
+ friendly_id :name, :use => :history, :dependent => false
184
+ end
185
+
186
+ class DefaultManual < ActiveRecord::Base
187
+ self.table_name = 'manuals'
188
+
189
+ extend FriendlyId
190
+ friendly_id :name, :use => :history
191
+ end
192
+
193
+ test 'should allow disabling of dependent destroy' do
194
+ transaction do
195
+ assert FriendlyId::Slug.find_by_slug('foo').nil?
196
+ l = FalseManual.create! :name => 'foo'
197
+ assert FriendlyId::Slug.find_by_slug('foo').present?
198
+ l.destroy
199
+ assert FriendlyId::Slug.find_by_slug('foo').present?
200
+ end
201
+ end
202
+
203
+ test 'should dependently destroy by default' do
204
+ transaction do
205
+ assert FriendlyId::Slug.find_by_slug('baz').nil?
206
+ l = DefaultManual.create! :name => 'baz'
207
+ assert FriendlyId::Slug.find_by_slug('baz').present?
208
+ l.destroy
209
+ assert FriendlyId::Slug.find_by_slug('baz').nil?
210
+ end
211
+ end
212
+ end
213
+
175
214
  class HistoryTestWithSti < HistoryTest
176
215
  class Journalist < ActiveRecord::Base
177
216
  extend FriendlyId
@@ -217,6 +256,36 @@ class HistoryTestWithFriendlyFinders < HistoryTest
217
256
  end
218
257
  end
219
258
 
259
+ class HistoryTestWithFindersBeforeHistory < HistoryTest
260
+ class Novelist < ActiveRecord::Base
261
+ has_many :novels
262
+ end
263
+
264
+ class Novel < ActiveRecord::Base
265
+ extend FriendlyId
266
+
267
+ belongs_to :novelist
268
+
269
+ friendly_id :name, :use => [:finders, :history]
270
+
271
+ def should_generate_new_friendly_id?
272
+ slug.blank? || name_changed?
273
+ end
274
+ end
275
+
276
+ test "should be findable by old slug through has_many association" do
277
+ transaction do
278
+ novelist = Novelist.create!(:name => "Stephen King")
279
+ novel = novelist.novels.create(:name => "Rita Hayworth and Shawshank Redemption")
280
+ slug = novel.slug
281
+ novel.name = "Shawshank Redemption"
282
+ novel.save!
283
+ assert_equal novel, Novel.find(slug)
284
+ assert_equal novel, novelist.novels.find(slug)
285
+ end
286
+ end
287
+ end
288
+
220
289
  class City < ActiveRecord::Base
221
290
  has_many :restaurants
222
291
  end
@@ -89,6 +89,22 @@ class SequentiallySluggedTest < TestCaseClass
89
89
  end
90
90
  end
91
91
 
92
+ test "should not generate a slug when canidates set is empty" do
93
+ model_class = Class.new(ActiveRecord::Base) do
94
+ self.table_name = "cities"
95
+ extend FriendlyId
96
+ friendly_id :slug_candidates, :use => [ :sequentially_slugged ]
97
+
98
+ def slug_candidates
99
+ [name, [name, code]]
100
+ end
101
+ end
102
+ transaction do
103
+ record = model_class.create!(:name => nil, :code => nil)
104
+ assert_nil record.slug
105
+ end
106
+ end
107
+
92
108
  test "should not generate a slug when the sluggable attribute is blank" do
93
109
  record = model_class.create!(:name => '')
94
110
  assert_nil record.slug
data/test/slugged_test.rb CHANGED
@@ -373,3 +373,35 @@ class FailedValidationAfterUpdateRegressionTest < TestCaseClass
373
373
  end
374
374
 
375
375
  end
376
+
377
+ class ConfigurableRoutesTest < TestCaseClass
378
+ include FriendlyId::Test
379
+
380
+ class Article < ActiveRecord::Base
381
+ extend FriendlyId
382
+
383
+ friendly_id :name, :use => :slugged, :routes => :friendly
384
+ end
385
+
386
+ class Novel < ActiveRecord::Base
387
+ extend FriendlyId
388
+
389
+ friendly_id :name, :use => :slugged, :routes => :default
390
+ end
391
+
392
+ test "to_param should return a friendly id when the routes option is set to :friendly" do
393
+ transaction do
394
+ article = Article.create! :name => "Titanic Hits; Iceberg Sinks"
395
+
396
+ assert_equal "titanic-hits-iceberg-sinks", article.to_param
397
+ end
398
+ end
399
+
400
+ test "to_param should return the id when the routes option is set to anything but friendly" do
401
+ transaction do
402
+ novel = Novel.create! :name => "Don Quixote"
403
+
404
+ assert_equal novel.id.to_s, novel.to_param
405
+ end
406
+ end
407
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: friendly_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0.beta.1
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Norman Clarke
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-06-01 00:00:00.000000000 Z
12
+ date: 2016-12-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -163,6 +163,7 @@ files:
163
163
  - gemfiles/Gemfile.rails-4.0.rb
164
164
  - gemfiles/Gemfile.rails-4.1.rb
165
165
  - gemfiles/Gemfile.rails-4.2.rb
166
+ - gemfiles/Gemfile.rails-5.0.rb
166
167
  - guide.rb
167
168
  - lib/friendly_id.rb
168
169
  - lib/friendly_id/.gitattributes
@@ -185,6 +186,8 @@ files:
185
186
  - lib/friendly_id/version.rb
186
187
  - lib/generators/friendly_id_generator.rb
187
188
  - test/base_test.rb
189
+ - test/benchmarks/finders.rb
190
+ - test/benchmarks/object_utils.rb
188
191
  - test/candidates_test.rb
189
192
  - test/configuration_test.rb
190
193
  - test/core_test.rb
@@ -202,7 +205,7 @@ files:
202
205
  - test/simple_i18n_test.rb
203
206
  - test/slugged_test.rb
204
207
  - test/sti_test.rb
205
- homepage: http://github.com/norman/friendly_id
208
+ homepage: https://github.com/norman/friendly_id
206
209
  licenses:
207
210
  - MIT
208
211
  metadata: {}
@@ -217,14 +220,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
217
220
  version: 1.9.3
218
221
  required_rubygems_version: !ruby/object:Gem::Requirement
219
222
  requirements:
220
- - - ">"
223
+ - - ">="
221
224
  - !ruby/object:Gem::Version
222
- version: 1.3.1
225
+ version: '0'
223
226
  requirements: []
224
227
  rubyforge_project: friendly_id
225
- rubygems_version: 2.4.5
228
+ rubygems_version: 2.5.2
226
229
  signing_key:
227
230
  specification_version: 4
228
231
  summary: A comprehensive slugging and pretty-URL plugin.
229
232
  test_files: []
230
- has_rdoc: