tadyjp/rendezvous

View on GitHub
app/models/post.rb

Summary

Maintainability
A
0 mins
Test Coverage
# == Schema Information
#
# Table name: posts
#
#  id             :integer          not null, primary key
#  title          :string(255)
#  body           :text
#  author_id      :integer
#  created_at     :datetime
#  updated_at     :datetime
#  is_draft       :boolean          default(FALSE)
#  specified_date :date
#
#    specified_dateは特定の日付を指定したい場合に使用

require 'date'

class Post < ActiveRecord::Base
  include HipchatIntegration if Settings.respond_to?(:hipchat)

  # for versioning
  has_paper_trail

  ######################################################################
  # Associations
  ######################################################################
  has_many :post_tags
  has_many :tags, through: :post_tags
  belongs_to :author, class_name: 'User'
  has_many :comments
  has_many :footprints

  has_many :watches, as: :watchable, dependent: :destroy
  has_many :watchers, through: :watches

  ######################################################################
  # Validations
  ######################################################################
  validates :title, presence: true
  validates :body, presence: true

  ######################################################################
  # Callback
  ######################################################################
  after_save :set_watcher!
  after_save :notify_watchers!
  after_create :notify_hipchat! if Settings.hipchat.token.present? && Settings.hipchat.room.present?

  ######################################################################
  # Named scope
  ######################################################################
  scope :search, (lambda do |query|
    where_list = includes(:author, :tags).order(updated_at: :desc)

    # Convert spaces to one space.
    query_list = query.split(/[\s ]+/)

    query_list.each do |where_query|
      case where_query
      when /\Aid:(.+)/
        where_list = where_list.where(id: Regexp.last_match[1])
      when /\Atitle:(.+)/
        where_list = where_list.where('posts.title LIKE ?', "%#{Regexp.last_match[1]}%")
      when /\Abody:(.+)/
        where_list = where_list.where('posts.body LIKE ?', "%#{Regexp.last_match[1]}%")
      when /\A@(.+)/
        where_list = where_list.where(users: { nickname: Regexp.last_match[1] })
      when /\A#(.+)/
        where_list = where_list.where(tags: { name: Regexp.last_match[1] })
      when /\Adate:(\d+)-(\d+)-(\d+)/
        date = Time.new(Regexp.last_match[1], Regexp.last_match[2], Regexp.last_match[3])
        where_list = where_list.where('posts.updated_at > ? AND posts.updated_at < ?', date, date + 1.day)
      when /\Adraft:1/
        where_list = where_list.where(is_draft: true)
      else
        where_list = where_list.where('posts.title LIKE ? OR posts.body LIKE ?', "%#{where_query}%", "%#{where_query}%")
      end
    end

    where_list
  end)

  scope :recent, (lambda do |limit = 10|
    order(updated_at: :desc).limit(limit)
  end)

  scope :today, -> { where(arel_table[:updated_at].gt 1.day.ago) }
  scope :this_month, -> { where(arel_table[:updated_at].gt 1.month.ago) }
  scope :last_month, -> { where(arel_table[:updated_at].gt 2.months.ago).where(arel_table[:updated_at].lt 1.month.ago) }

  ######################################################################
  # Class method
  ######################################################################
  def self.most_pv_in_this_week(limit)
    posts_with_footprints = where(arel_table[:created_at].gt 1.week.ago)
                            .select('posts.id, count(footprints.id) AS footprints_count')
                            .joins(:footprints)
                            .group('posts.id')
                            .order('footprints_count DESC')
                            .limit(limit)
    posts = find(posts_with_footprints.map(&:id))
    posts.to_a.zip posts_with_footprints.map(&:footprints_count)
  end

  ######################################################################
  # Instance method
  ######################################################################

  # generate forked post (not saved)
  def generate_fork(user)
    # `id`以外をコピーする
    forked_post = Post.new(attributes.except('id'))

    # `%name`をユーザー名に置換
    forked_post.title = forked_post.title.gsub(/%name/, user.name)
    # `%Y`などを日付に変換
    forked_post.title = Time.now.strftime(forked_post.title) # TODO
    forked_post.title = forked_post.title

    forked_post.tag_ids = tag_ids
    forked_post.author = user
    forked_post.specified_date = Date.today

    forked_post
  end

  # slideshow用のbody
  def body_for_slideshow
    body.gsub(/^#/, "---\n\n#")
  end

  def visited_user_count
    footprints.select(:user_id).uniq.count
  end

  # FIXME: 正常に動作しないため動作しないため一時的にメソッドを作成
  #   has_many :watchers, :through => :watches
  #
  # def watchers
  #   watches.map { |watch| watch.watcher }
  # end

  private

  def notify_watchers!
    watchers.each do |watcher|
      next if watcher == author

      watcher.push_notification(decorate.show_path, "#{author.name}さんが「#{title}」を編集しました")
    end
  end

  def set_watcher!
    author.watch!(post: self)
  end
end