Rails: 階層構造のリソースで子リソースのIDを連番にしたい

  • 3
    いいね
  • 0
    コメント

Railsではルーティングでリソースを階層構造にできますが、子リソースのIDは子リソース全体の連番になってしまい、URLにしたときかっこ良くないことがあります。

こうではなく
/questions/3 ... 質問のURL
/questions/3/answers/100 ... 質問3への回答の詳細URL
/questions/3/answers/123 ... 同上
/questions/3/answers/145 ... 同上
こうしたい
/questions/3 ... 質問のURL
/questions/3/answers/1 ... 質問3への回答の詳細URL
/questions/3/answers/2 ... 同上
/questions/3/answers/3 ... 同上

いろいろ調べましたが、sequencedというgemで手っ取り早く解決できるようです。

sequencedのインストール

Gemfile
gem 'sequenced'
$ bundle install

モデルを作る

連番をつけたいモデルにsequential_idカラムを追加し、DBをマイグレーションします。例えば、Questionに複数のAnswerがつく場合、Answerにsequential_idを追加します。

$ rails generate model Question
$ rails generate model Answer question:references sequential_id:integer
db/migrate/20160903082623_create_answers.rb
class CreateAnswers < ActiveRecord::Migration
  def change
    create_table :answers do |t|
      # null: falseを追加
      t.references :question, index: true, foreign_key: true, null: false

      # null: falseを追加
      t.integer :sequential_id, null: false

      t.timestamps null: false
    end
    # 複合ユニーク制約
    add_index :answers, [:question_id, :sequential_id], unique: true
  end
end
$ rake db:migrate

Answerモデルにacts_as_sequencedを追加します。

app/models/answer.rb
class Answer < ActiveRecord::Base
  belongs_to :question

  # この行を追加
  acts_as_sequenced scope: :question_id
end

これで、AnswerはQuestionごとに連番になります。

参考: Rails: sequencedでネストしたリソースのIDを連番にする