class Notifications::Channel < ApplicationRecord belongs_to :app has_many :templates, class_name: 'Notifications::Template', dependent: :destroy has_many :broadcasts, class_name: 'Notifications::Broadcast', dependent: :destroy has_many :user_preferences, class_name: 'Notifications::Preference', dependent: :destroy has_one :in_app_template, -> { in_app.order(updated_at: :desc) }, class_name: 'Notifications::Template', inverse_of: :channel has_one :email_html_template, -> { email.html.order(updated_at: :desc) }, class_name: 'Notifications::Template', inverse_of: :channel has_one :email_text_template, -> { email.text.order(updated_at: :desc) }, class_name: 'Notifications::Template', inverse_of: :channel validates :name, presence: true, uniqueness: { scope: :app_id, case_sensitive: true } scope :internal, -> { where(internal: true) } def self.deliver(via:, to:, with:) as_notifier(via: via, with: with) &.deliver(to) end def self.deliver_later(via:, to:, with:) as_notifier(via: via, with: with) &.deliver_later(to) end def self.as_notifier(via:, with:) channel_name = via.to_s.remove('_notifier').remove('Notifier') find_by_name(channel_name) # rubocop:disable Rails/DynamicFindBy &.as_notifier(with: with) end def self.find_by_name(channel_name) find_by(name: [ channel_name, channel_name.to_s.underscore, channel_name.to_s.camelize ]) end def deliver(to:, with:) as_notifier(with: with) .deliver(to) end def deliver_later(to:, with:) as_notifier(with: with) .deliver_later(to) end def as_notifier(with:) to_noticed_class .with(with) end private def to_noticed_class # we need local variables for the `define_method` closures to have access to these data in_app_subject_template = in_app_template&.subject in_app_body_template = in_app_template&.body email_subject_template = (email_html_template || email_text_template)&.subject email_html_body_template = email_html_template&.body email_text_body_template = email_text_template&.body channel_id = id klass = Class.new(Noticed::Base) do deliver_by :database, if: :in_app_notifications? deliver_by :email, mailer: 'NotificationMailer', if: :email_notifications? define_method :in_app_notifications? do preference = preferences&.in_app? return preference unless preference.nil? true end define_method :email_notifications? do preference = preferences&.email? return preference unless preference.nil? true end define_method :in_app_subject do render_template(in_app_subject_template) end define_method :in_app_body do render_template(in_app_body_template).html_safe end define_method :email_subject do render_template(email_subject_template) end define_method :email_html_body do render_template(email_html_body_template) end define_method :email_text_body do render_template(email_text_body_template) end define_method :preferences do recipient.notification_preferences.find_by(channel_id: channel_id) end define_method :render_template do |template| return '' unless template template % attributes end define_method :attributes do original = params.symbolize_keys Hash.new { |_, k| original[k] || '' } end end # to avoid ever seeing something like #<#:0x00007fd5868c5088> in logs or the console Object.const_set "#{app.name.camelize}#{name.camelize}Notifier", klass end end