active_permalink 0.2.0 → 0.3.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 +4 -4
- data/lib/active_permalink.rb +2 -0
- data/lib/active_permalink/generator.rb +81 -34
- data/lib/active_permalink/loader.rb +31 -11
- data/lib/active_permalink/localizer.rb +86 -0
- data/lib/active_permalink/permalink.rb +3 -1
- data/lib/active_permalink/persistence.rb +22 -0
- data/lib/active_permalink/querying.rb +55 -15
- data/lib/active_permalink/version.rb +1 -1
- metadata +16 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b16f6386aa52361de778a4b894b3479fd489e44a4144e116076c73f7b21cce68
|
4
|
+
data.tar.gz: a43e93473637eded10cb189a4ee2a9829579bc11b32b749ac470adf66558eb5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8db0d6f4e65f9fe4dc46e36f2555371040a7851d95a39b860e3f5fef42080dda00bd576048b80fc4a7ec77516e28869987b800c8db99c9d13c720d949a5818b1
|
7
|
+
data.tar.gz: 89a4f9e787ac3dc150204dceac4cb88836c92bc736502567c974842e98ef9c6199d1ac6d7e90d64b53e2da692e1922ec3ce7444bf3d0ddccab44d9351a038c4c
|
data/lib/active_permalink.rb
CHANGED
@@ -1,60 +1,107 @@
|
|
1
1
|
module ActivePermalink
|
2
2
|
class Generator
|
3
|
-
def initialize(record,
|
4
|
-
@record
|
5
|
-
@
|
6
|
-
@
|
3
|
+
def initialize(record, options = {})
|
4
|
+
@record = record
|
5
|
+
@options = options
|
6
|
+
@field = options[:field]
|
7
|
+
@scope = options.fetch(:scope, :global)
|
8
|
+
end
|
9
|
+
|
10
|
+
def generate(new_value)
|
7
11
|
@new_value = new_value
|
8
|
-
|
9
|
-
|
12
|
+
return unless changed?
|
13
|
+
|
14
|
+
deactivate_active_permalink
|
15
|
+
assign_active_permalink
|
10
16
|
end
|
11
17
|
|
12
|
-
def
|
13
|
-
@
|
18
|
+
def permalinks
|
19
|
+
@permalinks ||= @record.permalinks
|
14
20
|
end
|
15
21
|
|
16
|
-
|
17
|
-
|
22
|
+
private
|
23
|
+
|
24
|
+
def locale
|
25
|
+
I18n.locale.to_s
|
18
26
|
end
|
19
27
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
28
|
+
def changed?
|
29
|
+
@new_value.blank? || @new_value != active_permalink.try(:slug)
|
30
|
+
end
|
23
31
|
|
24
|
-
|
25
|
-
|
26
|
-
|
32
|
+
def localized?
|
33
|
+
@options[:localized].present?
|
34
|
+
end
|
27
35
|
|
28
|
-
|
36
|
+
def locale_column
|
37
|
+
@options[:locale_column]
|
29
38
|
end
|
30
39
|
|
31
|
-
def
|
32
|
-
|
40
|
+
def exists?(slug)
|
41
|
+
params = localize(scope: @scope, slug: slug)
|
42
|
+
Permalink.where(params).count.zero?
|
43
|
+
end
|
44
|
+
|
45
|
+
def localize(**params)
|
46
|
+
params[locale_column] = locale if localized?
|
47
|
+
params
|
48
|
+
end
|
49
|
+
|
50
|
+
def available_permalinks
|
51
|
+
if localized?
|
52
|
+
permalinks.select { |item| item.send(locale_column) == locale }
|
53
|
+
else
|
54
|
+
permalinks
|
55
|
+
end
|
56
|
+
end
|
33
57
|
|
34
|
-
|
35
|
-
|
58
|
+
def active_permalink
|
59
|
+
available_permalinks.find { |item| item.active == true }
|
60
|
+
end
|
36
61
|
|
37
|
-
|
62
|
+
def build_permalink
|
63
|
+
params = localize(scope: @scope, active: true)
|
64
|
+
active_permalink || permalinks.build(params)
|
38
65
|
end
|
39
66
|
|
40
|
-
def
|
41
|
-
|
42
|
-
return if permalink.nil?
|
67
|
+
def old_permalink
|
68
|
+
params = localize(slug: slug_from_column)
|
43
69
|
|
44
|
-
|
45
|
-
|
70
|
+
available_permalinks.find do |item|
|
71
|
+
params.all? { |key, value| item.send(key) == value }
|
72
|
+
end
|
46
73
|
end
|
47
74
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
75
|
+
def slug_from_column
|
76
|
+
@slug_from_column ||= begin
|
77
|
+
value = @new_value.presence || @record.send(@field)
|
78
|
+
value.to_s.to_url
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def scope_unique_slug
|
83
|
+
unique = slug_from_column
|
84
|
+
index = 1
|
85
|
+
|
86
|
+
while not exists?(unique)
|
87
|
+
unique = "#{slug_from_column}-#{(index += 1)}"
|
88
|
+
end
|
89
|
+
|
90
|
+
unique
|
51
91
|
end
|
52
92
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
93
|
+
def deactivate_active_permalink
|
94
|
+
available_permalinks.each do |item|
|
95
|
+
item.active = false unless item.new_record?
|
96
|
+
end
|
97
|
+
end
|
56
98
|
|
57
|
-
|
99
|
+
def assign_active_permalink
|
100
|
+
if old_permalink
|
101
|
+
old_permalink.write_attribute(:active, true)
|
102
|
+
else
|
103
|
+
build_permalink.write_attribute(:slug, scope_unique_slug)
|
104
|
+
end
|
58
105
|
end
|
59
106
|
end
|
60
107
|
end
|
@@ -3,23 +3,43 @@ module ActivePermalink
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
class_methods do
|
6
|
-
def has_permalink(field,
|
6
|
+
def has_permalink(field, localized: false, locale_column: :locale, **options)
|
7
7
|
include ActiveDelegate
|
8
|
-
include Querying
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
class_attribute :permalink_options
|
10
|
+
|
11
|
+
self.permalink_options = options.merge(
|
12
|
+
field: field,
|
13
|
+
localized: localized,
|
14
|
+
locale_column: locale_column
|
15
|
+
)
|
16
|
+
|
17
|
+
with_options(as: :sluggable, class_name: 'ActivePermalink::Permalink') do
|
18
|
+
has_many :permalinks,
|
19
|
+
dependent: :destroy,
|
20
|
+
autosave: true
|
21
|
+
|
22
|
+
has_many :old_permalinks,
|
23
|
+
-> { inactive }
|
13
24
|
|
14
|
-
|
15
|
-
|
25
|
+
if localized
|
26
|
+
has_many :active_permalinks,
|
27
|
+
-> { active }
|
16
28
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
29
|
+
has_one :active_permalink,
|
30
|
+
-> { active.where(locale_column => I18n.locale) }
|
31
|
+
else
|
32
|
+
has_one :active_permalink,
|
33
|
+
-> { active }
|
21
34
|
end
|
22
35
|
end
|
36
|
+
|
37
|
+
delegate_attribute :slug, :string,
|
38
|
+
to: :active_permalink
|
39
|
+
|
40
|
+
include Persistence
|
41
|
+
include Querying
|
42
|
+
include Localizer if localized
|
23
43
|
end
|
24
44
|
end
|
25
45
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module ActivePermalink
|
2
|
+
module Localizer
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def permalink_reader
|
7
|
+
PermalinkReader.new(permalinks, permalink_options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def slug?
|
11
|
+
permalink_reader.exists?
|
12
|
+
end
|
13
|
+
|
14
|
+
def slug
|
15
|
+
permalink_reader.value
|
16
|
+
end
|
17
|
+
|
18
|
+
I18n.available_locales.each do |locale|
|
19
|
+
define_method(:"slug_#{locale}?") do
|
20
|
+
I18n.with_locale(locale) { slug? }
|
21
|
+
end
|
22
|
+
|
23
|
+
define_method(:"slug_#{locale}") do
|
24
|
+
I18n.with_locale(locale) { slug }
|
25
|
+
end
|
26
|
+
|
27
|
+
define_method(:"slug_#{locale}=") do |value|
|
28
|
+
I18n.with_locale(locale) { send(:slug=, value) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class PermalinkReader
|
34
|
+
attr_reader :permalinks, :options
|
35
|
+
|
36
|
+
def initialize(permalinks, options)
|
37
|
+
@permalinks = permalinks
|
38
|
+
@options = options
|
39
|
+
end
|
40
|
+
|
41
|
+
def fallbacks?
|
42
|
+
options[:fallbacks].present?
|
43
|
+
end
|
44
|
+
|
45
|
+
def exists?
|
46
|
+
find_permalink(I18n.locale).present?
|
47
|
+
end
|
48
|
+
|
49
|
+
def value
|
50
|
+
find_slug(I18n.locale)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def locale_column
|
56
|
+
@options[:locale_column]
|
57
|
+
end
|
58
|
+
|
59
|
+
def find_permalink(locale)
|
60
|
+
permalinks.find do |permalink|
|
61
|
+
permalink.send(locale_column) == locale.to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def find_fallback(locale)
|
66
|
+
fallbacks = I18n.try(:fallbacks) || {}
|
67
|
+
fallbacks = fallbacks.fetch(locale, [I18n.default_locale])
|
68
|
+
permalink = nil
|
69
|
+
|
70
|
+
fallbacks.find do |fallback|
|
71
|
+
permalink = find_permalink(fallback)
|
72
|
+
permalink.present?
|
73
|
+
end
|
74
|
+
|
75
|
+
permalink
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_slug(locale)
|
79
|
+
permalink = find_permalink(locale)
|
80
|
+
permalink = find_fallback(locale) if permalink.blank?
|
81
|
+
|
82
|
+
permalink.try(:slug)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -4,7 +4,9 @@ module ActivePermalink
|
|
4
4
|
|
5
5
|
default_scope { order created_at: :desc }
|
6
6
|
|
7
|
-
scope :global,
|
7
|
+
scope :global, -> { where scope: :global }
|
8
|
+
scope :active, -> { where active: true }
|
9
|
+
scope :inactive, -> { where active: false }
|
8
10
|
|
9
11
|
belongs_to :sluggable, polymorphic: true, optional: true
|
10
12
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ActivePermalink
|
2
|
+
module Persistence
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_validation do
|
7
|
+
self.slug = self[:slug]
|
8
|
+
end
|
9
|
+
|
10
|
+
after_update do
|
11
|
+
permalinks.reload
|
12
|
+
end
|
13
|
+
|
14
|
+
def slug=(value)
|
15
|
+
generator = Generator.new(self, permalink_options)
|
16
|
+
generator.generate(value)
|
17
|
+
|
18
|
+
self.permalinks = generator.permalinks
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -3,25 +3,20 @@ module ActivePermalink
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
class_methods do
|
6
|
-
def
|
7
|
-
|
6
|
+
def permalink_locator
|
7
|
+
PermalinkLocator.new(self, permalink_options)
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
10
|
+
def with_slug(*args)
|
11
|
+
permalink_locator.scope(*args)
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
method = raise_error ? :find_by! : :find_by
|
18
|
-
record = includes(:permalinks).send(method, permalinks: { slug: value })
|
19
|
-
|
20
|
-
unless record.nil?
|
21
|
-
record.found_by_slug = value
|
22
|
-
end
|
14
|
+
def find_by_slug(*args)
|
15
|
+
permalink_locator.locate(*args)
|
16
|
+
end
|
23
17
|
|
24
|
-
|
18
|
+
def find_by_slug!(*args)
|
19
|
+
permalink_locator.locate!(*args)
|
25
20
|
end
|
26
21
|
end
|
27
22
|
|
@@ -34,7 +29,7 @@ module ActivePermalink
|
|
34
29
|
end
|
35
30
|
|
36
31
|
def found_by_slug?
|
37
|
-
|
32
|
+
found_by_slug.present?
|
38
33
|
end
|
39
34
|
|
40
35
|
def needs_redirect?
|
@@ -44,5 +39,50 @@ module ActivePermalink
|
|
44
39
|
def old_slugs
|
45
40
|
@old_slugs ||= old_permalinks.pluck(:slug)
|
46
41
|
end
|
42
|
+
|
43
|
+
class PermalinkLocator
|
44
|
+
attr_reader :model, :options
|
45
|
+
|
46
|
+
def initialize(model, options)
|
47
|
+
@model = model
|
48
|
+
@options = options
|
49
|
+
end
|
50
|
+
|
51
|
+
def scope(value, locale: nil)
|
52
|
+
params = localize(slug: value, locale: locale)
|
53
|
+
model.joins(:permalinks).where(permalinks: params)
|
54
|
+
end
|
55
|
+
|
56
|
+
def locate(*args)
|
57
|
+
find_record(:find_by, *args)
|
58
|
+
end
|
59
|
+
|
60
|
+
def locate!(*args)
|
61
|
+
find_record(:find_by!, *args)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def localized?
|
67
|
+
options[:localized].present?
|
68
|
+
end
|
69
|
+
|
70
|
+
def locale_column
|
71
|
+
options[:locale_column]
|
72
|
+
end
|
73
|
+
|
74
|
+
def localize(locale: nil, **params)
|
75
|
+
params[locale_column] = (locale || I18n.locale) if localized?
|
76
|
+
params
|
77
|
+
end
|
78
|
+
|
79
|
+
def find_record(method, value, locale: nil)
|
80
|
+
params = localize(slug: value, locale: locale)
|
81
|
+
record = model.joins(:permalinks).send(method, permalinks: params)
|
82
|
+
|
83
|
+
record.found_by_slug = value if record.present?
|
84
|
+
record
|
85
|
+
end
|
86
|
+
end
|
47
87
|
end
|
48
88
|
end
|
metadata
CHANGED
@@ -1,29 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_permalink
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonian Guveli
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '5.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '7.0'
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
|
-
- - "
|
27
|
+
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '5.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '7.0'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: active_delegate
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +64,14 @@ dependencies:
|
|
58
64
|
requirements:
|
59
65
|
- - "~>"
|
60
66
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
67
|
+
version: '2.0'
|
62
68
|
type: :development
|
63
69
|
prerelease: false
|
64
70
|
version_requirements: !ruby/object:Gem::Requirement
|
65
71
|
requirements:
|
66
72
|
- - "~>"
|
67
73
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
74
|
+
version: '2.0'
|
69
75
|
- !ruby/object:Gem::Dependency
|
70
76
|
name: rake
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,7 +114,9 @@ files:
|
|
108
114
|
- lib/active_permalink.rb
|
109
115
|
- lib/active_permalink/generator.rb
|
110
116
|
- lib/active_permalink/loader.rb
|
117
|
+
- lib/active_permalink/localizer.rb
|
111
118
|
- lib/active_permalink/permalink.rb
|
119
|
+
- lib/active_permalink/persistence.rb
|
112
120
|
- lib/active_permalink/querying.rb
|
113
121
|
- lib/active_permalink/version.rb
|
114
122
|
- lib/generators/active_permalink/install_generator.rb
|
@@ -132,8 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
140
|
- !ruby/object:Gem::Version
|
133
141
|
version: '0'
|
134
142
|
requirements: []
|
135
|
-
|
136
|
-
rubygems_version: 2.7.7
|
143
|
+
rubygems_version: 3.0.6
|
137
144
|
signing_key:
|
138
145
|
specification_version: 4
|
139
146
|
summary: Add permalinks to ActiveRecord models
|