はじめに
学習用のメモとして投稿します。
先日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])
参考にした記事