Techioz Blog

本を注文するための Ruby モデル スコープを作成する方法はありますか? (数字もアルファベットもなし)

概要

私は、本からの引用と、その引用についてのメモや感想を掲載するアプリを持っています。本の順序、章の順序、ページの順序の順に引用をリストしたいと思います。

ActiveRelation を維持するために、これをモデル内のスコープに移動する方法はありますか?

のように

class Quote
  scope :sorted, ->(order_of_books|book|) { where("reference_book = ?", book) }
end

私のコントローラーには、書籍の注文ごとに引用を並べ替える次のようなコードがあります。

# /app/controllers/quotes_controller.rb

def quotes
    @quotes = Quotes.all
    @sorted_quotes = []
        
    order_of_books.each do |book|
        @temp_array = []
        if @quotes.any? { |quote| quote[:reference_book] == book}
            @temp_array << @quotes.detect { |quote| quote[:reference_book] == book}
            # @temp_array.sort_by! { |quote| quote.reference_paragraph, quote.reference_sentence }
            @sorted_quotes << @temp_array
        end
    end
end

# /app/models/concerns/book_concern.rb

def order_of_books
   [ 
    "Book A",
    "Book B",
    "Book C",
   ]
end

参考用のデータベーステーブルです。

# db/schema.rb
create_table "quotes", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "text", null: false
    t.string "reference_book", null: false
    t.integer "reference_chapter", null: false
    t.integer "reference_paragraph", null: false
    t.integer "reference_sentence", null: false
    t.string "image"
    t.text "notes"
end

エラー

問題は、引用符を並べ替えようとしていることであり、ビュー内で quote.image のようなものを呼び出そうとすると、他のすべてのコードが壊れて、次のエラーが発生します。

問題は、引用符を並べ替えようとしていることであり、ビュー内で quote.image のようなものを呼び出そうとすると、他のすべてのコードが壊れて、次のエラーが発生します。

サイドノート

コントローラー内のsort_by!を実行しようとしている行です。段落と文が機能しないので、コメントアウトしました。今のところ、それは私にとってそれほど重要ではありません。

コントローラー内のsort_by!を実行しようとしている行です。段落と文が機能しないので、コメントアウトしました。今のところ、それは私にとってそれほど重要ではありません。

解決策

書籍ごとに複数の引用があると仮定すると (コードに新しい行を追加せずに、時間の経過とともにさらに書籍を追加することになります)、書籍テーブルを用意し、書籍の並べ替えフィールドを保存することで、データをもう少し適切に正規化することができます。本の好ましい並べ替え順序を取得するため (コードに直接組み込まれるのではなく)。

# models/book.rb
class Book < ApplicationRecord
  validates :sort, presence: true
end

# models/quote.rb
class Quote < ApplicationRecord
  belongs_to :book
end

# db/schema.rb
create_table "books", force: :cascade do |t|
    t.string "title", null: false
    t.string "author"
    t.integer "sort", null: false
end
create_table "quotes", force: :cascade do |t|
    t.string "text", null: false
    t.bigint "book_id", null: false # < new column
    t.integer "reference_chapter", null: false
    t.integer "reference_paragraph", null: false
    t.integer "reference_sentence", null: false
    t.string "image"
    t.text "notes"
    # TODO: you will also want a foreign key constraint here for quote.book_id
end

次に、このリレーションシップを使用して引用を並べ替え、複数の列を order メソッドに渡します。つまり、最初に book.sort で並べ替え、次に、reference_chapter (同じ書籍内のすべての引用について)、次に、reference_paragraph (同じ章内のすべての引用について) で並べ替えることができます。ベストプラクティスとして、同じ本+章+段落+文から複数の引用があった場合に備えて、最終的な曖昧さ回避として quotes.id を使用することをお勧めします。

# models/quote.rb
class Quote < ApplicationRecord
  scope :sorted, -> { joins(:book).order('books.sort ASC, reference_chapter ASC, reference_paragraph ASC, reference_sentence ASC, id ASC') }
end