friendly_id 5.0.0.beta3 → 5.0.0.beta4

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: b7dc57b3098c5b155bf109e9cefccf404bce14e5
4
- data.tar.gz: 2958d34628cca3ae7c93fc828d10ec11da863a47
3
+ metadata.gz: 04766b0ed96f1b271571b983cf3b73cf9385406c
4
+ data.tar.gz: 5881c90dc07cf35780402d04211cc93ebd597d01
5
5
  SHA512:
6
- metadata.gz: aa871391245ae44af48c1e6676681f169ebf25a4d922a871e1d68344cab69705c5f63464caf1bfa0f4bb37f80ff6be45569005ea5b26fb1629477046285834b2
7
- data.tar.gz: 2c4658fea02b39fea957a833ce3e533abaa9273c29d77af9a7f720099130fe3c63e6c4f4394217af2166d1477a1ff83251a3cab5c670fb6861f748c5718b6c11
6
+ metadata.gz: 06b4a78391d3a6f9ca7a42e4769087e4dbf70a559e29313147b48b655dbc59ffddfbaf3f91e78854d64c8b1cedf1bf2e088280c9747fcb9fc45318ec7243d925
7
+ data.tar.gz: 2e66f50e25d14cf807e2f2719c49e13e2936656ac50a6842f1225357089e0561b2ec39effad76571558999d04d905715f365649cd1119b7a2a8765dd81084c79
data/Changelog.md CHANGED
@@ -3,6 +3,12 @@
3
3
  We would like to think our many {file:Contributors contributors} for
4
4
  suggestions, ideas and improvements to FriendlyId.
5
5
 
