Skip to content

Instantly share code, notes, and snippets.

@patrixr
Last active November 26, 2020 06:41
Show Gist options
  • Save patrixr/f9d7f4d50b5015f62c512690ce59c26f to your computer and use it in GitHub Desktop.
Save patrixr/f9d7f4d50b5015f62c512690ce59c26f to your computer and use it in GitHub Desktop.
#
# MIGRATION
#
create_table :user_favourites do |t|
t.string :favourite_type, index: true
t.integer :favourite_id
t.integer :user_id
t.boolean :persitent, default: false # Setting this prop to true would essentially make it behave as a "favourite"
t.timestamps
end
add_index :user_favourites, [:favourite_type, :favourite_id], unique: true
add_foreign_key :user_favourites, :users, column: :user_id
#
# UserFavourites Model
#
class UserFavourites < ApplicationRecord
include PushUpdatesMinimal
LIMIT_PER_TABLE = 20
belongs_to :favourite, polymorphic: true
after_create :apply_limit
def apply_limit
#
# Delete non-persistent favorites > 20
#
UserFavourites
.where(user_id: user_id, favourite_type: favourite_type, persistent: false)
.order('updated_at')
.offset(LIMIT_PER_TABLE)
.destroy_all
end
class << self
#
# Mark a record as a favourite
#
def add_user_favourite(record, persistent: false, user: User.current_user)
return unless user.present?
UserFavourites.where(
user: user,
favourite: record,
persistent: persistent
).first_or_initialize do |fav|
fav.save if r.new_record?
fav.touch if r.persisted?
end
end
#
# Removes a favourite
#
def remove_user_favourite(record, user: User.current_user)
UserFavourites.where(user: user, favourite: record).destroy_all if user.present?
end
end
end
#
# A concern that detects usage of a record by a user, and adds it to the favourites
#
module AutoFavourite
extend ActiveSupport::Concern
included do
after_create :mark_recent_usage
after_update :mark_recent_usage
after_destroy :remove_from_favourites
scope :recently_used, -> (user_id) {
joins(%{
LEFT JOIN user_favourites ON user_favourites.favourite_type = '#{self.class.name}' AND user_favourites.user_id = #{user_id}
}).order('user_favourites.updated_at DESC').limit(20)
}
end
class_methods do
def auto_favourite(enabled = true)
@auto_favourite_enabled = enabled
end
def auto_favourite_relations(relations = [])
@auto_favourite_relations = relations
end
end
private
def mark_recent_usage
UserFavourite.add_user_favorite(self) if @@auto_favourite_enabled
relations = @@auto_favourite_relations || []
relations.each do |name|
rel = self.try(name)
if rel.present?
foreign_key = self.reflections[name].foreign_key
UserFavourite.add_user_favorite(rel) if self["#{foreign_key}_changed?"].present?
end
end
end
def remove_from_favourites
UserFavourite.remove_user_favourite(self)
end
end
#
# Example usage of the concern
#
class Package < ApplicationRecord
include AutoFavourite
...
auto_favourite # the package will be auto-favourited
auto_favourite_relations ['package_type'] # the package's type will be auto-favourited if it has changed
end
class PackagesInventory < ApplicationRecord
include AutoFavourite
auto_favourite false # We don't want to keep track of recently used packages_inventories
auto_favourite_relations ['package', 'location'] # We do want to keep track of packages and locations when a packages_inventory is created
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment