Skip to content

Commit bebb7a8

Browse files
committed
Add permalink to categories and scope articles
1 parent 91d813f commit bebb7a8

File tree

9 files changed

+101
-34
lines changed

9 files changed

+101
-34
lines changed

app/controllers/articles_controller.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@ def destroy
4444
private
4545

4646
def set_article
47-
@article = Article.find_by!(permalink: params[:id])
47+
@article = Article.find_by!(permalink: params[:id], category_id: category)
48+
end
49+
50+
def category
51+
Category.find_by(permalink: params[:category_id])
4852
end
4953

5054
def article_params

app/models/article.rb

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,9 @@
11
class Article < ApplicationRecord
2-
belongs_to :category
3-
4-
validates :title, :content, :category, presence: true
5-
6-
attr_accessor :regenerate_permalink
7-
before_save :set_permalink
8-
9-
def generate_permalink(count = 0)
10-
new_permalink = title.parameterize[0..49]
2+
include Permalinkable
113

12-
if count > 0
13-
new_permalink += "-#{count}"
14-
end
4+
self.permalink_scope = "category_id"
155

16-
if Article.where.not(id: id).find_by(permalink: new_permalink)
17-
new_permalink = generate_permalink(count + 1)
18-
end
19-
20-
new_permalink
21-
end
22-
23-
def to_param
24-
permalink
25-
end
26-
27-
private
6+
belongs_to :category
287

29-
def set_permalink
30-
if regenerate_permalink.to_i > 0 || (new_record? && !permalink?)
31-
self.permalink = generate_permalink
32-
end
33-
end
8+
validates :title, :content, :category, presence: true
349
end

app/models/category.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
class Category < ApplicationRecord
2+
include Permalinkable
3+
4+
self.permalink_column = "name"
25
end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module Permalinkable
2+
extend ActiveSupport::Concern
3+
4+
included do
5+
cattr_accessor :permalink_column, default: "title"
6+
cattr_accessor :permalink_scope
7+
attr_accessor :regenerate_permalink
8+
before_save :set_permalink
9+
end
10+
11+
def generate_permalink(count = 0)
12+
column_value = attributes.fetch(self.class.permalink_column)
13+
new_permalink = column_value.parameterize[0..49]
14+
15+
if count > 0
16+
new_permalink += "-#{count}"
17+
end
18+
19+
if scoped_permalink_entries.find_by(permalink: new_permalink)
20+
new_permalink = generate_permalink(count + 1)
21+
end
22+
23+
new_permalink
24+
end
25+
26+
def to_param
27+
permalink
28+
end
29+
30+
private
31+
32+
def scoped_permalink_entries
33+
context = attributes.slice(self.class.permalink_scope)
34+
self.class.where(context).where.not(id: id)
35+
end
36+
37+
def set_permalink
38+
if regenerate_permalink.to_i > 0 || (new_record? && !permalink?)
39+
self.permalink = generate_permalink
40+
end
41+
end
42+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class AddPermalinkToCategories < ActiveRecord::Migration[6.0]
2+
def change
3+
add_column :categories, :permalink, :string
4+
add_index :categories, :permalink
5+
end
6+
end

db/schema.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema.define(version: 2019_09_17_195150) do
13+
ActiveRecord::Schema.define(version: 2019_10_01_191142) do
1414

1515
create_table "articles", force: :cascade do |t|
1616
t.string "title"
@@ -27,6 +27,8 @@
2727
t.string "name"
2828
t.datetime "created_at", precision: 6, null: false
2929
t.datetime "updated_at", precision: 6, null: false
30+
t.string "permalink"
31+
t.index ["permalink"], name: "index_categories_on_permalink"
3032
end
3133

3234
add_foreign_key "articles", "categories"

spec/controllers/articles_controller_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@
1414
expect(response.status).to eql(200)
1515
end
1616

17+
context "without correct category" do
18+
subject(:perform_request) {
19+
get :show, params: { id: "my-permalink", category_id: other_category }
20+
}
21+
22+
let(:other_category) { FactoryBot.create(:category) }
23+
24+
it "raises error" do
25+
expect { perform_request }
26+
.to raise_error(ActiveRecord::RecordNotFound)
27+
end
28+
end
29+
1730
context "without correct permalink" do
1831
subject(:perform_request) {
1932
get :show, params: { id: "wrong-permalink", category_id: category }

spec/models/article_spec.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
describe "#generate_permalink" do
55
subject { article.generate_permalink }
66

7+
let(:category) { FactoryBot.create(:category) }
78
let(:article) {
8-
FactoryBot.build_stubbed(:article, title: "Hello world!")
9+
FactoryBot.build(:article, title: "Hello world!", category: category)
910
}
1011

1112
it { is_expected.to eql("hello-world") }
@@ -20,15 +21,23 @@
2021

2122
context "with existing article having the same title" do
2223
before do
23-
FactoryBot.create(:article, title: "Hello world!")
24+
FactoryBot.create(:article, title: "Hello world!", category: category)
2425
end
2526

2627
it { is_expected.to eql("hello-world-1") }
2728
end
2829

30+
context "with existing article having the same title and different category" do
31+
before do
32+
FactoryBot.create(:article, title: "Hello world!")
33+
end
34+
35+
it { is_expected.to eql("hello-world") }
36+
end
37+
2938
context "with multiple existing articles having the same title" do
3039
before do
31-
FactoryBot.create_list(:article, 3, title: "Hello world!")
40+
FactoryBot.create_list(:article, 3, title: "Hello world!", category: category)
3241
end
3342

3443
it { is_expected.to eql("hello-world-3") }

spec/models/category_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
require 'rails_helper'
2+
3+
RSpec.describe Category do
4+
describe "#save" do
5+
subject(:save) { category.save }
6+
7+
let(:category) { FactoryBot.build(:category, name: "Politics!") }
8+
9+
it "sets a permalink" do
10+
expect { save }.to change { category.permalink }.to("politics")
11+
end
12+
end
13+
end

0 commit comments

Comments
 (0)