class Post < ApplicationRecord require 'mini_magick' belongs_to :uploaded_user, class_name: 'User', optional: true has_many :post_tags, dependent: :destroy, inverse_of: :post has_many :active_post_tags, -> { kept }, class_name: 'PostTag', inverse_of: :post has_many :post_tags_with_discarded, -> { with_discarded }, class_name: 'PostTag' has_many :tags, through: :active_post_tags has_many :user_post_views, dependent: :delete_all has_many :post_similarities, dependent: :delete_all has_many :post_versions has_many :parent_post_implications, class_name: 'PostImplication', foreign_key: :post_id, dependent: :destroy, inverse_of: :post has_many :parents, through: :parent_post_implications, source: :parent_post has_many :child_post_implications, class_name: 'PostImplication', foreign_key: :parent_post_id, dependent: :destroy, inverse_of: :parent_post has_many :children, through: :child_post_implications, source: :post has_one_attached :thumbnail before_validation :normalise_url validates :url, presence: true, uniqueness: true validate :validate_original_created_range validate :url_must_be_http_url def parent_posts = parents def child_posts = children def sibling_posts parent_post_ids = parent_posts.order(:id).pluck(:id) parent_post_ids.to_h { [_1, PostImplication.where(parent_post: _1).map(&:post)] } end def as_json options = { } super(options).merge(thumbnail: thumbnail.attached? ? Rails.application.routes.url_helpers.rails_blob_url( thumbnail, only_path: false) : nil) rescue super(options).merge(thumbnail: nil) end def snapshot_tag_names = tags.joins(:tag_name).order('tag_names.name').pluck('tag_names.name') def snapshot_parent_post_ids = parents.order(:parent_post_id).pluck(:parent_post_id) def related limit: nil ids = post_similarities.order(cos: :desc) ids = ids.limit(limit) if limit ids = ids.pluck(:target_post_id) return Post.none if ids.empty? Post.where(id: ids) .with_attached_thumbnail .order(Arel.sql("FIELD(posts.id, #{ ids.join(',') })")) end def resized_thumbnail! return unless thumbnail.attached? image = MiniMagick::Image.read(thumbnail.download) image.resize '180x180' thumbnail.purge thumbnail.attach(io: File.open(image.path), filename: 'resized_thumbnail.jpg', content_type: 'image/jpeg') end private def validate_original_created_range f = original_created_from b = original_created_before return if f.blank? || b.blank? f = Time.zone.parse(f) if String === f b = Time.zone.parse(b) if String === b return if !(f) || !(b) if f >= b errors.add :original_created_before, 'オリジナルの作成日時の順番がをかしぃです.' end end def url_must_be_http_url begin u = URI.parse(url) rescue URI::InvalidURIError errors.add(:url, 'URL が不正です.') return end if !(u in URI::HTTP) || u.host.blank? errors.add(:url, 'URL が不正です.') return end end def normalise_url return if url.blank? self.url = url.strip u = URI.parse(url) return unless u in URI::HTTP u.host = u.host.downcase if u.host u.path = u.path.sub(/\/\Z/, '') if u.path.present? self.url = u.to_s rescue URI::InvalidURIError ; end end