#59 関聯投稿一覧の追加

This commit is contained in:
2025-08-01 01:06:09 +09:00
parent 0f902f0d27
commit efb6b16412
4 changed files with 31 additions and 5 deletions
+4 -4
View File
@@ -5,16 +5,16 @@ require 'nokogiri'
class PostsController < ApplicationController
# GET /posts
def index
limit = (params[:limit] || 20).to_i
limit = params[:limit].presence&.to_i
cursor = params[:cursor].presence
q = filtered_posts.order(created_at: :desc)
q = q.where('posts.created_at < ?', Time.iso8601(cursor)) if cursor
posts = q.limit(limit + 1)
posts = limit ? q.limit(limit + 1) : q
next_cursor = nil
if posts.size > limit
if limit && posts.size > limit
next_cursor = posts.last.created_at.iso8601(6)
posts = posts.first(limit)
end
@@ -51,7 +51,7 @@ class PostsController < ApplicationController
render json: (post
.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } })
.merge(viewed: viewed))
.merge(related: post.related(limit: 20), viewed:))
end
# POST /posts
+21
View File
@@ -7,6 +7,12 @@ class Post < ApplicationRecord
has_many :post_tags, dependent: :destroy
has_many :tags, through: :post_tags
has_many :user_post_views, dependent: :destroy
has_many :post_similarities_as_post,
class_name: 'PostSimilarity',
foreign_key: :post_id
has_many :post_similarities_as_target_post,
class_name: 'PostSimilarity',
foreign_key: :target_post_id
has_one_attached :thumbnail
def as_json options = { }
@@ -18,6 +24,21 @@ class Post < ApplicationRecord
super(options).merge(thumbnail: nil)
end
def related(limit: nil)
ids_with_cos =
post_similarities_as_post.select(:target_post_id, :cos)
.map { |ps| [ps.target_post_id, ps.cos] } +
post_similarities_as_target_post.select(:post_id, :cos)
.map { |ps| [ps.post_id, ps.cos] }
sorted = ids_with_cos.sort_by { |_, cos| -cos }
ids = sorted.map(&:first)
ids = ids.first(limit) if limit
Post.where(id: ids)
end
def resized_thumbnail!
return unless thumbnail.attached?
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react'
import { Helmet } from 'react-helmet-async'
import { useParams } from 'react-router-dom'
import PostList from '@/components/PostList'
import TagDetailSidebar from '@/components/TagDetailSidebar'
import NicoViewer from '@/components/NicoViewer'
import PostEditForm from '@/components/PostEditForm'
@@ -117,6 +118,9 @@ export default ({ user }: Props) => {
{post.viewed ? '閲覧済' : '未閲覧'}
</Button>
<TabGroup>
<Tab name="関聯">
<PostList posts={post.related} />
</Tab>
{(['admin', 'member'].some (r => user?.role === r) && editing) && (
<Tab name="編輯">
<PostEditForm post={post}
+2 -1
View File
@@ -23,7 +23,8 @@ export type Post = {
thumbnail: string
thumbnailBase: string
tags: Tag[]
viewed: boolean }
viewed: boolean
related: Post[] }
export type SubMenuItem = {
component: React.ReactNode