41 行
1.2 KiB
Ruby
41 行
1.2 KiB
Ruby
class PostImplication < ApplicationRecord
|
|
self.primary_key = :post_id, :parent_post_id
|
|
|
|
belongs_to :post, inverse_of: :parent_post_implications
|
|
belongs_to :parent_post, class_name: 'Post', inverse_of: :child_post_implications
|
|
|
|
validates :post_id, presence: true, uniqueness: { scope: :parent_post_id }
|
|
validates :parent_post_id, presence: true
|
|
|
|
validate :parent_post_mustnt_be_itself
|
|
validate :parent_post_mustnt_create_cycle
|
|
|
|
private
|
|
|
|
def parent_post_mustnt_be_itself
|
|
if parent_post_id == post_id
|
|
errors.add :parent_post_id, '親投稿に同じ投稿を設定することはできません.'
|
|
end
|
|
end
|
|
|
|
def parent_post_mustnt_create_cycle
|
|
return if post_id.blank? || parent_post_id.blank?
|
|
return if errors[:parent_post_id].present?
|
|
|
|
ancestor_ids = Set.new
|
|
frontier_ids = [parent_post_id]
|
|
|
|
until frontier_ids.empty?
|
|
if frontier_ids.include?(post_id)
|
|
errors.add :parent_post_id, :invalid
|
|
return
|
|
end
|
|
|
|
ancestor_ids.merge(frontier_ids)
|
|
frontier_ids = PostImplication.where(post_id: frontier_ids)
|
|
.distinct.pluck(:parent_post_id)
|
|
.reject { ancestor_ids.include?(_1) }
|
|
end
|
|
end
|
|
end
|