ページネーションをkaminari、検索をransackに置き換え

This commit is contained in:
Rikuoh Tsujitani 2025-02-22 23:39:32 +09:00
parent 6ba87e4ee7
commit 50f2214021
Signed by: riq0h
GPG key ID: 010F09DEA298C717
15 changed files with 127 additions and 48 deletions

View file

@ -16,6 +16,9 @@ gem 'sqlite3', '>= 1.4'
gem 'solid_cache'
gem 'solid_queue'
gem 'kaminari'
gem 'ransack'
# Use the Puma web server [https://github.com/puma/puma]
gem 'puma', '>= 5.0'

View file

@ -120,6 +120,18 @@ GEM
jbuilder (2.13.0)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
kaminari (1.2.2)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.2)
kaminari-activerecord (= 1.2.2)
kaminari-core (= 1.2.2)
kaminari-actionview (1.2.2)
actionview
kaminari-core (= 1.2.2)
kaminari-activerecord (1.2.2)
activerecord
kaminari-core (= 1.2.2)
kaminari-core (1.2.2)
logger (1.6.6)
loofah (2.24.0)
crass (~> 1.0.2)
@ -212,6 +224,10 @@ GEM
thor (~> 1.0, >= 1.2.2)
zeitwerk (~> 2.6)
rake (13.2.1)
ransack (4.3.0)
activerecord (>= 6.1.5)
activesupport (>= 6.1.5)
i18n
rdoc (6.12.0)
psych (>= 4.0.0)
regexp_parser (2.10.0)
@ -305,9 +321,11 @@ DEPENDENCIES
debug
importmap-rails
jbuilder
kaminari
puma (>= 5.0)
rails (= 8.0.1)
rails-i18n
ransack
selenium-webdriver
solid_cache
solid_queue

View file

@ -2,13 +2,11 @@ class MemosController < ApplicationController
before_action :set_memo, only: %i[edit update destroy]
def index
page = (params[:page] || 0).to_i
@memos = Memo.search(params[:query])
.order(created_at: :desc)
.limit(4)
.offset(page * 4)
@has_next = Memo.search(params[:query]).count > (page + 1) * 4
@q = Memo.ransack(params[:q])
@memos = @q.result(distinct: true)
.order(created_at: :desc)
.page(params[:page])
.per(4)
respond_to do |format|
format.html

View file

@ -1,10 +0,0 @@
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
submit() {
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.element.requestSubmit();
}, 300);
}
}

View file

@ -1,11 +1,11 @@
class Memo < ApplicationRecord
validates :content, presence: true
def self.search(query)
if query.present?
where('content LIKE ?', "%#{query}%").order(created_at: :desc)
else
order(created_at: :desc)
end
def self.ransackable_attributes(_auth_object = nil)
%w[content created_at id updated_at]
end
def self.ransackable_associations(_auth_object = nil)
[]
end
end

View file

@ -0,0 +1,11 @@
<%# Link to the "First" page
- available local variables
url: url to the first page
current_page: a page object for the currently displayed page
total_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<span class="first">
<%= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote %>
</span>

View file

@ -0,0 +1,8 @@
<%# Non-link tag that stands for skipped pages...
- available local variables
current_page: a page object for the currently displayed page
total_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<span class="page gap"><%= t('views.pagination.truncate').html_safe %></span>

View file

@ -0,0 +1,11 @@
<%# Link to the "Last" page
- available local variables
url: url to the last page
current_page: a page object for the currently displayed page
total_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<span class="last">
<%= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote %>
</span>

View file

@ -0,0 +1,3 @@
<%= link_to_next_page @memos, "気力十分😤",
class: "inline-flex items-center px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white font-medium rounded-lg transition-colors duration-200",
data: { turbo_frame: "memos" } %>

View file

@ -0,0 +1,12 @@
<%# Link showing page number
- available local variables
page: a page object for "this" page
url: url to this page
current_page: a page object for the currently displayed page
total_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<span class="page<%= ' current' if page.current? %>">
<%= link_to_unless page.current?, page, url, {remote: remote, rel: page.rel} %>
</span>

View file

@ -0,0 +1,15 @@
<%= paginator.render do %>
<nav class="flex justify-center space-x-2">
<%= first_page_tag unless current_page.first? %>
<%= prev_page_tag unless current_page.first? %>
<% each_page do |page| %>
<% if page.display_tag? %>
<%= page_tag page %>
<% elsif !page.was_truncated? %>
<%= gap_tag %>
<% end %>
<% end %>
<%= next_page_tag unless current_page.last? %>
<%= last_page_tag unless current_page.last? %>
</nav>
<% end %>

View file

@ -0,0 +1,11 @@
<%# Link to the "Previous" page
- available local variables
url: url to the previous page
current_page: a page object for the currently displayed page
total_pages: total number of pages
per_page: number of items to fetch per page
remote: data-remote
-%>
<span class="prev">
<%= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote %>
</span>

View file

@ -1,37 +1,30 @@
<div class="mb-8 mt-8">
<div class="flex items-center gap-4">
<%= form_with url: memos_path, method: :get,
data: { turbo_frame: "search-results", controller: "search" } do |f| %>
<%= search_form_for @q, html: { data: { turbo_frame: "search-results", controller: "search" } } do |f| %>
<div class="relative">
<%= f.text_field :query,
<%= f.text_field :content_cont,
class: "w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500",
placeholder: "検索...",
data: { action: "input->search#submit" },
value: params[:query] %>
data: { action: "input->search#submit" } %>
</div>
<% end %>
<%= link_to new_memo_path, class: "bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-lg transition-colors duration-200" do %>
<span class="flex items-center">
</svg>
出力開始
</span>
<% end %>
</div>
</div>
<div id="memos">
<%= turbo_frame_tag "memos" do %>
<%= turbo_frame_tag "memos" do %>
<div id="memos-container" class="flex flex-col gap-4">
<%= render @memos %>
<%= render "empty_results", query: params[:query] if @memos.empty? %>
<%= render "empty_results", query: @q&.content_cont if @memos.empty? %>
</div>
<% end %>
<div id="load-more" class="text-center mt-8">
<% if @has_next %>
<%= link_to "気力十分😤",
memos_path(page: (params[:page] || 0).to_i + 1, query: params[:query]),
<div class="text-center mt-8">
<%= link_to_next_page @memos, "気力十分😤",
class: "inline-flex items-center px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white font-medium rounded-lg transition-colors duration-200",
data: { turbo_frame: "memos" } %>
<% end %>
</div>
</div>
</div>
<% end %>

View file

@ -1,11 +1,3 @@
<%= turbo_stream.append "memos-container" do %>
<%= render @memos %>
<% end %>
<div id="load-more" class="text-center mt-8">
<% if @has_next %>
<%= link_to "気力十分😤",
memos_path(page: (params[:page] || 0).to_i + 1, query: params[:query]),
class: "inline-flex items-center px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white font-medium rounded-lg transition-colors duration-200",
data: { turbo_frame: "memos" } %>
<% end %>
</div>

View file

@ -0,0 +1,14 @@
# frozen_string_literal: true
Kaminari.configure do |config|
# config.default_per_page = 25
# config.max_per_page = nil
# config.window = 4
# config.outer_window = 0
# config.left = 0
# config.right = 0
# config.page_method_name = :page
# config.param_name = :page
# config.max_pages = nil
# config.params_on_first_page = false
end