mil_friendly_id 4.0.9.8
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 +7 -0
- data/.gemtest +0 -0
- data/.gitignore +12 -0
- data/.travis.yml +20 -0
- data/.yardopts +4 -0
- data/Changelog.md +86 -0
- data/Gemfile +15 -0
- data/Guide.rdoc +553 -0
- data/MIT-LICENSE +19 -0
- data/README.md +150 -0
- data/Rakefile +108 -0
- data/WhatsNew.md +95 -0
- data/bench.rb +63 -0
- data/friendly_id.gemspec +43 -0
- data/gemfiles/Gemfile.rails-3.0.rb +21 -0
- data/gemfiles/Gemfile.rails-3.1.rb +22 -0
- data/gemfiles/Gemfile.rails-3.2.rb +22 -0
- data/geothird_friendly_id.gemspec +45 -0
- data/lib/friendly_id.rb +114 -0
- data/lib/friendly_id/base.rb +291 -0
- data/lib/friendly_id/configuration.rb +80 -0
- data/lib/friendly_id/finder_methods.rb +35 -0
- data/lib/friendly_id/globalize.rb +115 -0
- data/lib/friendly_id/history.rb +134 -0
- data/lib/friendly_id/migration.rb +19 -0
- data/lib/friendly_id/object_utils.rb +50 -0
- data/lib/friendly_id/reserved.rb +68 -0
- data/lib/friendly_id/scoped.rb +149 -0
- data/lib/friendly_id/simple_i18n.rb +95 -0
- data/lib/friendly_id/slug.rb +14 -0
- data/lib/friendly_id/slug_generator.rb +80 -0
- data/lib/friendly_id/slugged.rb +329 -0
- data/lib/generators/friendly_id_generator.rb +17 -0
- data/mil_friendly_id.gemspec +45 -0
- data/test/base_test.rb +72 -0
- data/test/compatibility/ancestry/Gemfile +8 -0
- data/test/compatibility/ancestry/ancestry_test.rb +34 -0
- data/test/compatibility/threading/Gemfile +8 -0
- data/test/compatibility/threading/threading.rb +45 -0
- data/test/configuration_test.rb +48 -0
- data/test/core_test.rb +48 -0
- data/test/databases.yml +19 -0
- data/test/generator_test.rb +20 -0
- data/test/globalize_test.rb +57 -0
- data/test/helper.rb +87 -0
- data/test/history_test.rb +149 -0
- data/test/object_utils_test.rb +28 -0
- data/test/reserved_test.rb +40 -0
- data/test/schema.rb +79 -0
- data/test/scoped_test.rb +83 -0
- data/test/shared.rb +156 -0
- data/test/simple_i18n_test.rb +133 -0
- data/test/slugged_test.rb +280 -0
- data/test/sti_test.rb +77 -0
- metadata +262 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
# The configuration paramters passed to +friendly_id+ will be stored in
|
3
|
+
# this object.
|
4
|
+
class Configuration
|
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
|
+
# @param [Symbol] 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
|
29
|
+
|
30
|
+
# The default configuration options.
|
31
|
+
attr_reader :defaults
|
32
|
+
|
33
|
+
# The model class that this configuration belongs to.
|
34
|
+
# @return ActiveRecord::Base
|
35
|
+
attr_accessor :model_class
|
36
|
+
|
37
|
+
def initialize(model_class, values = nil)
|
38
|
+
@model_class = model_class
|
39
|
+
@defaults = {}
|
40
|
+
set values
|
41
|
+
end
|
42
|
+
|
43
|
+
# Lets you specify the modules to use with FriendlyId.
|
44
|
+
#
|
45
|
+
# This method is invoked by {FriendlyId::Base#friendly_id friendly_id} when
|
46
|
+
# passing the +:use+ option, or when using {FriendlyId::Base#friendly_id
|
47
|
+
# friendly_id} with a block.
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# class Book < ActiveRecord::Base
|
51
|
+
# extend FriendlyId
|
52
|
+
# friendly_id :name, :use => :slugged
|
53
|
+
# end
|
54
|
+
# @param [#to_s,Module] *modules Arguments should be Modules, or symbols or
|
55
|
+
# strings that correspond with the name of a module inside the FriendlyId
|
56
|
+
# namespace. By default FriendlyId provides +:slugged+, +:history+,
|
57
|
+
# +:simple_i18n+, +:globalize+, and +:scoped+.
|
58
|
+
def use(*modules)
|
59
|
+
modules.to_a.flatten.compact.map do |object|
|
60
|
+
mod = object.kind_of?(Module) ? object : FriendlyId.const_get(object.to_s.classify)
|
61
|
+
model_class.send(:include, mod)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# The column that FriendlyId will use to find the record when querying by
|
66
|
+
# friendly id.
|
67
|
+
#
|
68
|
+
# This method is generally only used internally by FriendlyId.
|
69
|
+
# @return String
|
70
|
+
def query_field
|
71
|
+
base.to_s
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def set(values)
|
77
|
+
values and values.each {|name, value| self.send "#{name}=", value}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
# These methods will be added to the model's {FriendlyId::Base#relation_class relation_class}.
|
3
|
+
module FinderMethods
|
4
|
+
|
5
|
+
protected
|
6
|
+
|
7
|
+
# FriendlyId overrides this method to make it possible to use friendly id's
|
8
|
+
# identically to numeric ids in finders.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# person = Person.find(123)
|
12
|
+
# person = Person.find("joe")
|
13
|
+
#
|
14
|
+
# @see FriendlyId::ObjectUtils
|
15
|
+
def find_one(id)
|
16
|
+
return super if id.unfriendly_id?
|
17
|
+
where(@klass.friendly_id_config.query_field => id).first or super
|
18
|
+
end
|
19
|
+
|
20
|
+
# FriendlyId overrides this method to make it possible to use friendly id's
|
21
|
+
# identically to numeric ids in finders.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# person = Person.exists?(123)
|
25
|
+
# person = Person.exists?("joe")
|
26
|
+
# person = Person.exists?({:name => 'joe'})
|
27
|
+
# person = Person.exists?(['name = ?', 'joe'])
|
28
|
+
#
|
29
|
+
# @see FriendlyId::ObjectUtils
|
30
|
+
def exists?(id = false)
|
31
|
+
return super if id.unfriendly_id?
|
32
|
+
super @klass.friendly_id_config.query_field => id
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
|
3
|
+
module FriendlyId
|
4
|
+
|
5
|
+
=begin
|
6
|
+
|
7
|
+
== Translating Slugs Using Globalize
|
8
|
+
|
9
|
+
The {FriendlyId::Globalize Globalize} module lets you use
|
10
|
+
Globalize[https://github.com/svenfuchs/globalize3] to translate slugs. This
|
11
|
+
module is most suitable for applications that need to be localized to many
|
12
|
+
languages. If your application only needs to be localized to one or two
|
13
|
+
languages, you may wish to consider the {FriendlyId::SimpleI18n SimpleI18n}
|
14
|
+
module.
|
15
|
+
|
16
|
+
In order to use this module, your model's table and translation table must both
|
17
|
+
have a slug column, and your model must set the +slug+ field as translatable
|
18
|
+
with Globalize:
|
19
|
+
|
20
|
+
class Post < ActiveRecord::Base
|
21
|
+
translates :title, :slug
|
22
|
+
extend FriendlyId
|
23
|
+
friendly_id :title, :use => :globalize
|
24
|
+
end
|
25
|
+
|
26
|
+
=== Finds
|
27
|
+
|
28
|
+
Finds will take the current locale into consideration:
|
29
|
+
|
30
|
+
I18n.locale = :it
|
31
|
+
Post.find("guerre-stellari")
|
32
|
+
I18n.locale = :en
|
33
|
+
Post.find("star-wars")
|
34
|
+
|
35
|
+
Additionally, finds will fall back to the default locale:
|
36
|
+
|
37
|
+
I18n.locale = :it
|
38
|
+
Post.find("star-wars")
|
39
|
+
|
40
|
+
To find a slug by an explicit locale, perform the find inside a block
|
41
|
+
passed to I18n's +with_locale+ method:
|
42
|
+
|
43
|
+
I18n.with_locale(:it) { Post.find("guerre-stellari") }
|
44
|
+
|
45
|
+
=== Creating Records
|
46
|
+
|
47
|
+
When new records are created, the slug is generated for the current locale only.
|
48
|
+
|
49
|
+
=== Translating Slugs
|
50
|
+
|
51
|
+
To translate an existing record's friendly_id, use
|
52
|
+
{FriendlyId::Globalize::Model#set_friendly_id}. This will ensure that the slug
|
53
|
+
you add is properly escaped, transliterated and sequenced:
|
54
|
+
|
55
|
+
post = Post.create :name => "Star Wars"
|
56
|
+
post.set_friendly_id("Guerre stellari", :it)
|
57
|
+
|
58
|
+
If you don't pass in a locale argument, FriendlyId::Globalize will just use the
|
59
|
+
current locale:
|
60
|
+
|
61
|
+
I18n.with_locale(:it) { post.set_friendly_id("Guerre stellari") }
|
62
|
+
|
63
|
+
=end
|
64
|
+
module Globalize
|
65
|
+
|
66
|
+
def self.included(model_class)
|
67
|
+
model_class.instance_eval do
|
68
|
+
friendly_id_config.use :slugged
|
69
|
+
relation_class.send :include, FinderMethods
|
70
|
+
include Model
|
71
|
+
# Check if slug field is enabled to be translated with Globalize
|
72
|
+
unless respond_to?('translated_attribute_names') || translated_attribute_names.exclude?(friendly_id_config.query_field.to_sym)
|
73
|
+
puts "\n[FriendlyId] You need to translate '#{friendly_id_config.query_field}' field with Globalize (add 'translates :#{friendly_id_config.query_field}' in your model '#{self.class.name}')\n\n"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
module Model
|
79
|
+
def set_friendly_id(text, locale)
|
80
|
+
I18n.with_locale(locale || I18n.locale) do
|
81
|
+
set_slug(normalize_friendly_id(text))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
module FinderMethods
|
87
|
+
# FriendlyId overrides this method to make it possible to use friendly id's
|
88
|
+
# identically to numeric ids in finders.
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# person = Person.find(123)
|
92
|
+
# person = Person.find("joe")
|
93
|
+
#
|
94
|
+
# @see FriendlyId::ObjectUtils
|
95
|
+
def find_one(id)
|
96
|
+
return super if id.unfriendly_id?
|
97
|
+
found = where(@klass.friendly_id_config.query_field => id).first
|
98
|
+
found = includes(:translations).
|
99
|
+
where(translation_class.arel_table[:locale].in([I18n.locale, I18n.default_locale])).
|
100
|
+
where(translation_class.arel_table[@klass.friendly_id_config.query_field].eq(id)).first if found.nil?
|
101
|
+
|
102
|
+
if found
|
103
|
+
# Reload the translations for the found records.
|
104
|
+
found.tap { |f| f.translations.reload }
|
105
|
+
else
|
106
|
+
# if locale is not translated fallback to default locale
|
107
|
+
super
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
protected :find_one
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
== History: Avoiding 404's When Slugs Change
|
6
|
+
|
7
|
+
FriendlyId's {FriendlyId::History History} module adds the ability to store a
|
8
|
+
log of a model's slugs, so that when its friendly id changes, it's still
|
9
|
+
possible to perform finds by the old id.
|
10
|
+
|
11
|
+
The primary use case for this is avoiding broken URLs.
|
12
|
+
|
13
|
+
=== Setup
|
14
|
+
|
15
|
+
In order to use this module, you must add a table to your database schema to
|
16
|
+
store the slug records. FriendlyId provides a generator for this purpose:
|
17
|
+
|
18
|
+
rails generate friendly_id
|
19
|
+
rake db:migrate
|
20
|
+
|
21
|
+
This will add a table named +friendly_id_slugs+, used by the {FriendlyId::Slug}
|
22
|
+
model.
|
23
|
+
|
24
|
+
=== Considerations
|
25
|
+
|
26
|
+
This module is incompatible with the +:scoped+ module.
|
27
|
+
|
28
|
+
Because recording slug history requires creating additional database records,
|
29
|
+
this module has an impact on the performance of the associated model's +create+
|
30
|
+
method.
|
31
|
+
|
32
|
+
=== Example
|
33
|
+
|
34
|
+
class Post < ActiveRecord::Base
|
35
|
+
extend FriendlyId
|
36
|
+
friendly_id :title, :use => :history
|
37
|
+
end
|
38
|
+
|
39
|
+
class PostsController < ApplicationController
|
40
|
+
|
41
|
+
before_filter :find_post
|
42
|
+
|
43
|
+
...
|
44
|
+
|
45
|
+
def find_post
|
46
|
+
@post = Post.find params[:id]
|
47
|
+
|
48
|
+
# If an old id or a numeric id was used to find the record, then
|
49
|
+
# the request path will not match the post_path, and we should do
|
50
|
+
# a 301 redirect that uses the current friendly id.
|
51
|
+
if request.path != post_path(@post)
|
52
|
+
return redirect_to @post, :status => :moved_permanently
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
=end
|
57
|
+
module History
|
58
|
+
|
59
|
+
# Configures the model instance to use the History add-on.
|
60
|
+
def self.included(model_class)
|
61
|
+
model_class.instance_eval do
|
62
|
+
raise "FriendlyId::History is incompatible with FriendlyId::Scoped" if self < Scoped
|
63
|
+
@friendly_id_config.use :slugged
|
64
|
+
has_many :slugs, :as => :sluggable, :dependent => :destroy,
|
65
|
+
:class_name => Slug.to_s, :order => "#{Slug.quoted_table_name}.id DESC"
|
66
|
+
after_save :create_slug
|
67
|
+
relation_class.send :include, FinderMethods
|
68
|
+
friendly_id_config.slug_generator_class.send :include, SlugGenerator
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def create_slug
|
75
|
+
return unless friendly_id
|
76
|
+
return if slugs.first.try(:slug) == friendly_id
|
77
|
+
# Allow reversion back to a previously used slug
|
78
|
+
relation = slugs.where(:slug => friendly_id)
|
79
|
+
result = relation.select("id").lock(true).all
|
80
|
+
relation.delete_all unless result.empty?
|
81
|
+
slugs.create! do |record|
|
82
|
+
record.slug = friendly_id
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Adds a finder that explictly uses slugs from the slug table.
|
87
|
+
module FinderMethods
|
88
|
+
|
89
|
+
# Search for a record in the slugs table using the specified slug.
|
90
|
+
def find_one(id)
|
91
|
+
return super(id) if id.unfriendly_id?
|
92
|
+
where(@klass.friendly_id_config.query_field => id).first or
|
93
|
+
with_old_friendly_id(id) {|x| find_one_without_friendly_id(x)} or
|
94
|
+
find_one_without_friendly_id(id)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Search for a record in the slugs table using the specified slug.
|
98
|
+
def exists?(id = false)
|
99
|
+
return super if id.unfriendly_id?
|
100
|
+
exists_without_friendly_id?(@klass.friendly_id_config.query_field => id) or
|
101
|
+
with_old_friendly_id(id) {|x| exists_without_friendly_id?(x)} or
|
102
|
+
exists_without_friendly_id?(id)
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# Accepts a slug, and yields a corresponding sluggable_id into the block.
|
108
|
+
def with_old_friendly_id(slug, &block)
|
109
|
+
sql = "SELECT sluggable_id FROM #{Slug.quoted_table_name} WHERE sluggable_type = %s AND slug = %s"
|
110
|
+
sql = sql % [@klass.base_class.to_s, slug].map {|x| connection.quote(x)}
|
111
|
+
sluggable_id = connection.select_values(sql).first
|
112
|
+
yield sluggable_id if sluggable_id
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# This module overrides {FriendlyId::SlugGenerator#conflicts} to consider
|
117
|
+
# all historic slugs for that model.
|
118
|
+
module SlugGenerator
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def conflicts
|
123
|
+
sluggable_class = friendly_id_config.model_class.base_class
|
124
|
+
pkey = sluggable_class.primary_key
|
125
|
+
value = sluggable.send pkey
|
126
|
+
|
127
|
+
scope = Slug.with_deleted.where("slug = ? OR slug LIKE ?", normalized, wildcard)
|
128
|
+
scope = scope.where(:sluggable_type => sluggable_class.to_s)
|
129
|
+
scope = scope.where("sluggable_id <> ?", value) unless sluggable.new_record?
|
130
|
+
scope.order("LENGTH(slug) DESC, slug DESC")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateSlugs < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :slugs do |t|
|
5
|
+
t.string :slug, :null => false
|
6
|
+
t.integer :sluggable_id, :null => false
|
7
|
+
t.string :sluggable_type, :limit => 40
|
8
|
+
t.datetime :created_at
|
9
|
+
t.deleted_at :boolean
|
10
|
+
end
|
11
|
+
add_index :slugs, :sluggable_id
|
12
|
+
add_index :slugs, [:slug, :sluggable_type], :unique => true
|
13
|
+
add_index :slugs, :sluggable_type
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.down
|
17
|
+
drop_table :slugs
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
# Utility methods for determining whether any object is a friendly id.
|
3
|
+
#
|
4
|
+
# Monkey-patching Object is a somewhat extreme measure not to be taken lightly
|
5
|
+
# by libraries, but in this case I decided to do it because to me, it feels
|
6
|
+
# cleaner than adding a module method to {FriendlyId}. I've given the methods
|
7
|
+
# names that unambigously refer to the library of their origin, which should
|
8
|
+
# be sufficient to avoid conflicts with other libraries.
|
9
|
+
module ObjectUtils
|
10
|
+
|
11
|
+
# True is the id is definitely friendly, false if definitely unfriendly,
|
12
|
+
# else nil.
|
13
|
+
#
|
14
|
+
# An object is considired "definitely unfriendly" if its class is or
|
15
|
+
# inherits from ActiveRecord::Base, Array, Hash, NilClass, Numeric, or
|
16
|
+
# Symbol.
|
17
|
+
#
|
18
|
+
# An object is considered "definitely friendly" if it responds to +to_i+,
|
19
|
+
# and its value when cast to an integer and then back to a string is
|
20
|
+
# different from its value when merely cast to a string:
|
21
|
+
#
|
22
|
+
# 123.friendly_id? #=> false
|
23
|
+
# :id.friendly_id? #=> false
|
24
|
+
# {:name => 'joe'}.friendly_id? #=> false
|
25
|
+
# ['name = ?', 'joe'].friendly_id? #=> false
|
26
|
+
# nil.friendly_id? #=> false
|
27
|
+
# "123".friendly_id? #=> nil
|
28
|
+
# "abc123".friendly_id? #=> true
|
29
|
+
def friendly_id?
|
30
|
+
# Considered unfriendly if this is an instance of an unfriendly class or
|
31
|
+
# one of its descendants.
|
32
|
+
unfriendly_classes = [ActiveRecord::Base, Array, Hash, NilClass, Numeric,
|
33
|
+
Symbol, TrueClass, FalseClass]
|
34
|
+
|
35
|
+
if unfriendly_classes.detect {|klass| self.class <= klass}
|
36
|
+
false
|
37
|
+
elsif respond_to?(:to_i) && to_i.to_s != to_s
|
38
|
+
true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# True if the id is definitely unfriendly, false if definitely friendly,
|
43
|
+
# else nil.
|
44
|
+
def unfriendly_id?
|
45
|
+
val = friendly_id? ; !val unless val.nil?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Object.send :include, FriendlyId::ObjectUtils
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
== Reserved Words
|
6
|
+
|
7
|
+
The {FriendlyId::Reserved Reserved} module adds the ability to exlude a list of
|
8
|
+
words from use as FriendlyId slugs.
|
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}:
|
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:
|
25
|
+
|
26
|
+
class Person < ActiveRecord::Base
|
27
|
+
extend FriendlyId
|
28
|
+
friendly_id :name, use: :slugged
|
29
|
+
|
30
|
+
after_validation :move_friendly_id_error_to_name
|
31
|
+
|
32
|
+
def move_friendly_id_error_to_name
|
33
|
+
errors.add :name, *errors.delete(:friendly_id) if errors[:friendly_id].present?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
=end
|
38
|
+
module Reserved
|
39
|
+
|
40
|
+
# When included, this module adds configuration options to the model class's
|
41
|
+
# friendly_id_config.
|
42
|
+
def self.included(model_class)
|
43
|
+
model_class.class_eval do
|
44
|
+
friendly_id_config.class.send :include, Reserved::Configuration
|
45
|
+
friendly_id_config.defaults[:reserved_words] ||= ["new", "edit"]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# This module adds the +:reserved_words+ configuration option to
|
50
|
+
# {FriendlyId::Configuration FriendlyId::Configuration}.
|
51
|
+
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
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|