Skip to content

Instantly share code, notes, and snippets.

@fdutey
Created January 15, 2012 00:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fdutey/1613585 to your computer and use it in GitHub Desktop.
Save fdutey/1613585 to your computer and use it in GitHub Desktop.
module Formol
class Post < ActiveRecord::Base
#Security
attr_protected :topic_id, :user_id, :created_by_topic
#Virtual attributes
attr_accessor :created_by_topic, :quote_id, :register_user_as_subscriber
#Default values
default_value_for :created_by_topic, false
default_value_for :display_signature do |p|
p.user ? p.user.preference.use_signature : true
end
#Associations
belongs_to :topic, :touch => true,
:counter_cache => true
belongs_to :user, :class_name => Formol.config.user_class,
:counter_cache => :formol_posts_count
has_one :forum, :through => :topic
#Validations
validates :topic, :presence => true
validates :user, :presence => true
#Length is set with a minimum of 2 to allow posts with simple "ok" answer
#Length is set with a maximum of 50 000 because 50Kb is enough for a non
#binary forum
validates :content, :presence => true,
:length => { :in => 2..50_000,
:allow_blank => true }
validate :validates_topic_not_locked
#Normalization
normalize_attribute :content, :with => [:strip, :blank]
#Callbacks
after_initialize :feed_content_with_quote
after_save :register_author_as_subscriber
after_create :increment_forum_counter_cache,
:register_as_last_post_on_topic,
:register_as_last_post_on_forum
after_destroy :decrement_forum_counter_cache,
:unregister_as_last_post_on_topic,
:unregister_as_last_post_on_forum
#Scopes
class << self
# scope for ordering posts conveniently for listing views
# order by id (no order is random with mysql)
def ordered_for_listing
order('formol_posts.id ASC')
end
# scope to get posts conveniently prepared for listing
def ready_for_listing
ordered_for_listing.includes(:topic, { :user => :preference })
end
# scope to get last five posts with reverse ordering
# usefull to have a little history when replying to a topic
def last_fives
order('formol_posts.id DESC').limit(5).includes(:user)
end
end
#Business methods
# Read accessor for 'register_user_as_subscriber'
def register_user_as_subscriber(force_recompute = false)
if @register_user_as_subscriber.nil? || force_recompute
@register_user_as_subscriber = compute_register_subscribing
end
@register_user_as_subscriber
end
private
# Convert 'register_user_as_subscriber' to boolean
def register_user_as_subscriber?
[true, '1', 'true'].include?(register_user_as_subscriber)
end
#Callback methods
# Registers author as subscriber if he's not already
def register_author_as_subscriber
if register_user_as_subscriber?
topic.register_subscriber(user) unless topic.subscriber?(user)
else
topic.unregister_subscriber(user) if topic.subscriber?(user)
end
end
# Validates topic is not locked
# If topic is locked, it will add an error on base (not on topic)
# This validation does not trigger on first post
def validates_topic_not_locked
errors.add(:base, :topic_locked) if topic.locked? && !created_by_topic
end
# Holds counter cache on Forum till AR does not support it on has_one
def increment_forum_counter_cache
Formol::Forum.increment_counter(:posts_count, forum.id) if forum.present?
end
# Holds counter cache on Forum till AR does not support it on has_one
def decrement_forum_counter_cache
Formol::Forum.decrement_counter(:posts_count, forum.id) if forum.present?
end
# Feed content with quote's content
# If you're trying to pass quote_id in a POST, your content will be wiped
# Too bad!
def feed_content_with_quote
return true if quote_id.blank?
q = topic.posts.find(quote_id)
formatter = Formol.config.formatter.new
# Extract and agnostize it
content_with_quote = "> **#{q.user.display_name} #{I18n.t('.wrote')}:**\n>\n"
content_with_quote << formatter.quote(q.content)
self.content = content_with_quote
self.content << "\n\n" #use '<<' to skip normalize_attribute
self.content
end
# Register current post being the last of its topic
def register_as_last_post_on_topic
topic.register_last_post(self)
end
# Unregister current post being the last of its topic
def unregister_as_last_post_on_topic
topic.unregister_last_post if topic.last_post == self
end
# Register current post being the last post of its forum
def register_as_last_post_on_forum
forum.register_last_post(self)
end
# Unregister current post being the last of its forum
def unregister_as_last_post_on_forum
forum.unregister_last_post if forum.last_post == self
end
# Computes 'register_user_as_subscriber
def compute_register_subscribing
if topic && user
topic.subscriber?(user)
else
false
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment