Rails에서 "관련"게시물에 대한 모델 생성

내 페이지에 관련 게시물로 연결되는 섹션을 만들고 싶었습니다. 한 가지 제안은 추가 테이블을 만들고 관련 게시물의 fromto ID를 저장하는 것이었습니다.
rails g model post title content

먼저 우리는 우리의 모델을 원합니다. 그것에 대해 특별한 것은 없고 단지 예제 Post 클래스입니다.

다음으로 관련 게시물을 연결할 클래스가 필요합니다.
rails g model post_connection from_post:references to_post:references

여기에 내 마이그레이션 파일이 있습니다. 중복 레코드를 피하기 위해 Post -> Post의 각 조합당 하나의 PostConnection만 있을 수 있도록 두 ID에 인덱스도 추가하고 있습니다.
class CreatePostConnections < ActiveRecord::Migration[7.0]
  def change
    create_table :post_connections do |t|
      t.references :from_post
      t.references :to_post

      t.index [:from_post_id, :to_post_id], unique: true

      t.timestamps
    end
  end
end

이제 사용자가 게시물 자체를 연관시킬 수 없도록 하고 싶습니다. 따라서 사용 가능한 유일한 연결은 p1 -> p2 및 p2 -> p1입니다. 이 p1 -> p1 연결은 중복됩니다.
class PostConnection < ApplicationRecord
  belongs_to :from_post, class_name: 'Post'
  belongs_to :to_post, class_name: 'Post'

  validate :connection_uniqueness
  validates :from_post_id, uniqueness: { scope: [:to_post_id, :from_post_id], message: 'this connection already exists' }

  def connection_uniqueness
    if self.from_post_id == self.to_post_id
      errors.add(:post_connection, 'must be between two different posts')
    end
  end
end

Post 측에서는 특정 연결에 액세스할 수 있는지 확인해야 합니다. 종속: :destroy를 사용하면 게시물이 파괴될 때마다 연결도 파괴됩니다.
class Post < ApplicationRecord
  has_many :from_posts, foreign_key: :from_post_id, class_name: 'PostConnection', dependent: :destroy
  has_many :to_posts, foreign_key: :to_post_id, class_name: 'PostConnection', dependent: :destroy

  def post_connections
    from_posts.or(to_posts)
  end
end

이제 이것이 실제로 작동하는 것을 봅시다.
p1 = Post.create(title: "First Post")
=>
#<Post:0x00000001105b6d08                                                                    
 id: 1,                                                                                      
 title: "First Post",                                                                        
 ... >   
p2 = Post.create(title: "Second Post")
=>
#<Post:0x0000000110245d18                        
 id: 2,                                          
 title: "Second Post",                                                            
 ... >

게시물을 추가하면 이제 게시물 간의 연결을 만들 수 있습니다.
pc1 = PostConnection.create!(from_post: p1, to_post: p2)
pc1
=> 
#<PostConnection:0x00000001377a7988              
 id: 1,                                          
 from_post_id: 1,                                
 to_post_id: 2,                                  
 ... >

좋아, 우리는 우리의 연결이 있습니다! 이제 정확히 동일한 연결을 다시 추가하려고 하면 어떻게 되는지 살펴보겠습니다.
pc1 = PostConnection.create!(from_post: p1, to_post: p2)

Validation failed: From post this connection already exists (ActiveRecord::RecordInvalid)

훌륭합니다. 유효성 검사가 작동하고 PostConnection에 추가된 사용자 지정 유효성 검사를 다시 확인하기 위해 동일한 Post와의 연결을 할당해 볼 수 있습니다.
pc1 = PostConnection.create!(from_post: p1, to_post: p1)

Validation failed: Post connection must be between two different posts (ActiveRecord::RecordInvalid)  

멋진 사용자 지정 유효성 검사가 예상대로 작동합니다!

다른 방향으로 연결을 만들고 게시물에 대한 모든 연결을 찾아봅시다.
pc2 = PostConnection.create!(from_post: p2, to_post: p1)
pc2
=> 
#<PostConnection:0x0000000116fc2800                                                      
 id: 2,                                                                                  
 from_post_id: 2,                                                                        
 to_post_id: 1,                                                                          
 ... >

p1.post_connections
=>                                                             
[#<PostConnection:0x00000001132d4790                           
  id: 1,                                                       
  from_post_id: 1,                                             
  to_post_id: 2,                                               
  ... >, 
 #<PostConnection:0x00000001132d4650                           
  id: 2,                                                       
  from_post_id: 2,                                             
  to_post_id: 1,                                               
  ... >] 

예, 이제 모든 연결에 액세스할 수 있습니다! 또한 특정 연결을 사용하여 특정 게시물에 대한 PostConnections의 한 부분에만 액세스할 수 있습니다. 예를 들어 from_posts만 선택하여 이 게시물에서 직접 생성된 연결을 확인할 수 있습니다.
p1.from_posts
=>
[#<PostConnection:0x0000000113064e38                           
  id: 1,                                                       
  from_post_id: 1,                                             
  to_post_id: 2,                                               
  ... >] 

알았어요! 아마도 수행할 수 있는 한 가지는 필터링에 그다지 효율적이지 않은 OR 문을 사용하므로 post_connections를 호출할 때 쿼리 최적화입니다. 이를 개선하기 위한 제안 사항이 있으면 알려주세요. 도움이 되기를 바랍니다.

좋은 웹페이지 즐겨찾기