はじめに
学習用のメモとして投稿します。
先日RealWorld という OSS のプロジェクトで、APIのエンドポイントを実装する機会がありました。
そのAPIスペックに、スラッグの使用が含まれていたので、どのように実装したかについて書いていきます。
APIスペック
RealWorldでは、ブログ投稿プラットフォームを作っていきます。
多くのエンドポイントがありますが、今回はスラッグに関する部分のみに絞ります。
①記事の作成
-
リクエスト
GET /api/articles/:slug
-
レスポンス
{
"article": {
"slug": "how-to-train-your-dragon",
"title": "How to train your dragon",
"description": "Ever wonder how?",
"body": "It takes a Jacobian",
"tagList": ["dragons", "training"],
"createdAt": "2016-02-18T03:22:56.637Z",
"updatedAt": "2016-02-18T03:48:35.824Z",
"favorited": false,
"favoritesCount": 0,
"author": {
"username": "jake",
"bio": "I work at statefarm",
"image": "https://i.stack.imgur.com/xHWG8.jpg",
"following": false
}
}
}
②記事の投稿
- リクエスト
POST /api/articles
// リクエストボディ例
{
"article": {
"title": "How to train your dragon",
"description": "Ever wonder how?",
"body": "You have to believe",
"tagList": ["reactjs", "angularjs", "dragons"]
}
}
- レスポンス
{
"article": {
"slug": "how-to-train-your-dragon",
"title": "How to train your dragon",
"description": "Ever wonder how?",
"body": "You have to believe",
"tagList": ["reactjs", "angularjs", "dragons"],
"createdAt": "2016-02-18T03:22:56.637Z",
"updatedAt": "2016-02-18T03:48:35.824Z",
"favorited": false,
"favoritesCount": 0,
"author": {
"username": "jake",
"bio": "I work at statefarm",
"image": "https://i.stack.imgur.com/xHWG8.jpg",
"following": false
}
}
}
実装: マイグレーション
GET /api/articles/:slug
でスラッグは記事特定に使用されているため、データベースに保存する必要があります。
また、レスポンスの内容を見ると、スラッグはタイトルをベースにした内容になっています。
そうすると、①スラッグはuniqueである必要があり、②スラッグのベースとなるタイトルもuniqueである必要があります。
class CreateArticles < ActiveRecord::Migration[7.0]
def change
create_table :articles do |t|
t.string :slug, null: false, unique: true
t.string :title, null: false, unique: true
# ... 略
実装: モデル
POST /api/articles
でリクエストボディにスラッグは含まれないため、こちらで作成する必要があります。そこで、タイトルからスラッグを作成するメソッドを作成し、データベースに保存する前に呼び出すようにします。スラッグの作成には色々な方法が考えられますが、今回のAPIスペックを満たすためには、rails6で追加されたparameterizeメソッドで実装できそうだったので、これを使用しました。
また、URLでidではなく、スラッグを使用するために、to_paramメソッドをオーバーライドします。
class Article < ApplicationRecord
before_save :generate_slug
validates :title, presence: true, uniqueness: true
def generate_slug
self.slug = self.title.parameterize if title.present?
end
def to_param
slug
end
# ... 略
実装: コントローラー
記事の作成に成功すれば、データベースには、uniqueなスラッグが書き込まれているはずです。
これでスラッグを条件にしてデータが取得できるようになります。
@article = Article.find_by(slug: params[:slug])
参考にした記事