friendly_id-globalize 1.0.0.alpha2 → 1.0.0.alpha4
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 +5 -5
- data/README.md +6 -0
- data/friendly_id-globalize.gemspec +1 -1
- data/lib/friendly_id/globalize/version.rb +1 -1
- data/lib/friendly_id/globalize.rb +5 -10
- data/lib/friendly_id/history.rb +142 -0
- data/lib/friendly_id/migration.rb +11 -0
- data/lib/generators/friendly_id_globalize_generator.rb +20 -0
- data/test/globalize_test.rb +9 -6
- metadata +10 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3c63abb7940af7e1cfb45dc6bcc7203699a4993ee7fb7d2bda9a8f788c2710a2
|
4
|
+
data.tar.gz: c87d245f950ef8da97062015d6bd05be41e4c2466953d0dcf689077d1a160839
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70275b9abdc134b05ec8e0836b0a22894f02faa18304f8962231bcb55052312dde373d115b2ee16aeed1e33220bb063776535c3911d6ec3a56cae30f13079f52
|
7
|
+
data.tar.gz: 94721821b35d7ad98055e76498ac403d964af9ad03a26daf982bf2e1bc4081e650749f4b5d6ca481260a198d04fc1970c37b98a09775c35406145c7c800e7523
|
data/README.md
CHANGED
@@ -3,6 +3,12 @@
|
|
3
3
|
[Globalize](https://github.com/globalize/globalize) support for
|
4
4
|
[FriendlyId](https://github.com/norman/friendly_id).
|
5
5
|
|
6
|
+
### Installation
|
7
|
+
```ruby
|
8
|
+
gem 'friendly_id-globalize'
|
9
|
+
rails generate friendly_id_globalize
|
10
|
+
```
|
11
|
+
|
6
12
|
### Translating Slugs Using Globalize
|
7
13
|
The `FriendlyId::Globalize Globalize` module lets you use
|
8
14
|
[Globalize](https://github.com/globalize/globalize) to translate slugs. This
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
|
17
17
|
s.required_ruby_version = '>= 1.9.3'
|
18
18
|
|
19
|
-
s.add_dependency 'friendly_id', '
|
19
|
+
s.add_dependency 'friendly_id', '>= 5.1.0', '< 6.0'
|
20
20
|
s.add_development_dependency 'minitest'
|
21
21
|
s.add_development_dependency 'yard'
|
22
22
|
s.add_development_dependency "globalize"
|
@@ -7,7 +7,7 @@ module FriendlyId
|
|
7
7
|
== Translating Slugs Using Globalize
|
8
8
|
|
9
9
|
The {FriendlyId::Globalize Globalize} module lets you use
|
10
|
-
Globalize[https://github.com/
|
10
|
+
Globalize[https://github.com/globalize/globalize] to translate slugs. This
|
11
11
|
module is most suitable for applications that need to be localized to many
|
12
12
|
languages. If your application only needs to be localized to one or two
|
13
13
|
languages, you may wish to consider the {FriendlyId::SimpleI18n SimpleI18n}
|
@@ -85,7 +85,7 @@ current locale:
|
|
85
85
|
|
86
86
|
def set_friendly_id(text, locale = nil)
|
87
87
|
::Globalize.with_locale(locale || ::Globalize.locale) do
|
88
|
-
|
88
|
+
super_set_slug normalize_friendly_id(text)
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
@@ -94,12 +94,8 @@ current locale:
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def set_slug(normalized_slug = nil)
|
97
|
-
|
98
|
-
|
99
|
-
::Globalize.with_locale(locale) { super_set_slug(normalized_slug) }
|
100
|
-
end
|
101
|
-
else
|
102
|
-
::Globalize.with_locale(::Globalize.locale) { super_set_slug(normalized_slug) }
|
97
|
+
(self.translations.map(&:locale).presence || [::Globalize.locale]).each do |locale|
|
98
|
+
::Globalize.with_locale(locale) { super_set_slug(normalized_slug) }
|
103
99
|
end
|
104
100
|
end
|
105
101
|
|
@@ -107,9 +103,8 @@ current locale:
|
|
107
103
|
if should_generate_new_friendly_id?
|
108
104
|
candidates = FriendlyId::Candidates.new(self, normalized_slug || send(friendly_id_config.base))
|
109
105
|
slug = slug_generator.generate(candidates) || resolve_friendly_id_conflict(candidates)
|
110
|
-
translation.
|
106
|
+
translation.send("#{friendly_id_config.slug_column}=", slug)
|
111
107
|
end
|
112
108
|
end
|
113
109
|
end
|
114
110
|
end
|
115
|
-
|
@@ -0,0 +1,142 @@
|
|
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_globalize
|
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
|
+
Because recording slug history requires creating additional database records,
|
27
|
+
this module has an impact on the performance of the associated model's `create`
|
28
|
+
method.
|
29
|
+
|
30
|
+
### Example
|
31
|
+
|
32
|
+
class Post < ActiveRecord::Base
|
33
|
+
extend FriendlyId
|
34
|
+
friendly_id :title, :use => :history
|
35
|
+
end
|
36
|
+
|
37
|
+
class PostsController < ApplicationController
|
38
|
+
|
39
|
+
before_filter :find_post
|
40
|
+
|
41
|
+
...
|
42
|
+
|
43
|
+
def find_post
|
44
|
+
@post = Post.find params[:id]
|
45
|
+
|
46
|
+
# If an old id or a numeric id was used to find the record, then
|
47
|
+
# the request path will not match the post_path, and we should do
|
48
|
+
# a 301 redirect that uses the current friendly id.
|
49
|
+
if request.path != post_path(@post)
|
50
|
+
return redirect_to @post, :status => :moved_permanently
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
=end
|
55
|
+
module History
|
56
|
+
|
57
|
+
def self.setup(model_class)
|
58
|
+
model_class.instance_eval do
|
59
|
+
friendly_id_config.use :slugged
|
60
|
+
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
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Configures the model instance to use the History add-on.
|
71
|
+
def self.included(model_class)
|
72
|
+
model_class.class_eval do
|
73
|
+
has_many :slugs, -> {order(Slug.arel_table[:id].desc)},
|
74
|
+
as: :sluggable,
|
75
|
+
dependent: :destroy,
|
76
|
+
class_name: Slug.to_s
|
77
|
+
|
78
|
+
after_save :create_slug
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module FinderMethods
|
83
|
+
include ::FriendlyId::FinderMethods
|
84
|
+
|
85
|
+
def exists_by_friendly_id?(id)
|
86
|
+
joins(:slugs, :translations).where(translation_class.arel_table[friendly_id_config.query_field].eq(id)).exists? || joins(:slugs).where(slug_history_clause(id)).exists?
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def first_by_friendly_id(id)
|
92
|
+
matching_record = where(friendly_id_config.query_field => id).first
|
93
|
+
matching_record || slug_table_record(id)
|
94
|
+
end
|
95
|
+
|
96
|
+
def slug_table_record(id)
|
97
|
+
select(quoted_table_name + '.*').joins(:slugs).where(slug_history_clause(id)).order(Slug.arel_table[:id].desc).first
|
98
|
+
end
|
99
|
+
|
100
|
+
def slug_history_clause(id)
|
101
|
+
Slug.arel_table[:sluggable_type].eq(base_class.to_s).and(Slug.arel_table[:slug].eq(id)).and(Slug.arel_table[:locale].eq(::Globalize.locale))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# If we're updating, don't consider historic slugs for the same record
|
108
|
+
# to be conflicts. This will allow a record to revert to a previously
|
109
|
+
# used slug.
|
110
|
+
def scope_for_slug_generator
|
111
|
+
relation = super
|
112
|
+
return relation if new_record?
|
113
|
+
relation = relation.merge(Slug.where('sluggable_id <> ?', id))
|
114
|
+
if friendly_id_config.uses?(:scoped)
|
115
|
+
relation = relation.where(Slug.arel_table[:scope].eq(serialized_scope))
|
116
|
+
end
|
117
|
+
relation
|
118
|
+
end
|
119
|
+
|
120
|
+
def create_slug
|
121
|
+
translations.map(&:locale).each do |locale|
|
122
|
+
::Globalize.with_locale(locale) { super_create_slug(locale) }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def super_create_slug(locale)
|
127
|
+
return unless friendly_id
|
128
|
+
return if slugs.where(locale: locale).first.try(:slug) == friendly_id
|
129
|
+
# Allow reversion back to a previously used slug
|
130
|
+
relation = slugs.where(slug: friendly_id, locale: locale)
|
131
|
+
if friendly_id_config.uses?(:scoped)
|
132
|
+
relation = relation.where(:scope => serialized_scope)
|
133
|
+
end
|
134
|
+
relation.delete_all
|
135
|
+
slugs.create! do |record|
|
136
|
+
record.slug = friendly_id
|
137
|
+
record.locale = locale
|
138
|
+
record.scope = serialized_scope if friendly_id_config.uses?(:scoped)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class AddLocaleToFriendlyIdSlugs < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
add_column :friendly_id_slugs, :locale, :string, length: 2, null: :false, after: :scope
|
4
|
+
|
5
|
+
remove_index :friendly_id_slugs, [:slug, :sluggable_type]
|
6
|
+
add_index :friendly_id_slugs, [:slug, :sluggable_type, :locale], length: { slug: 140, sluggable_type: 50, locale: 2 }
|
7
|
+
remove_index :friendly_id_slugs, [:slug, :sluggable_type, :scope]
|
8
|
+
add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope, :locale], length: { slug: 70, sluggable_type: 50, scope: 70, locale: 2 }, unique: true, name: :index_friendly_id_slugs_uniqueness
|
9
|
+
add_index :friendly_id_slugs, :locale
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require "rails/generators/active_record"
|
3
|
+
|
4
|
+
# This generator adds a migration for the {FriendlyId::History
|
5
|
+
# FriendlyId::History} addon.
|
6
|
+
class FriendlyIdGlobalizeGenerator < ActiveRecord::Generators::Base
|
7
|
+
# ActiveRecord::Generators::Base inherits from Rails::Generators::NamedBase which requires a NAME parameter for the
|
8
|
+
# new table name. Our generator always uses 'friendly_id_slugs', so we just set a random name here.
|
9
|
+
argument :name, type: :string, default: 'random_name'
|
10
|
+
|
11
|
+
class_option :'skip-migration', :type => :boolean, :desc => "Don't generate a migration for the slugs table"
|
12
|
+
|
13
|
+
source_root File.expand_path('../../friendly_id', __FILE__)
|
14
|
+
|
15
|
+
# Copies the migration template to db/migrate.
|
16
|
+
def copy_files
|
17
|
+
return if options['skip-migration']
|
18
|
+
migration_template 'migration.rb', 'db/migrate/add_locale_to_friendly_id_slugs.rb'
|
19
|
+
end
|
20
|
+
end
|
data/test/globalize_test.rb
CHANGED
@@ -22,14 +22,14 @@ ActiveRecord::Migration.verbose = false
|
|
22
22
|
FriendlyIdGlobalizeTest.up
|
23
23
|
|
24
24
|
class Article < ActiveRecord::Base
|
25
|
-
translates :
|
25
|
+
translates :my_slug, :title, fallbacks_for_empty_translations: true
|
26
26
|
accepts_nested_attributes_for :translations
|
27
27
|
|
28
28
|
extend FriendlyId
|
29
|
-
friendly_id :title, :use =>
|
29
|
+
friendly_id :title, :use => :globalize, :slug_column => 'my_slug'
|
30
30
|
end
|
31
31
|
|
32
|
-
Article.create_translation_table! :
|
32
|
+
Article.create_translation_table! :my_slug => :string, :title => :string
|
33
33
|
|
34
34
|
class Module
|
35
35
|
def test(name, &block)
|
@@ -77,21 +77,25 @@ class GlobalizeTest < MiniTest::Unit::TestCase
|
|
77
77
|
transaction do
|
78
78
|
article = Article.create!(:title => "War and Peace")
|
79
79
|
article.set_friendly_id("Guerra y paz", :es)
|
80
|
+
article.set_friendly_id("Guerra e pace", :it)
|
80
81
|
article.save!
|
81
82
|
found_article = Article.friendly.find('war-and-peace')
|
82
83
|
I18n.with_locale(:es) { assert_equal "guerra-y-paz", found_article.friendly_id }
|
83
84
|
I18n.with_locale(:en) { assert_equal "war-and-peace", found_article.friendly_id }
|
85
|
+
I18n.with_locale(:it) { assert_equal "guerra-e-pace", found_article.friendly_id }
|
84
86
|
end
|
85
87
|
end
|
86
88
|
|
87
89
|
test "should set all friendly ids for each nested translation" do
|
88
90
|
transaction do
|
89
91
|
article = Article.create!(translations_attributes: {
|
90
|
-
xx: { :
|
91
|
-
yy: { title: 'Guerre et paix', locale: 'fr' }
|
92
|
+
xx: { title: 'Guerra e pace', locale: 'it' },
|
93
|
+
yy: { title: 'Guerre et paix', locale: 'fr' },
|
94
|
+
zz: { title: 'Guerra y paz', locale: 'es' }
|
92
95
|
})
|
93
96
|
I18n.with_locale(:it) { assert_equal "guerra-e-pace", article.friendly_id }
|
94
97
|
I18n.with_locale(:fr) { assert_equal "guerre-et-paix", article.friendly_id }
|
98
|
+
I18n.with_locale(:es) { assert_equal "guerra-y-paz", article.friendly_id }
|
95
99
|
end
|
96
100
|
end
|
97
101
|
|
@@ -110,4 +114,3 @@ class GlobalizeTest < MiniTest::Unit::TestCase
|
|
110
114
|
end
|
111
115
|
end
|
112
116
|
end
|
113
|
-
|
metadata
CHANGED
@@ -1,21 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: friendly_id-globalize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.alpha4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Norman Clarke
|
8
8
|
- Philip Arndt
|
9
|
-
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2025-03-04 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: friendly_id
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
16
|
requirements:
|
18
|
-
- - "
|
17
|
+
- - ">="
|
19
18
|
- !ruby/object:Gem::Version
|
20
19
|
version: 5.1.0
|
21
20
|
- - "<"
|
@@ -25,7 +24,7 @@ dependencies:
|
|
25
24
|
prerelease: false
|
26
25
|
version_requirements: !ruby/object:Gem::Requirement
|
27
26
|
requirements:
|
28
|
-
- - "
|
27
|
+
- - ">="
|
29
28
|
- !ruby/object:Gem::Version
|
30
29
|
version: 5.1.0
|
31
30
|
- - "<"
|
@@ -90,12 +89,14 @@ files:
|
|
90
89
|
- friendly_id-globalize.gemspec
|
91
90
|
- lib/friendly_id/globalize.rb
|
92
91
|
- lib/friendly_id/globalize/version.rb
|
92
|
+
- lib/friendly_id/history.rb
|
93
|
+
- lib/friendly_id/migration.rb
|
94
|
+
- lib/generators/friendly_id_globalize_generator.rb
|
93
95
|
- test/globalize_test.rb
|
94
96
|
homepage: http://github.com/norman/friendly_id-globalize
|
95
97
|
licenses:
|
96
98
|
- MIT
|
97
99
|
metadata: {}
|
98
|
-
post_install_message:
|
99
100
|
rdoc_options: []
|
100
101
|
require_paths:
|
101
102
|
- lib
|
@@ -106,14 +107,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
106
107
|
version: 1.9.3
|
107
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
109
|
requirements:
|
109
|
-
- - "
|
110
|
+
- - ">="
|
110
111
|
- !ruby/object:Gem::Version
|
111
|
-
version:
|
112
|
+
version: '0'
|
112
113
|
requirements: []
|
113
|
-
|
114
|
-
rubygems_version: 2.4.6
|
115
|
-
signing_key:
|
114
|
+
rubygems_version: 3.6.2
|
116
115
|
specification_version: 4
|
117
116
|
summary: Globalize support for FriendlyId.
|
118
117
|
test_files: []
|
119
|
-
has_rdoc:
|