-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example of not using ActionMailer #14
Comments
I would love to see some documentation for how to use caffeinate without ActionMailer... In my case, Email Templates are are stored in the database, so curious if I could get that to work! |
How are you sending mail? API? (though, if you're still using ActionMailer, you can still store the templates in the database and have them sent via ActionMailer. I do this for my horse ranch and https://github.com/andreapavoni/panoramic.) Let me know how you're sending mail and I can figure out some ways to make this work for you! |
Just found some time to put a really icky thing together. You'll miss out on some of the callbacks but they're pretty easy to implement. Here's the basics:
It'll still be named
The rest should take care of itself! This will still give you the callbacks too. |
Also, if you don't like #14 (comment) (I don't), you might like this better?
|
Thank you very much for writing two whole versions of this. Looks very cool! |
Please do and let me know how it goes! I'd love to chat about how you're using Caffeinate too sometime, just drop me an email at |
Ah, I didn't realize this conversation has picked up in the last couple of days! How timely 😛 I just recently built out a custom Here's our secret sauce in case it helps others: (modified from original code for IP but premise remains) Persisted Emails + ActionMailerA note: we store our # app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
layout "standard_email"
def thirty_day_followup(mailing)
@user = mailing.subscriber.decorate
@email = Email.new(
sender: User.internal_bot,
recipient: @user,
to_email_addy: @user.full_email,
from_email_addy: @user.first_contacted_by.full_email,
email_type: :outgoing,
subject: "Following up on your new thing",
full_body: {
io: StringIO.new(render(layout: false)),
filename: "full_body.html",
content_type: "text/html"
}
)
@email.save! unless mailing.is_a?(MockMailing) # Rails Mailer Previews shouldn't actually save off email records
mail(subject: @email.subject, to: @email. to_email_addy, from: @email. from_email_addy, cc: @email.cc, bcc: @email.bcc)
end
end
# spec/mailers/previews/user_mailer_preview.rb
class UserMailerPreview < ActionMailer::Preview
def thirty_day_followup
UserMailer.thirty_day_followup(MockMailing.new(User.last))
end
end
# in config/initializers/action_mailer.rb
MockMailing = Struct.new(:subscriber) So, pretty straightforward there. Using ActionMailer but saving the record off in the middle (unless ActionMailer is being invoked from a Preview class via the custom Caffeinated TextingWe wrote a custom "Texter" class — somewhat a nod to Textris but custom-made to be more easily spoofed to Caffeinate's API. I'm not sure Textris is maintained much anymore either. The Texters here could definitely be made more like Textris / ActionMailer, but this is our current v1 approach. # app/texters/application_texter.rb
class ApplicationTexter
# NOTE: Delegates unknown class methods to a new instance as to support the
# ActionMailer API of FooMailer.intro_message(xyz) (which sets up a new instance)
class << self
delegate_missing_to :new
end
attr_accessor :caffeinate_mailing
attr_writer :perform_deliveries
# NOTE: This method is built to be at rough-parity with ActionMailer in its
# callback sequence and underlying sending structure for compatibility with
# Caffeinate
def deliver
# Run ActionMailer-parity/Caffeinate callbacks and hooks
@perform_deliveries ||= true
Caffeinate::ActionMailer::Interceptor.delivering_email self
return unless @perform_deliveries
message = Sms.create!(
direction: :outbound,
user: @user,
internal_number: @internal_number,
external_number: @external_number,
body: @body
)
message.send!
if caffeinate_mailing
caffeinate_mailing.update!(sent_at: Caffeinate.config.time_now, skipped_at: nil)
caffeinate_mailing.caffeinate_campaign.to_dripper.run_callbacks(:after_send, caffeinate_mailing, self)
end
end
# Renders out the view template of the given subclass's method, by name,
# similar-ish to controller-style:
# UserTexter#introduction_message -> views/texters/user_texter/introduction_message.text.erb
def render(template_name = nil)
# Digging into Kernel a bit to get the name of the subclass action that called
template_name ||= caller_locations(1, 1)[0].label
class_name = self.class.name.underscore
assigns = instance_variables.map do |iv|
key = iv.to_s.delete("@")
[key, instance_variable_get(iv)]
end.to_h
ApplicationController.renderer.new(
http_host: "example.com",
https: true
).render(
template: "texters/#{class_name}/#{template_name}",
layout: false,
assigns: assigns
)
end
end and a typical sub-class... # app/texters/user_texter.rb
class UserTexter < ApplicationTexter
def welcome(texting)
@user = User.internal_bot
@internal_number = Rails.config.our_phone_number
@external_number = @user.phone
@body = render
self # Texter actions must return self as parity with ActionMailers
end
end So we can now have a dripper like: # app/drippers/welcome_dripper.rb
class WelcomeDripper < ApplicationDripper
self.campaign = :welcome_user
before_drip do |_drip, mailing|
user = mailing.subscriber
if user.has_setup_new_assets?
mailing.subscription.unsubscribe!("User got setup")
throw(:abort)
end
end
drip :welcome, mailer: :UserTexter
drip :welcome_email, mailer: :UserMailer
# etc.
end which uses both Texters and Mailers 🎉 |
this has just pushed me to actually work on getting POROs properly supported. Edit: not to say that your implementation is wrong or bad, but it makes me feel like it should be native. Will tag you in PR for review, hope you don't mind :) |
Not at all! Happy to take a look and see where it goes. Will never say no to the implementation on our side getting simpler 😆 |
@jon-sully invited you as collab; also see (and kindly review) #24 :) |
@joshmn my apologies that I haven't been able to get to testing this yet... I've got a big vacation coming tomorrow, so you know how the week before vacation can end up crazy... I'm still very excited to test using caffinate as you described as soon as I'm back - May 8th. |
@erwin Very excited for you to try it too! I have already plugged it in for my horse ranch and it's working lovely so hopefully it'll work for you too! :) have fun on your vaca! |
It's plenty possible, but will be kind of hacky.
Edit: here's a proof of concept. I'll make something more clean for V3, whenever that will be: #14 (comment), also #14 (comment)
The text was updated successfully, but these errors were encountered: