自作ブログにパーマリンク(任意のURL)を設定できるようにしたので、そのメモ書きです。
以前は、記事を投稿するとURLがhttps://yamatabi.jp/posts/11
のように、投稿した記事のIDがそのままURLになってしまっていました。
それでもいいんですが、URLがIDだと検索エンジン側から見たら「その記事がどんな記事か」がわからない(SEO的にも良くない?)ですし、何より僕が気になってしょうがないw
やはり、記事ごとに固有のURLを設定できた方が見栄えがいいじゃないですかw
ということで、今回はhttps://yamatabi.jp/posts/11
のようなURLからhttps://yamatabi.jp/hokkaido-trip-day-1
のような独自のURLを設定できるようにしました。
パーマリンクを設定できるようにするまでの流れ
パーマリンク保存用のカラム作成
パーマリンクを保存するためのカラムpermalink
を追加します。
$ rails g migration add_permalink_to_posts permalink:string
作成されたマイグレーションファイルを確認。
class AddPermalinkToPosts < ActiveRecord::Migration[7.0]
def change
add_column :posts, :permalink, :string
end
end
マイグレーションを実行してカラムを追加します。
$ rails db:migrate
ルーティングの設定
パーマリンク設定前は以下のようなルーティング設定にしていました。(draftは下書き保存用のルーティング設定)
resources :posts do
collection do
get "draft"
end
end
各アクションのルーティングはこちら↓
draft_posts GET /posts/draft(.:format) posts#draft
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
これを、以下のように書き換えます↓
resources :posts, only: [:index, :new] do
collection do
get "draft"
end
end
get ":permalink", to: "posts#show", as: "post"
post ":permalink", to: "posts#create"
get ":permalink/edit", to: "posts#edit", as: "edit_post"
patch ":permalink", to: "posts#update"
put ":permalink", to: "posts#update"
delete ":permalink", to: "posts#destroy"
書き換えた後のルーティングです↓
draft_posts GET /posts/draft(.:format) posts#draft
posts GET /posts(.:format) posts#index
new_post GET /posts/new(.:format) posts#new
post GET /:permalink(.:format) posts#show
POST /:permalink(.:format) posts#create
edit_post GET /:permalink/edit(.:format) posts#edit
PATCH /:permalink(.:format) posts#update
PUT /:permalink(.:format) posts#update
DELETE /:permalink(.:format) posts#destroy
index
およびnew
アクションについてはパーマリンクを設定する必要がないのでそのままにしています。
ただ、このままだとパーマリンクの設定をしてもパーマリンクのURLにアクセスできないため、モデルファイルに次のような設定をします。
URLにパーマリンクを表示させるためのメソッドを追加(post.rb)
モデルファイルpost.rb
に以下を追記します。
class Post < ApplicationRecord
...
def to_param
permalink
end
end
これで、設定したパーマリンクにアクセスできるようになります。
パーマリンク入力フォームの追加
パーマリンク用の入力フォームを追加します↓
<%= form_with(model: post) do |form| %>
......
<!-- パーマリンク -->
<div class="my-3">
<%= form.label :permalink, for: "postPermalinkInput", class: "form-label fw-bold" %>
<%= form.text_field :permalink, class: "form-control", id: "postPermalinkInput" %>
</div>
......
<% end %>
これでパーマリンクを入力、保存できるようになりました。
パーマリンクを保存後、投稿した記事にアクセスすると設定したパーマリンクがURLに表示されているはずです。
ただ、現時点ではパーマリンクの文字種類に制限がなかったり、同一のパーマリンクを入力できてしまうため、この辺のバリデーションも実装する必要があります。
(Postモデルでバリデーションかけてもいいのですが、僕はリアルタイムでバリデーションチェックがしたかったのでJavaScriptで実装しました)
バリデーションについてはまた別記事で紹介します。
パーマリンクが未入力の場合の対処(適当なパーマリンクを自動生成)
先ほどのフォームで、パーマリンクを未入力にしたまま保存してしまうことを想定し、パーマリンクが未入力でも適当なパーマリンクを自動生成、割り当てするようにします。
post.rb
に以下の内容を追記します↓
class Post < ApplicationRecord
...
before_create :set_post_permalink # ←追記
def to_param
permalink
end
# ↓追記
private
# 初期のパーマリンクを生成する(パーマリンクを指定しなかった場合)
def set_post_permalink
while self.permalink.blank? || Post.find_by(permalink: self.permalink).present? do
self.permalink = "post-#{rand(99999999)}"
end
end
end
パーマリンクの文字列はなんでもいいですが、他の投稿と被らないようにするためにパーマリンクの文字列をランダムにし、かつwhile文でデータベース上に同一のパーマリンクが存在しないかチェックしています(生成したパーマリンクと同一のものがなければそのまま保存する)。
以上です。
開発環境
- Ruby 3.1.2
- Ruby on Rails 7.0.4.3
- Bootstrap 5.2.3
- M1 Macbook Air 2020
- mac OS Monterey (ver. 12.4)
コメント