Skip to content

Commit 1d62daf

Browse files
committed
Add permalink to article
1 parent bd046ae commit 1d62daf

File tree

7 files changed

+127
-3
lines changed

7 files changed

+127
-3
lines changed

app/controllers/articles_controller.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ def destroy
4242
private
4343

4444
def set_article
45-
@article = Article.find(params[:id])
45+
@article = Article.find_by!(permalink: params[:id])
4646
end
4747

4848
def article_params
49-
params.require(:article).permit(:title, :content, :category_id)
49+
params
50+
.require(:article)
51+
.permit(:title, :content, :category_id, :regenerate_permalink)
5052
end
5153
end

app/models/article.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,33 @@ class Article < ApplicationRecord
22
belongs_to :category
33

44
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]
11+
12+
if count > 0
13+
new_permalink += "-#{count}"
14+
end
15+
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
28+
29+
def set_permalink
30+
if regenerate_permalink.to_i > 0 || (new_record? && !permalink?)
31+
self.permalink = generate_permalink
32+
end
33+
end
534
end

app/views/articles/_form.html.erb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,11 @@
1111

1212
<p><%= f.text_area :content, placeholder: "Content" %></p>
1313
<p><%= f.collection_select :category_id, Category.all, :id, :name %></p>
14+
<% if f.object.persisted? %>
15+
<p>
16+
<%= f.check_box :regenerate_permalink %>
17+
<%= f.label :regenerate_permalink %>
18+
</p>
19+
<% end %>
1420
<p><%= f.submit "Save" %></p>
1521
<% end %>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class AddPermalinkToArticle < ActiveRecord::Migration[6.0]
2+
def change
3+
add_column :articles, :permalink, :string
4+
add_index :articles, :permalink
5+
end
6+
end

db/schema.rb

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

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

1515
create_table "articles", force: :cascade do |t|
1616
t.string "title"
1717
t.text "content"
1818
t.integer "category_id", null: false
1919
t.datetime "created_at", precision: 6, null: false
2020
t.datetime "updated_at", precision: 6, null: false
21+
t.string "permalink"
2122
t.index ["category_id"], name: "index_articles_on_category_id"
23+
t.index ["permalink"], name: "index_articles_on_permalink"
2224
end
2325

2426
create_table "categories", force: :cascade do |t|
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
require 'rails_helper'
2+
3+
RSpec.describe ArticlesController do
4+
describe "#show" do
5+
before do
6+
FactoryBot.create(:article, permalink: "my-permalink")
7+
end
8+
9+
it "renders successfully" do
10+
get :show, params: { id: "my-permalink" }
11+
12+
expect(response.status).to eql(200)
13+
end
14+
15+
context "without correct permalink" do
16+
subject(:perform_request) {
17+
get :show, params: { id: "wrong-permalink" }
18+
}
19+
20+
it "raises error" do
21+
expect { perform_request }
22+
.to raise_error(ActiveRecord::RecordNotFound)
23+
end
24+
end
25+
end
26+
end

spec/models/article_spec.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
require 'rails_helper'
2+
3+
RSpec.describe Article do
4+
describe "#generate_permalink" do
5+
subject { article.generate_permalink }
6+
7+
let(:article) {
8+
FactoryBot.build_stubbed(:article, title: "Hello world!")
9+
}
10+
11+
it { is_expected.to eql("hello-world") }
12+
13+
context "with a very long title" do
14+
let(:article) {
15+
FactoryBot.build_stubbed(:article, title: "x" * 200)
16+
}
17+
18+
it { is_expected.to eql("x" * 50) }
19+
end
20+
21+
context "with existing article having the same title" do
22+
before do
23+
FactoryBot.create(:article, title: "Hello world!")
24+
end
25+
26+
it { is_expected.to eql("hello-world-1") }
27+
end
28+
29+
context "with multiple existing articles having the same title" do
30+
before do
31+
FactoryBot.create_list(:article, 3, title: "Hello world!")
32+
end
33+
34+
it { is_expected.to eql("hello-world-3") }
35+
end
36+
end
37+
38+
describe "#save" do
39+
subject(:save) { article.save }
40+
41+
let(:article) { FactoryBot.build(:article) }
42+
43+
before do
44+
allow(article)
45+
.to receive(:generate_permalink).and_return("my-permalink")
46+
end
47+
48+
it "sets permalink" do
49+
expect { save }
50+
.to change { article.permalink }.to("my-permalink")
51+
end
52+
end
53+
end

0 commit comments

Comments
 (0)