Collection of concerns for your Rails application
Copy to your app/models/concerns
directory
Use and modificate at your will. Fork this gist to participate.
@romansklenar
module Paranoid | |
extend ActiveSupport::Concern | |
included do | |
extend ClassMethods | |
include InstanceMethods | |
scope :only_deleted, -> { unscoped.where.not(deleted_at: nil) } | |
scope :with_deleted, -> { unscoped } | |
scope :without_deleted, -> { where(deleted_at: nil) } | |
default_scope { without_deleted } | |
end | |
module ClassMethods | |
def restore(id) | |
if id.is_a?(Array) | |
id.map { |one_id| restore(one_id) } | |
else | |
only_deleted.find(id).restore! | |
end | |
end | |
end | |
module InstanceMethods | |
def destroy! | |
run_callbacks(:destroy) { delete! } | |
end | |
alias :destroy :destroy! | |
def delete! | |
return if new_record? || destroyed? | |
self.class.unscoped { update_column :deleted_at, Time.now } | |
end | |
alias :delete :delete! | |
def restore! | |
self.class.unscoped { update_column :deleted_at, nil } | |
end | |
alias :restore :restore! | |
def destroyed? | |
!self.deleted_at.nil? | |
end | |
alias :deleted? :destroyed? | |
def paranoid? | |
true | |
end | |
# If a paranoid record is selected, then we only want to check | |
# if it's a new record, not if it is "destroyed". | |
def persisted? | |
paranoid? ? !new_record? : super | |
end | |
end | |
end |
module Steppable | |
extend ActiveSupport::Concern | |
included do | |
include InstanceMethods | |
attr_writer :steps, :current_step | |
end | |
module ClassMethods | |
end | |
module InstanceMethods | |
def steps | |
@step ||= [] | |
end | |
def current_step | |
@current_step ||= steps.first | |
end | |
def next_step | |
steps[steps.index(current_step)+1] unless last_step? && steps.any? | |
end | |
def previous_step | |
steps[steps.index(current_step)-1] unless first_step? && steps.any? | |
end | |
def first_step | |
steps.first | |
end | |
def last_step | |
steps.last | |
end | |
def skip_step! | |
@current_step = next_step | |
end | |
def current_step?(step) | |
current_step == step | |
end | |
def next_step?(step) | |
steps[steps.index(step)] == next_step if steps.include?(step) | |
end | |
def previous_step?(step) | |
steps[steps.index(step)] == previous_step if steps.include?(step) | |
end | |
def first_step?(step = nil) | |
(step || current_step) == first_step | |
end | |
def last_step?(step = nil) | |
(step || current_step) == last_step | |
end | |
def progress | |
i = steps.index(current_step) | |
(i+1).to_f / steps.size * 100 if steps.any? | |
end | |
end | |
end |
module Taggable | |
extend ActiveSupport::Concern | |
included do | |
include InstanceMethods | |
has_many :taggings, as: :taggable, dependent: :destroy | |
has_many :tags, through: :taggings | |
end | |
module InstanceMethods | |
def tag(name) | |
name.strip! | |
tag = Tag.where(name: name).first_or_create! | |
self.taggings.where(tag: tag).first_or_create! | |
end | |
def tag_names | |
@tag_names ||= tags.collect(&:name).flatten.uniq.join(Tag::DELIMITER) | |
end | |
def tag_names=(names) | |
self.taggings.destroy_all | |
names.strip.split(Tag::DELIMITER).flatten.uniq.each { |name| self.tag(name) } | |
end | |
end | |
end |
module Tagger | |
extend ActiveSupport::Concern | |
included do | |
include InstanceMethods | |
has_many :owned_taggings, as: :tagger, dependent: :destroy, class_name: "Tagging" | |
has_many :owned_tags, through: :owned_taggings, source: :tag, class_name: "Tag" | |
end | |
module InstanceMethods | |
def tag(taggable, with) | |
tag_names = with.flatten.uniq.map(&:strip) | |
tag_names.each do |name| | |
tag = Tag.where(name: name).first_or_create! | |
self.owned_taggings.where(tag: tag, taggable: taggable, tagger: self).first_or_create! | |
end | |
end | |
def owned_tag_names | |
owned_tags.pluck(:name).flatten.uniq.join(Tag::DELIMITER) | |
end | |
end | |
end |