Class: ActiveDelivery::Base

Inherits:
Object
  • Object
show all
Includes:
Callbacks, TestDelivery
Defined in:
lib/active_delivery/base.rb

Overview

Base class for deliveries.

Delivery object describes how to notify a user about an event (e.g. via email or via push notification or both).

Delivery class acts like a proxy in front of the different delivery channels (i.e. mailers, notifiers). That means that calling a method on delivery class invokes the same method on the corresponding class, e.g.:

EventsDelivery.one_hour_before(profile, event).deliver_later
# or
EventsDelivery.notify(:one_hour_before, profile, event)

# under the hood it calls
EventsMailer.one_hour_before(profile, event).deliver_later

# and
EventsNotifier.one_hour_before(profile, event).notify_later

Delivery also supports parameterized calling:

EventsDelivery.with(profile: profile).canceled(event).deliver_later

The parameters could be accessed through params instance method (e.g. to implement guard-like logic).

When params are presents the parametrized mailer is used, i.e.:

EventsMailer.with(profile: profile).canceled(event).deliver_later

See api.rubyonrails.org/classes/ActionMailer/Parameterized.html

Constant Summary

Constants included from Callbacks

Callbacks::CALLBACK_TERMINATOR

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from TestDelivery

clear, enable, enabled?, lines, store, #test?, track, track_line

Constructor Details

#initialize(**params) ⇒ Base

Returns a new instance of Base.



169
170
171
172
# File 'lib/active_delivery/base.rb', line 169

def initialize(**params)
  @params = params
  @params.freeze
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(mid) ⇒ Object



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/active_delivery/base.rb', line 200

def method_missing(mid, *, **)
  return super unless respond_to_missing?(mid)

  # Lazily define a method to avoid future lookups
  self.class.class_eval <<~CODE, __FILE__, __LINE__ + 1
    def #{mid}(*args, **kwargs)
      delivery(
        notification: :#{mid},
        params: args,
        options: kwargs
      )
    end
  CODE

  public_send(mid, *, **)
end

Class Attribute Details

.abstract_classObject

Returns the value of attribute abstract_class.



69
70
71
# File 'lib/active_delivery/base.rb', line 69

def abstract_class
  @abstract_class
end

Instance Attribute Details

#notification_nameObject (readonly)

Returns the value of attribute notification_name.



167
168
169
# File 'lib/active_delivery/base.rb', line 167

def notification_name
  @notification_name
end

#paramsObject (readonly)

Returns the value of attribute params.



167
168
169
# File 'lib/active_delivery/base.rb', line 167

def params
  @params
end

Class Method Details

.abstract_class?Boolean

Returns:

  • (Boolean)


126
# File 'lib/active_delivery/base.rb', line 126

def abstract_class? = abstract_class == true

.delivers(*actions) ⇒ Object

Specify explicitly which actions are supported by the delivery.



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/active_delivery/base.rb', line 129

def delivers(*actions)
  actions.each do |mid|
    class_eval <<~CODE, __FILE__, __LINE__ + 1
      def self.#{mid}(...)
        new.#{mid}(...)
      end

      def #{mid}(*args, **kwargs)
        delivery(
          notification: :#{mid},
          params: args,
          options: kwargs
        )
      end
    CODE
  end
end

.delivery_linesObject



86
87
88
89
90
91
92
93
94
# File 'lib/active_delivery/base.rb', line 86

def delivery_lines
  @lines ||= if superclass.respond_to?(:delivery_lines)
    superclass.delivery_lines.each_with_object({}) do |(key, val), acc|
      acc[key] = val.dup_for(self)
    end
  else
    {}
  end
end

.method_missing(mid) ⇒ Object



155
156
157
158
159
160
161
162
# File 'lib/active_delivery/base.rb', line 155

def method_missing(mid, *, **)
  return super unless respond_to_missing?(mid)

  # Lazily define a class method to avoid lookups
  delivers(mid)

  public_send(mid, *, **)
end

.notifyObject

Enqueues delivery (i.e. uses #deliver_later for mailers)



74
75
76
# File 'lib/active_delivery/base.rb', line 74

def notify(...)
  new.notify(...)
end

.notify!(mid, **hargs) ⇒ Object

The same as .notify but delivers synchronously (i.e. #deliver_now for mailers)



80
81
82
# File 'lib/active_delivery/base.rb', line 80

def notify!(mid, *, **hargs)
  notify(mid, *, **hargs, sync: true)
end

.notify_nowObject

The same as .notify but delivers synchronously (i.e. #deliver_now for mailers)



84
85
86
# File 'lib/active_delivery/base.rb', line 84

def notify!(mid, *, **hargs)
  notify(mid, *, **hargs, sync: true)
end

.register_line(line_id, line_class = nil, notifier: nil) ⇒ Object

Raises:

  • (ArgumentError)


96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/active_delivery/base.rb', line 96

def register_line(line_id, line_class = nil, notifier: nil, **)
  raise ArgumentError, "A line class or notifier configuration must be provided" if line_class.nil? && notifier.nil?

  # Configure Notifier
  if line_class.nil?
    line_class = ActiveDelivery::Lines::Notifier
  end

  delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **)

  instance_eval <<~CODE, __FILE__, __LINE__ + 1
    def #{line_id}(val)
      delivery_lines[:#{line_id}].handler_class_name = val
    end

    def #{line_id}_class
      delivery_lines[:#{line_id}].handler_class
    end
  CODE
end

.respond_to_missing?(mid, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


147
148
149
150
151
152
153
# File 'lib/active_delivery/base.rb', line 147

def respond_to_missing?(mid, include_private = false)
  unless ActiveDelivery.deliver_actions_required
    return true if delivery_lines.any? { |_, line| line.notify?(mid) }
  end

  super
end

.unregister_line(line_id) ⇒ Object



117
118
119
120
121
122
123
124
# File 'lib/active_delivery/base.rb', line 117

def unregister_line(line_id)
  removed_line = delivery_lines.delete(line_id)

  return if removed_line.nil?

  singleton_class.undef_method line_id
  singleton_class.undef_method "#{line_id}_class"
end

Instance Method Details

#notify(mid, *args, **kwargs) ⇒ Object

Enqueues delivery (i.e. uses #deliver_later for mailers)



175
176
177
178
179
# File 'lib/active_delivery/base.rb', line 175

def notify(mid, *args, **kwargs)
  perform_notify(
    delivery(notification: mid, params: args, options: kwargs)
  )
end

#notify!(mid, *args, **kwargs) ⇒ Object Also known as: notify_now

The same as .notify but delivers synchronously (i.e. #deliver_now for mailers)



183
184
185
186
187
188
# File 'lib/active_delivery/base.rb', line 183

def notify!(mid, *args, **kwargs)
  perform_notify(
    delivery(notification: mid, params: args, options: kwargs),
    sync: true
  )
end

#respond_to_missing?(mid, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


192
193
194
195
196
197
198
# File 'lib/active_delivery/base.rb', line 192

def respond_to_missing?(mid, include_private = false)
  unless ActiveDelivery.deliver_actions_required
    return true if delivery_lines.any? { |_, line| line.notify?(mid) }
  end

  super
end