palkan / active_delivery Goto Github PK
View Code? Open in Web Editor NEWRuby framework for keeping all types of notifications (mailers, push notifications, whatever) in one place
License: MIT License
Ruby framework for keeping all types of notifications (mailers, push notifications, whatever) in one place
License: MIT License
When I try to use negated matcher in RSpec, I get the following error:
Failure/Error: expect { subject }.to have_not_delivered_to(MyDelivery)
You must pass an argument rather than a block to use the provided matcher (have not delivered to MyDelivery), or the matcher must implement `supports_block_expectations?`.
The reason in method lookup path and matcher's name which leads to this point:
https://github.com/rspec/rspec-expectations/blob/33e3c614f82be81f81e09f8725b6bc450f7c40d0/lib/rspec/matchers.rb#L962-L963
Would love to send PR with fix if you give me a hint :)
UPDATED: problem is not only with negated matchers, but with all RSpec matchers
Hello,
When the active_delivery gem in installed, it is impossible for me to migrate my test ENV. I get this message :
NoMethodError: undefined method
'configure' for RSpec:Module /home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/active_delivery-0.3.0/lib/active_delivery/testing/rspec.rb:167:in
rails db:migrate RAILS_ENV=test --trace
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/faraday-0.17.0/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/faraday-0.17.0/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/faraday-0.17.0/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/faraday-0.17.0/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/faraday-0.17.0/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
rails aborted!
NoMethodError: undefined method `configure' for RSpec:Module
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/active_delivery-0.3.0/lib/active_delivery/testing/rspec.rb:167:in `<main>'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:325:in `block in require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:291:in `load_dependency'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:325:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/active_delivery-0.3.0/lib/active_delivery/testing.rb:48:in `<main>'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:325:in `block in require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:291:in `load_dependency'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:325:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/active_delivery-0.3.0/lib/active_delivery.rb:10:in `<main>'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/2.7.0/bundler/runtime.rb:74:in `block (2 levels) in require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/2.7.0/bundler/runtime.rb:69:in `each'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/2.7.0/bundler/runtime.rb:69:in `block in require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/2.7.0/bundler/runtime.rb:58:in `each'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/2.7.0/bundler/runtime.rb:58:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/2.7.0/bundler.rb:174:in `require'
/home/yves/calaundry/config/application.rb:7:in `<main>'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:325:in `block in require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:291:in `load_dependency'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:325:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:48:in `require_relative'
/home/yves/calaundry/Rakefile:4:in `<main>'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:54:in `load'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:54:in `load'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:319:in `block in load'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:291:in `load_dependency'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:319:in `load'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/rake_module.rb:29:in `load_rakefile'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/application.rb:703:in `raw_load_rakefile'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/application.rb:104:in `block in load_rakefile'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/application.rb:186:in `standard_exception_handling'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/application.rb:103:in `load_rakefile'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/railties-6.0.1/lib/rails/commands/rake/rake_command.rb:22:in `block in perform'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/application.rb:186:in `standard_exception_handling'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/railties-6.0.1/lib/rails/commands/rake/rake_command.rb:20:in `perform'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/railties-6.0.1/lib/rails/command.rb:48:in `invoke'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/railties-6.0.1/lib/rails/commands.rb:18:in `<main>'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:325:in `block in require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:291:in `load_dependency'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.1/lib/active_support/dependencies.rb:325:in `require'
/home/yves/calaundry/bin/rails:9:in `<top (required)>'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/spring-2.1.0/lib/spring/client/rails.rb:28:in `load'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/spring-2.1.0/lib/spring/client/rails.rb:28:in `call'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/spring-2.1.0/lib/spring/client/command.rb:7:in `call'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/spring-2.1.0/lib/spring/client.rb:30:in `run'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/spring-2.1.0/bin/spring:49:in `<top (required)>'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/spring-2.1.0/lib/spring/binstub.rb:11:in `load'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/spring-2.1.0/lib/spring/binstub.rb:11:in `<top (required)>'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
/home/yves/.rbenv/versions/2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
/home/yves/calaundry/bin/spring:15:in `<top (required)>'
bin/rails:3:in `load'
bin/rails:3:in `<main>'
I solved the problem by removing the gem from the gemfile for the moment.
Thanks for your help.
Texicitys
Hi, how would you suggests folders to be organized for deliveries and lines? something like app/deliveries and app/services/lines?
I know it's completely up to the developer, but I wonder whether you have a pattern to suggest for structuring this better!
Thanks
Hi!
How about to add have_not_deliverd_to
matcher?
This would allow me to rewrite my code
from
it "doesn't send notification to listener" do
expect { subject }.not_to have_delivered_to(EventDelivery, :notify_listener)
end
it "doesn't send notification to manager" do
expect { subject }.not_to have_delivered_to(EventDelivery, :notify_manager)
end
to
it "doesn't send notifications to listener and manager" do
expect { subject }.to have_not_delivered_to(EventDelivery, :notify_listener)
.and have_not_delivered_to(EventDelivery, :notify_manager)
end
Schedule a delivery like action mailer
MyDelivery.with(user: u).notify(:something, {wait_until: 1.minute.from_now})
I'm wondering if it's currently possible or not. I did not find any clue on the documentation. From the code I've read, it seams possible but not found the correct way to write it. @palkan I'm pretty sure you know everything about this subject. Could you light this up? 😁
The ActiveDelivery::TestDelivery module user fiber-local storage to store its state. This makes its behavior break when using rspec matchers to test a delivery done in a fiber.
class SomeDelivery < ActiveDelivery::Base
end
RSpec.describe SomeDelivery do
it 'works with fibers' do
expect do
Fiber.new { SomeDelivery.notify!(:event) }.resume
end.to have_delivered_to(SomeDelivery, :event)
end
end
Failures:
1) SomeDelivery works with fibers
Failure/Error:
expect do
Fiber.new { SomeDelivery.notify!(:event) }.resume
end.to have_delivered_to(SomeDelivery, :event)
expected to deliver :event notification via SomeDelivery with:
- args: <none>
exactly once, but haven't delivered anything
# ./spec/some_delivery.rb:8:in `block (2 levels) in <top (required)>'
Finished in 0.09412 seconds (files took 2.25 seconds to load)
1 example, 0 failures
This is behavior is related to the usage of Thread#[]
and Thread#[]=
to set the TestModule
internal state which are both fiber-local.
I believe this is not the intended behavior and could be fixed by using Thread#thread_variable_set
and Thread#thread_variable_get
methods.
In any case if you think this is worth fixing I can open a pull request for this.
Hi;
I'm trying to test the logic of my callbacks. I was hoping to do something like:
subject { MyDelivery.with(with_params).notify(notification) }
...
expect { subject }.not_to have_delivered_to(MyDelivery, notification)
but it looks like the callbacks are not actually getting called in test mode. Is that correct? Is there a different way you suggest to test my logic?
Here's what my class looks like:
class MyDelivery < ApplicationDelivery
before_notify :check_conditions
...
private
def check_conditions
if params[:only_if_unsent].present?
return false if user.notified?(notification_name)
end
I tried using it with sidekiq but not working
Upgrade from 0.4.4
to 1.0.0
Nothing breaking
Failure on specs for have_delivered_to
used with a_hash_including
expect { subject.do_something }
.to have_delivered_to(V1::SomeDelivery, :do_something).with(
a_hash_including(foo: :bar)
)
Error raised:
expected to deliver :do_something notification via V1::SomeDelivery with:
- params: a stash including {:foo => :bar}
- args: < none >
exactly once, but delivered the following unexpected notifications:
- params: {:foo => :bar}
- args: []
- kwargs: {}
Ruby Version: 2.7.2
Framework Version (Rails, whatever): 6.1.7.6
Active Delivery Version: 1.0.0
The reason for this behavior lies in the
active_delivery/lib/active_delivery/base.rb
Line 102 in 1c05a03
sync:
argument.
I believe that a hash should be correctly processed like any other argument and it needs some refactoring here.
On new line implementation, I figured out that example given is not working perfectly with parameterized mailer/line
# `kwargs.merge(line.params)` is the path I found
def notify_later(line, delivery_action, *args, **kwargs)
NewLineJob.perform_later line.class, delivery_action, *args, **kwargs.merge(line.params)
end
unless this, we cannot handle parametrized value on class method. Here is my second implementation on the new line
class NewLine
attr_reader :params
class << self
##
# Class method to init (for async) and call the instance method
def my_method(*args)
with(args.last).my_method
end
end
def initialize(params = {})
@params = params
# Do something else with params
end
end
end
I'm not 100% sure this works in all cases. Can you confirm with the whole gem knowledge
@palkan ?
In my case it's not a problem because all my mailers are parameterized (adding tracking headers) but I did not check with non-parameterized method after this fix.
With inheritance, if becomes more and more complicated to test callbacks correctly. A dedicated matcher could help a lot with that.
describe '#initialize' do
let(:service) { MyDelivery.with(foo: :bar) }
it 'has `baz` callback' do
expect(service).to have_active_callback(:baz)
.with_action(:before)
.on(:mailer)
.only_for(:foo_bar)
.and_return(true)
end
end
Unless, you need to test every single clauses manually for each method called.
I faced with problem when I need to notify by email several recipients with different content. So I have several Action Mailer classes for that. But I couldn't find a way how to explicitly set mailer class when I'm registering the line. It would be great to have it on the same way how we do it with ActiveDelivery::Lines::Notifier
:
register_line :merchant, ActiveDelivery::Lines::Notifier,
resolver: ->(name) { Notifications::MerchantMailer }
To have it working - I added CustomMailer
class:
module DeliveryLines
class CustomMailer < ActiveDelivery::Lines::Notifier
alias mailer_class handler_class
def notify?(method_name)
mailer_class.action_methods.include?(method_name.to_s)
end
def notify_now(mailer, mid, *args)
mailer.public_send(mid, *args).deliver_now
end
def notify_later(mailer, mid, *args)
mailer.public_send(mid, *args).deliver_later
end
end
end
It works good to me. But probably having ability to set resolver for ActiveDelivery::Lines::Mailer
class on the same way how we have it at ActiveDelivery::Lines::Notifier
is a good idea for improvement?
Because Anonymous args supports since Ruby 3.2, syntax error occur in Ruby 3.1.
https://rubyreferences.github.io/rubychanges/3.2.html#anonymous-arguments-passing-improvements
N/A
N/A
N/A
Ruby Version:
3.1
Framework Version (Rails, whatever):
N/A
Active Delivery Version:
1.2.0
If you want to avoid a callback for a specific method, skip
is not implemented
Something like AbstractController::Callbacks
Currently, the only solution to do that is to redefine the callback on the child class and use except
.
Hi guys,
I'm still working through my usecase.
My users can receive either email or sms notifications depending on whether or not they have provided an (email, phone), as well as how they have set up their preferences.
I've thought of modeling this several ways, none of which seem currently supported in the code. But I figure I must be misunderstanding something, since it seems like this is the problem you set out to solve in the first place.
Here's what I came up with:
conditional execution of Lines:
class ApplicationDelivery
before_notify { raise ArgumentError, 'need user' unless params[:user].present? }
register_line :email, if: ->() { params[:user].email.present? }
register_line :sms, if: ->() { params[:user].phone.present? }
end
or halting execution within the line itself:
# This works right now:
class ApplicationMailer < ActionMailer::Base
before_action do |mail|
if !params[:recipient].email.present?
# Callbacks for mailers are implemented using AbstractController::Callbacks
# This sets up a 'terminator' of:
# result_lambda.call; controller.performed?
# AbstractController::Base sets performed? as: 'response_body'
# So - as soon as we set a response body, no other callbacks or actions will occur.
# So - in addition to suppressing deliveries for this mail, we will also set a response body
# so that no further callbacks (or the action itself) get performed, thereby stopping processing.
mail.perform_deliveries = false
mail.response_body = "DO_NOT_DELIVER"
end
end
end
# but AbstractNotifier doesn't seem to support callbacks
class ApplicationSms < AbstractNotifier::Base
before_action do
# assuming a callback implementation with a terminator that checks for false return value
return params[:recipient].phone.present?
end
end
What am I missing?
Hi guys,
Thanks for implementing this gem, it's super helpful!
There is one thing, which seems to be really nice to have - an option to specify the name of the notification for a callback. It turned out that quite often, we need to do something only for specific notification. Right now, we have two options:
QuestionsDelivery < ApplicationDelivery
after_notify :mark_question_as_sent
after_notify do
# Option 2: check notification_name and call needed actions
mark_question_as_sent if notification_name == :send_questions
create_event if notification_name == :questions_reminder
end
private
def mark_question_as_sent
# Option 1: another notification doesn't need a question object, e.g. it's a reminder to a user that we can send questions, so we can just check if params[:question] is present.
return unless params[:question].present?
end
end
As you see, both solutions look hacky, it would be nice to have something like:
after_notify :mark_question_as_sent, only: %[questions_sent]
Upgrade from 0.4.4
to 1.0.0
Nothing breaking
Breaking change on resolve_class
definition for new delivery method.
# before "name" was a String
def resolve_class(name)
name.gsub(/Delivery$/, 'Pusher').safe_constantize
end
# after "name" is a Class
def resolve_class(name)
name.to_s.gsub(/Delivery$/, 'Pusher').safe_constantize
end
@palkan Is that a normal update? Maybe if it's breaking we can add it to the change log?
Ruby Version: 2.7.2
Framework Version (Rails, whatever): 6.1.7.6
Active Delivery Version: 1.0.0
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.