6
+ ## 5.0.0.beta4 (2013-08-21)
7
+
8
+ * Add an initializer to the generator; move the default reserved words there.
9
+ * Allow assignment from {FriendlyId::Configuration#base}.
10
+ * Fix bug whereby records could not reuse their own slugs.
11
+
6
12
  ## 5.0.0.beta3 (2013-08-20)
7
13
 
8
14
  * Update gemspec to ensure FriendlyId 5.0 is only used with AR 4.0.x.
data/README.md CHANGED
@@ -3,12 +3,14 @@
3
3
  **VERSION NOTE**
4
4
 
5
5
  **Rails 4**:
6
- Master branch of this repository contains FriendlyId 5 which is compatible with Rails 4.
7
- This version is in beta and will be released soon.
6
+
7
+ The master branch of this repository contains FriendlyId 5, which is compatible
8
+ with Rails 4. This version is in beta and will be released soon.
8
9
 
9
10
  **Rails 3**:
10
- If you wish to use this gem with Rails 3.1 or 3.2 you need to use FriendlyId version 4, which is the current stable release.
11
- Please see [4.0-stable
11
+
12
+ If you wish to use this gem with Rails 3.1 or 3.2 you must use FriendlyId 4,
13
+ which is the current stable release. Please see the [4.0-stable
12
14
  branch](https://github.com/norman/friendly_id/tree/4.0-stable).
13
15
 
14
16
  # FriendlyId
@@ -16,10 +18,10 @@ branch](https://github.com/norman/friendly_id/tree/4.0-stable).
16
18
  <em>For the most complete, user-friendly documentation, see the [FriendlyId Guide](http://rubydoc.info/github/norman/friendly_id/master/file/Guide.md).</em>
17
19
 
18
20
  FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins for
19
- Ruby on Rails. It allows you to create pretty URLs and work with human-friendly
20
- strings as if they were numeric ids for Active Record models.
21
+ Active Record. It lets you create pretty URLs and work with human-friendly
22
+ strings as if they were numeric ids.
21
23
 
22
- Using FriendlyId, it's easy to make your application use URLs like:
24
+ With FriendlyId, it's easy to make your application use URLs like:
23
25
 
24
26
  http://example.com/states/washington
25
27
 
@@ -33,49 +35,41 @@ instead of:
33
35
  FriendlyId offers many advanced features, including: slug history and
34
36
  versioning, i18n, scoped slugs, reserved words, and custom slug generators.
35
37
 
36
- Note: FriendlyId 5.0 is compatible with Active Record **4.0** and higher only.
37
- For Rails 3.x, please use FriendlyId 4.x.
38
-
39
-
40
- ## Version 5.x
38
+ ### What Changed in Version 5.0
41
39
 
42
40
  As of version 5.0, FriendlyId uses semantic versioning. Therefore, as you might
43
- infer from the version number, FriendlyId 5.0 introduces changes incompatible
44
- with 4.x.
41
+ infer from the version number, 5.0 introduces changes incompatible with 4.0.
45
42
 
46
- Here's a summary of the most important changes:
43
+ The most important changes are:
47
44
 
48
- * FriendlyId no longer overrides `find` by default. If you want to do friendly finds,
49
- you must do `Model.friendly.find` rather than `Model.find`. You can however easily
45
+ * Finders are no longer overridden by default. If you want to do friendly finds,
46
+ you must do `Model.friendly.find` rather than `Model.find`. You can however
50
47
  restore FriendlyId 4-style finders by using the `:finders` addon:
51
48
 
52
- ```ruby
53
- friendly_id :foo, use: :slugged # you must do MyClass.friendly.find('bar')
54
- # or...
55
- friendly_id :foo, use: [:slugged, :finders] # you can now do MyClass.find('bar')
56
- ```
49
+ friendly_id :foo, use: :slugged # you must do MyClass.friendly.find('bar')
50
+ # or...
51
+ friendly_id :foo, use: [:slugged, :finders] # you can now do MyClass.find('bar')
57
52
 
58
- * Version 5.0 offers a new "candidates" functionality which makes it easy to
59
- set up a list of alternate slugs that can be used to uniquely distinguish
60
- records, rather than appending a sequence. For example:
61
53
 
62
- ```ruby
63
- class Restaurant < ActiveRecord::Base
64
- extend FriendlyId
65
- friendly_id :slug_candidates, use: :slugged
66
-
67
- # Try building a slug based on the following fields in
68
- # increasing order of specificity.
69
- def slug_candidates
70
- [
71
- :name,
72
- [:name, :city],
73
- [:name, :street, :city],
74
- [:name, :street_number, :street, :city]
75
- ]
76
- end
77
- end
78
- ```
54
+ * A new "candidates" functionality which makes it easy to set up a list of
55
+ alternate slugs that can be used to uniquely distinguish records, rather than
56
+ appending a sequence. For example:
57
+
58
+ class Restaurant < ActiveRecord::Base
59
+ extend FriendlyId
60
+ friendly_id :slug_candidates, use: :slugged
61
+
62
+ # Try building a slug based on the following fields in
63
+ # increasing order of specificity.
64
+ def slug_candidates
65
+ [
66
+ :name,
67
+ [:name, :city],
68
+ [:name, :street, :city],
69
+ [:name, :street_number, :street, :city]
70
+ ]
71
+ end
72
+ end
79
73
 
80
74
  * Now that candidates have been added, FriendlyId no longer uses a numeric
81
75
  sequence to differentiate conflicting slug, but rather a UUID (e.g. something
@@ -83,26 +77,56 @@ end
83
77
  codebase simpler and more reliable when running concurrently, at the expense
84
78
  of uglier ids being generated when there are conflicts.
85
79
 
86
- * The default sequence separator is now `-` rather than `--`.
80
+ * The default sequence separator has been changed from two dashes to one dash.
87
81
 
88
82
  * Slugs are no longer regenerated when a record is saved. If you want to regenerate
89
83
  a slug, you must explicitly set the slug column to nil:
90
84
 
91
- ```ruby
92
- restaurant.friendly_id # joes-diner
93
- restaurant.name = "The Plaza Diner"
94
- restaurant.save!
95
- restaurant.friendly_id # joes-diner
96
- restaurant.slug = nil
97
- restaurant.save!
98
- restaurant.friendly_id # the-plaza-diner
99
- ```
85
+ restaurant.friendly_id # joes-diner
86
+ restaurant.name = "The Plaza Diner"
87
+ restaurant.save!
88
+ restaurant.friendly_id # joes-diner
89
+ restaurant.slug = nil
90
+ restaurant.save!
91
+ restaurant.friendly_id # the-plaza-diner
92
+
93
+ You can restore some of the old behavior by overriding the
94
+ `should_generate_new_friendly_id` method.
95
+
96
+ * The `friendly_id` Rails generator now generates an initializer showing you
97
+ how to do some commmon global configuration.
98
+
99
+ * The `:reserved` module no longer includes any default reserved words.
100
+ Previously it blocked "edit" and "new" everywhere. The default word list has
101
+ been moved to `config/initializers/friendly_id.rb` and now includes many more
102
+ words.
103
+
104
+ * The `:history` and `:scoped` addons can now be used together.
105
+
106
+ * Since it now requires Rails 4, FriendlyId also now requires Ruby 1.9.3 or
107
+ higher.
108
+
109
+ #### Upgrading from FriendlyId 4.0
110
+
111
+ Run `rails generate friendly_id --skip-migration` and edit the initializer
112
+ generated in `config/initializers/friendly_id.rb`. This file contains notes
113
+ describing how to restore (or not) some of the defaults from FriendlyId 4.0.
114
+
115
+ If you want to use the `:history` and `:scoped` addons together, you must add a
116
+ `:scope` column to your friendly_id slugs table and replace the unique index on
117
+ `:slug` and `:sluggable_type` with a unique index on those two columns, plus
118
+ the new `:scope` column.
119
+
120
+ A migration like this should be sufficient:
100
121
 
101
- * Like Rails 4, FriendlyId now requires Ruby 1.9.3 or higher.
122
+ add_column :friendly_id_slugs, :scope, :string
123
+ remove_index :friendly_id_slugs, [:slug, :sluggable_type]
124
+ add_index :friendly_id_slugs, [:slug, :sluggable_type]
125
+ add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], unique: true
102
126
 
103
127
  ## Docs
104
128
 
105
- The current docs can always be found
129
+ The most current docs from the master branch can always be found
106
130
  [here](http://rubydoc.info/github/norman/friendly_id/master/frames).
107
131
 
108
132
  The best place to start is with the
@@ -110,7 +134,7 @@ The best place to start is with the
110
134
  which compiles the top-level RDocs into one outlined document.
111
135
 
112
136
  You might also want to watch Ryan Bates's [Railscast on FriendlyId](http://railscasts.com/episodes/314-pretty-urls-with-friendlyid),
113
- which is now somewhat outdated but still mostly relevant.
137
+ which is now somewhat outdated but still relevant.
114
138
 
115
139
  ## Rails Quickstart
116
140
 
@@ -120,7 +144,7 @@ cd my_app
120
144
  ```
121
145
  ```ruby
122
146
  # Gemfile
123
- gem 'friendly_id', '5.0.0.beta1' # Note: You MUST use 5.0.0 or greater for Rails 4.0+
147
+ gem 'friendly_id', '5.0.0.beta4' # Note: You MUST use 5.0.0 or greater for Rails 4.0+
124
148
  ```
125
149
  ```shell
126
150
  rails generate friendly_id
data/lib/friendly_id.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  # encoding: utf-8
2
- require "thread"
3
2
  require "friendly_id/base"
4
3
  require "friendly_id/object_utils"
5
4
  require "friendly_id/configuration"
@@ -43,8 +42,6 @@ with numeric ids:
43
42
  =end
44
43
  module FriendlyId
45
44
 
46
- @mutex = Mutex.new
47
-
48
45
  autoload :History, "friendly_id/history"
49
46
  autoload :Slug, "friendly_id/slug"
50
47
  autoload :SimpleI18n, "friendly_id/simple_i18n"
@@ -95,18 +92,16 @@ module FriendlyId
95
92
 
96
93
  # Set global defaults for all models using FriendlyId.
97
94
  #
98
- # The default defaults are to use the +:reserved+ module and nothing else.
95
+ # The default defaults are to use the `:reserved` module and nothing else.
99
96
  #
100
97
  # @example
101
98
  # FriendlyId.defaults do |config|
102
- # config.base = :name
99
+ # config.base :name
103
100
  # config.use :slugged
104
101
  # end
105
102
  def self.defaults(&block)
106
- @mutex.synchronize do
107
- @defaults = block if block_given?
108
- @defaults ||= lambda {|config| config.use :reserved}
109
- end
103
+ @defaults = block if block_given?
104
+ @defaults ||= ->(config) {config.use :reserved}
110
105
  end
111
106
 
112
107
  # Set the ActiveRecord table name prefix to friendly_id_
@@ -55,10 +55,10 @@ often better and easier to use {FriendlyId::Slugged slugs}.
55
55
 
56
56
  # Configure FriendlyId's behavior in a model.
57
57
  #
58
- # class Post < ActiveRecord::Base
59
- # extend FriendlyId
60
- # friendly_id :title, :use => :slugged
61
- # end
58
+ # class Post < ActiveRecord::Base
59
+ # extend FriendlyId
60
+ # friendly_id :title, :use => :slugged
61
+ # end
62
62
  #
63
63
  # When given the optional block, this method will yield the class's instance
64
64
  # of {FriendlyId::Configuration} to the block before evaluating other
@@ -67,36 +67,36 @@ often better and easier to use {FriendlyId::Slugged slugs}.
67
67
  # multiple models, while being able to override the values it sets. Here is
68
68
  # a contrived example:
69
69
  #
70
- # $friendly_id_config_proc = Proc.new do |config|
71
- # config.base = :name
72
- # config.use :slugged
73
- # end
70
+ # $friendly_id_config_proc = Proc.new do |config|
71
+ # config.base = :name
72
+ # config.use :slugged
73
+ # end
74
74
  #
75
- # class Foo < ActiveRecord::Base
76
- # extend FriendlyId
77
- # friendly_id &$friendly_id_config_proc
78
- # end
75
+ # class Foo < ActiveRecord::Base
76
+ # extend FriendlyId
77
+ # friendly_id &$friendly_id_config_proc
78
+ # end
79
79
  #
80
- # class Bar < ActiveRecord::Base
81
- # extend FriendlyId
82
- # friendly_id :title, &$friendly_id_config_proc
83
- # end
80
+ # class Bar < ActiveRecord::Base
81
+ # extend FriendlyId
82
+ # friendly_id :title, &$friendly_id_config_proc
83
+ # end
84
84
  #
85
85
  # However, it's usually better to use {FriendlyId.defaults} for this:
86
86
  #
87
- # FriendlyId.defaults do |config|
88
- # config.base = :name
89
- # config.use :slugged
90
- # end
87
+ # FriendlyId.defaults do |config|
88
+ # config.base = :name
89
+ # config.use :slugged
90
+ # end
91
91
  #
92
- # class Foo < ActiveRecord::Base
93
- # extend FriendlyId
94
- # end
92
+ # class Foo < ActiveRecord::Base
93
+ # extend FriendlyId
94
+ # end
95
95
  #
96
- # class Bar < ActiveRecord::Base
97
- # extend FriendlyId
98
- # friendly_id :title
99
- # end
96
+ # class Bar < ActiveRecord::Base
97
+ # extend FriendlyId
98
+ # friendly_id :title
99
+ # end
100
100
  #
101
101
  # In general you should use the block syntax either because of your personal
102
102
  # aesthetic preference, or because you need to share some functionality
@@ -114,21 +114,21 @@ often better and easier to use {FriendlyId::Slugged slugs}.
114
114
  # modules into your class, and these modules in turn may add required
115
115
  # configuration options to the `@friendly_id_configuraton`'s class:
116
116
  #
117
- # class Person < ActiveRecord::Base
118
- # friendly_id do |config|
119
- # # This will work
120
- # config.use :slugged
121
- # config.sequence_separator = ":"
117
+ # class Person < ActiveRecord::Base
118
+ # friendly_id do |config|
119
+ # # This will work
120
+ # config.use :slugged
121
+ # config.sequence_separator = ":"
122
+ # end
122
123
  # end
123
- # end
124
124
  #
125
- # class Person < ActiveRecord::Base
126
- # friendly_id do |config|
127
- # # This will fail
128
- # config.sequence_separator = ":"
129
- # config.use :slugged
125
+ # class Person < ActiveRecord::Base
126
+ # friendly_id do |config|
127
+ # # This will fail
128
+ # config.sequence_separator = ":"
129
+ # config.use :slugged
130
+ # end
130
131
  # end
131
- # end
132
132
  #
133
133
  # ### Including Your Own Modules
134
134
  #
@@ -136,21 +136,21 @@ often better and easier to use {FriendlyId::Slugged slugs}.
136
136
  # can be a convenient place to set up behavior common to all classes using
137
137
  # FriendlyId. You can include any module, or more conveniently, define one
138
138
  # on-the-fly. For example, let's say you want to make
139
- # Babosa[http://github.com/norman/babosa] the default slugging library in
139
+ # [Babosa](http://github.com/norman/babosa) the default slugging library in
140
140
  # place of Active Support, and transliterate all slugs from Russian Cyrillic
141
141
  # to ASCII:
142
142
  #
143
- # require "babosa"
143
+ # require "babosa"
144
144
  #
145
- # FriendlyId.defaults do |config|
146
- # config.base = :name
147
- # config.use :slugged
148
- # config.use Module.new {
149
- # def normalize_friendly_id(text)
150
- # text.to_slug.normalize(:transliterations => [:russian, :latin])
151
- # end
152
- # }
153
- # end
145
+ # FriendlyId.defaults do |config|
146
+ # config.base = :name
147
+ # config.use :slugged
148
+ # config.use Module.new {
149
+ # def normalize_friendly_id(text)
150
+ # text.to_slug.normalize! :transliterations => [:russian, :latin]
151
+ # end
152
+ # }
153
+ # end
154
154
  #
155
155
  #
156
156
  # @option options [Symbol,Module] :use The addon or name of an addon to use.
@@ -1,31 +1,9 @@
1
1
  module FriendlyId
2
- # The configuration paramters passed to +friendly_id+ will be stored in
2
+ # The configuration paramters passed to {Base#friendly_id} will be stored in
3
3
  # this object.
4
4
  class Configuration
5
5
 
6
- # The base column or method used by FriendlyId as the basis of a friendly id
7
- # or slug.
8
- #
9
- # For models that don't use FriendlyId::Slugged, the base is the column that
10
- # is used as the FriendlyId directly. For models using FriendlyId::Slugged,
11
- # the base is a column or method whose value is used as the basis of the
12
- # slug.
13
- #
14
- # For example, if you have a model representing blog posts and that uses
15
- # slugs, you likely will want to use the "title" attribute as the base, and
16
- # FriendlyId will take care of transforming the human-readable title into
17
- # something suitable for use in a URL.
18
- #
19
- # A symbol referencing a column or method in the model. This
20
- # value is usually set by passing it as the first argument to
21
- # {FriendlyId::Base#friendly_id friendly_id}:
22
- #
23
- # @example
24
- # class Book < ActiveRecord::Base
25
- # extend FriendlyId
26
- # friendly_id :name
27
- # end
28
- attr_accessor :base
6
+ attr_writer :base
29
7
 
30
8
  # The default configuration options.
31
9
  attr_reader :defaults
@@ -44,10 +22,10 @@ module FriendlyId
44
22
  set values
45
23
  end
46
24
 
47
- # Lets you specify the modules to use with FriendlyId.
25
+ # Lets you specify the addon modules to use with FriendlyId.
48
26
  #
49
27
  # This method is invoked by {FriendlyId::Base#friendly_id friendly_id} when
50
- # passing the +:use+ option, or when using {FriendlyId::Base#friendly_id
28
+ # passing the `:use` option, or when using {FriendlyId::Base#friendly_id
51
29
  # friendly_id} with a block.
52
30
  #
53
31
  # @example
@@ -55,10 +33,11 @@ module FriendlyId
55
33
  # extend FriendlyId
56
34
  # friendly_id :name, :use => :slugged
57
35
  # end
36
+ #
58
37
  # @param [#to_s,Module] modules Arguments should be Modules, or symbols or
59
- # strings that correspond with the name of a module inside the FriendlyId
60
- # namespace. By default FriendlyId provides +:slugged+, +:history+,
61
- # +:simple_i18n+, and +:scoped+.
38
+ # strings that correspond with the name of an addon to use with FriendlyId.
39
+ # By default FriendlyId provides `:slugged`, `:history`, `:simple_i18n`,
40
+ # and `:scoped`.
62
41
  def use(*modules)
63
42
  modules.to_a.flatten.compact.map do |object|
64
43
  mod = get_module(object)
@@ -81,6 +60,33 @@ module FriendlyId
81
60
  base.to_s
82
61
  end
83
62
 
63
+ # The base column or method used by FriendlyId as the basis of a friendly id
64
+ # or slug.
65
+ #
66
+ # For models that don't use {FriendlyId::Slugged}, this is the column that
67
+ # is used to store the friendly id. For models using {FriendlyId::Slugged},
68
+ # the base is a column or method whose value is used as the basis of the
69
+ # slug.
70
+ #
71
+ # For example, if you have a model representing blog posts and that uses
72
+ # slugs, you likely will want to use the "title" attribute as the base, and
73
+ # FriendlyId will take care of transforming the human-readable title into
74
+ # something suitable for use in a URL.
75
+ #
76
+ # If you pass an argument, it will be used as the base. Otherwise the current
77
+ # value is returned.
78
+ #
79
+ # @param value A symbol referencing a column or method in the model. This
80
+ # value is usually set by passing it as the first argument to
81
+ # {FriendlyId::Base#friendly_id friendly_id}.
82
+ def base(*value)
83
+ if value.empty?
84
+ @base
85
+ else
86
+ self.base = value.first
87
+ end
88
+ end
89
+
84
90
  private
85
91
 
86
92
  def get_module(object)
@@ -0,0 +1,84 @@
1
+ # FriendlyId Global Configuration
2
+ #
3
+ # Use this to set up shared configuration options for your entire application.
4
+ # Any of the configuration options shown here can also be applied to single
5
+ # models by passing arguments to the `friendly_id` class method or defining
6
+ # methods in your model.
7
+ #
8
+ # To learn more, check out the guide:
9
+ #
10
+ # http://rubydoc.info/github/norman/friendly_id/master/file/Guide.md
11
+
12
+ FriendlyId.defaults do |config|
13
+ # ## Reserved Words
14
+ #
15
+ # Some words could conflict with Rails's routes when used as slugs, or are
16
+ # undesirable to allow as slugs. Edit this list as needed for your app.
17
+ config.use :reserved
18
+
19
+ config.reserved_words = %w(new edit index session login logout users admin
20
+ stylesheets assets javascripts images)
21
+
22
+ # ## Friendly Finders
23
+ #
24
+ # Uncomment this to use friendly finders in all models. By default, if
25
+ # you wish to find a record by its friendly id, you must do:
26
+ #
27
+ # MyModel.friendly.find('foo')
28
+ #
29
+ # If you uncomment this, you can do:
30
+ #
31
+ # MyModel.find('foo')
32
+ #
33
+ # This is significantly more convenient but may not be appropriate for
34
+ # all applications, so you must explicity opt-in to this behavior. You can
35
+ # always also configure it on a per-model basis if you prefer.
36
+ #
37
+ # config.use :finders
38
+ #
39
+ # ## Slugs
40
+ #
41
+ # Most applications will use the :slugged module everywhere. If you wish
42
+ # to do so, uncomment the following line.
43
+ #
44
+ # config.use :slugged
45
+ #
46
+ # By default, FriendlyId's :slugged addon expects the slug column to be named
47
+ # 'slug', but you can change it if you wish.
48
+ #
49
+ # config.slug_column = 'slug'
50
+ #
51
+ # When FriendlyId can not generate a unique ID from your base method, it appends
52
+ # a UUID, separated by a single dash. You can configure the character used as the
53
+ # separator. If you're upgrading from FriendlyId 4, you may wish to replace this
54
+ # with two dashes.
55
+ #
56
+ # config.sequence_separator = '-'
57
+ #
58
+ # ## Tips and Tricks
59
+ #
60
+ # ### Controlling when slugs are generated
61
+ #
62
+ # As of FriendlyId 5.0, new slugs are generated only when the slug field is
63
+ # nil, but you if you're using a column as your base method can change this
64
+ # behavior by overriding the `should_generate_new_friendly_id` method that
65
+ # FriendlyId adds to your model. The change below makes FriendlyId 5.0 behave
66
+ # more like 4.0.
67
+ #
68
+ # config.use Module.new {
69
+ # def should_generate_new_friendly_id?
70
+ # slug.blank? || <your_column_name_here>_changed?
71
+ # end
72
+ # }
73
+ #
74
+ # FriendlyId uses Rails's `parameterize` method to generate slugs, but for
75
+ # languages that don't use the Roman alphabet, that's not usually suffient. Here
76
+ # we use the Babosa library to transliterate Russian Cyrillic slugs to ASCII. If
77
+ # you use this, don't forget to add "babosa" to your Gemfile.
78
+ #
79
+ # config.use Module.new {
80
+ # def normalize_friendly_id(text)
81
+ # text.to_slug.normalize! :transliterations => [:russian, :latin]
82
+ # end
83
+ # }
84
+ end
@@ -7,21 +7,15 @@ module FriendlyId
7
7
  The {FriendlyId::Reserved Reserved} module adds the ability to exlude a list of
8
8
  words from use as FriendlyId slugs.
9
9
 
10
- By default, FriendlyId reserves the words "new" and "edit" when this module is
11
- included. You can configure this globally by using {FriendlyId.defaults
12
- FriendlyId.defaults}:
10
+ With Ruby on Rails, FriendlyId's generator generates an initializer that
11
+ reserves some words such as "new" and "edit" using {FriendlyId.defaults
12
+ FriendlyId.defaults}.
13
13
 
14
- FriendlyId.defaults do |config|
15
- config.use :reserved
16
- # Reserve words for English and Spanish URLs
17
- config.reserved_words = %w(new edit nueva nuevo editar)
18
- end
19
-
20
- Note that the error message will appear on the field `:friendly_id`. If you are
21
- using Rails's scaffolded form errors display, then it will have no field to
22
- highlight. If you'd like to change this so that scaffolding works as expected,
23
- one way to accomplish this is to move the error message to a different field.
24
- For example:
14
+ Note that the error messages for fields will appear on the field
15
+ `:friendly_id`. If you are using Rails's scaffolded form errors display, then
16
+ it will have no field to highlight. If you'd like to change this so that
17
+ scaffolding works as expected, one way to accomplish this is to move the error
18
+ message to a different field. For example:
25
19
 
26
20
  class Person < ActiveRecord::Base
27
21
  extend FriendlyId
@@ -42,27 +36,16 @@ For example:
42
36
  def self.included(model_class)
43
37
  model_class.class_eval do
44
38
  friendly_id_config.class.send :include, Reserved::Configuration
45
- friendly_id_config.defaults[:reserved_words] ||= ["new", "edit"]
39
+ validates_exclusion_of :friendly_id, :in => ->(_) {
40
+ friendly_id_config.reserved_words || []
41
+ }
46
42
  end
47
43
  end
48
44
 
49
45
  # This module adds the `:reserved_words` configuration option to
50
46
  # {FriendlyId::Configuration FriendlyId::Configuration}.
51
47
  module Configuration
52
- attr_writer :reserved_words
53
-
54
- # Overrides {FriendlyId::Configuration#base} to add a validation to the
55
- # model class.
56
- def base=(base)
57
- super
58
- reserved_words = model_class.friendly_id_config.reserved_words
59
- model_class.validates_exclusion_of :friendly_id, :in => reserved_words
60
- end
61
-
62
- # An array of words forbidden as slugs.
63
- def reserved_words
64
- @reserved_words ||= @defaults[:reserved_words]
65
- end
48
+ attr_accessor :reserved_words
66
49
  end
67
50
  end
68
51
  end
@@ -298,7 +298,12 @@ Github issue](https://github.com/norman/friendly_id/issues/185) for discussion.
298
298
  private :set_slug
299
299
 
300
300
  def slug_generator
301
- friendly_id_config.slug_generator_class.new(self.class.base_class.unscoped.friendly)
301
+ scope = self.class.base_class.unscoped.friendly
302
+ if changed.include?(friendly_id_config.slug_column)
303
+ column = self.class.quoted_table_name + '.' + self.class.quoted_primary_key
304
+ scope = scope.where("#{column} <> ?", send(self.class.primary_key))
305
+ end
306
+ friendly_id_config.slug_generator_class.new(scope)
302
307
  end
303
308
  private :slug_generator
304
309
 
@@ -1,3 +1,3 @@
1
1
  module FriendlyId
2
- VERSION = "5.0.0.beta3"
2
+ VERSION = "5.0.0.beta4"
3
3
  end
@@ -8,11 +8,19 @@ class FriendlyIdGenerator < ActiveRecord::Generators::Base
8
8
  # new table name. Our generator always uses 'friendly_id_slugs', so we just set a random name here.
9
9
  argument :name, type: :string, default: 'random_name'
10
10
 
11
+ class_option :'skip-migration', :type => :boolean, :desc => "Don't generate a migration for the slugs table"
12
+ class_option :'skip-initializer', :type => :boolean, :desc => "Don't generate an initializer"
13
+
11
14
  source_root File.expand_path('../../friendly_id', __FILE__)
12
15
 
13
16
  # Copies the migration template to db/migrate.
14
17
  def copy_files
18
+ return if options['skip-migration']
15
19
  migration_template 'migration.rb', 'db/migrate/create_friendly_id_slugs.rb'
16
20
  end
17
21
 
22
+ def create_initializer
23
+ return if options['skip-initializer']
24
+ copy_file 'initializer.rb', 'config/initializers/friendly_id.rb'
25
+ end
18
26
  end
@@ -45,4 +45,20 @@ class ConfigurationTest < MiniTest::Unit::TestCase
45
45
  assert @model_class < my_module
46
46
  end
47
47
 
48
+ test "#base should optionally set a value" do
49
+ config = FriendlyId::Configuration.new @model_class
50
+ assert_nil config.base
51
+ config.base = 'foo'
52
+ assert_equal 'foo', config.base
53
+ end
54
+
55
+ test "#base can set the value to nil" do
56
+ config = FriendlyId::Configuration.new @model_class
57
+ config.base 'foo'
58
+ config.base nil
59
+ assert_nil config.base
60
+
61
+ end
62
+
63
+
48
64
  end
@@ -17,4 +17,32 @@ class FriendlyIdGeneratorTest < Rails::Generators::TestCase
17
17
  FileUtils.rm_rf self.destination_root
18
18
  end
19
19
  end
20
+
21
+ test "should skip the migration when told to do so" do
22
+ begin
23
+ run_generator ['--skip-migration']
24
+ assert_no_migration "db/migrate/create_friendly_id_slugs"
25
+ ensure
26
+ FileUtils.rm_rf self.destination_root
27
+ end
28
+ end
29
+
30
+ test "should generate an initializer" do
31
+ begin
32
+ run_generator
33
+ assert_file "config/initializers/friendly_id.rb"
34
+ ensure
35
+ FileUtils.rm_rf self.destination_root
36
+ end
37
+ end
38
+
39
+ test "should skip the initializer when told to do so" do
40
+ begin
41
+ run_generator ['--skip-initializer']
42
+ assert_no_file "config/initializers/friendly_id.rb"
43
+ ensure
44
+ FileUtils.rm_rf self.destination_root
45
+ end
46
+ end
47
+
20
48
  end
@@ -6,7 +6,7 @@ class ReservedTest < MiniTest::Unit::TestCase
6
6
 
7
7
  class Journalist < ActiveRecord::Base
8
8
  extend FriendlyId
9
- friendly_id :name
9
+ friendly_id :name, :use => [:slugged, :reserved], :reserved_words => %w(new edit)
10
10
 
11
11
  after_validation :move_friendly_id_error_to_name
12
12
 
@@ -19,8 +19,8 @@ class ReservedTest < MiniTest::Unit::TestCase
19
19
  Journalist
20
20
  end
21
21
 
22
- test "should reserve 'new' and 'edit' by default" do
23
- %w(new edit).each do |word|
22
+ test "should reserve words" do
23
+ %w(new edit NEW Edit).each do |word|
24
24
  transaction do
25
25
  assert_raises(ActiveRecord::RecordInvalid) {model_class.create! :name => word}
26
26
  end
data/test/slugged_test.rb CHANGED
@@ -29,14 +29,6 @@ class SluggedTest < MiniTest::Unit::TestCase
29
29
  Journalist
30
30
  end
31
31
 
32
- test "should not allow reserved words in resulting slug" do
33
- ["new", "New", "NEW"].each do |word|
34
- transaction do
35
- assert_raises(ActiveRecord::RecordInvalid) {model_class.create! :name => word}
36
- end
37
- end
38
- end
39
-
40
32
  test "should allow validations on the slug" do
41
33
  model_class = Class.new(ActiveRecord::Base) do
42
34
  self.table_name = "articles"
@@ -76,6 +68,15 @@ class SluggedTest < MiniTest::Unit::TestCase
76
68
  refute instance2.valid?
77
69
  end
78
70
  end
71
+
72
+ test 'should allow a record to reuse its own slug' do
73
+ with_instance_of(model_class) do |record|
74
+ old_id = record.friendly_id
75
+ record.slug = nil
76
+ record.save!
77
+ assert_equal old_id, record.friendly_id
78
+ end
79
+ end
79
80
  end
80
81
 
81
82
  class SlugGeneratorTest < MiniTest::Unit::TestCase
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.0.0.beta3
4
+ version: 5.0.0.beta4
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: 2013-08-20 00:00:00.000000000 Z
12
+ date: 2013-08-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -170,6 +170,7 @@ files:
170
170
  - lib/friendly_id/finder_methods.rb
171
171
  - lib/friendly_id/finders.rb
172
172
  - lib/friendly_id/history.rb
173
+ - lib/friendly_id/initializer.rb
173
174
  - lib/friendly_id/migration.rb
174
175
  - lib/friendly_id/object_utils.rb
175
176
  - lib/friendly_id/reserved.rb