Last active
November 26, 2020 06:41
-
-
Save patrixr/f9d7f4d50b5015f62c512690ce59c26f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# 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