ActionMailer : Render multipart emails (text/html) from markdown the correct way? - view

I would like to render all my emails from markdown with using a layout "email".
Have been investigating gems and options there are 2 gems I could both could not get to work:
maildown and markerb.
Has anyone implemented a method to render text,html emails with action mailer from a markdown mail template and also using a layout? Or knows a good updated writeup on this?
Markerb registers a .markerb file extension like so:
module Markerb
class Railtie < ::Rails::Railtie
config.markerb = Markerb
config.app_generators.mailer :template_engine => :markerb
end
end
and
require "redcarpet"
require "markerb/railtie"
module Markerb
mattr_accessor :processing_options, :renderer
##processing_options = {}
##renderer = Redcarpet::Render::HTML
class Handler
def erb_handler
#erb_handler ||= ActionView::Template.registered_template_handler(:erb)
end
def call(template)
compiled_source = erb_handler.call(template)
if template.formats.include?(:html)
"Redcarpet::Markdown.new(Markerb.renderer, Markerb.processing_options).render(begin;#{compiled_source};end).html_safe"
else
compiled_source
end
end
end
end
ActionView::Template.register_template_handler :markerb, Markerb::Handler.new

Related

How to map routes to controllers in Sinatra?

I'd like to create a simple experimental MVC framework using Sinatra.
I'd like to define resources by name "pages" for example should resolve to:
/pages (index)
/pages/new
/pages/:id/show (show)
as WELL as map to app/controllers/PagesController.rb with corresponding get('/') to be responsible for the index, post('/pages/create') be responsible for creation, etc.
Trouble is even after reading the official documentation I'm terribly confused. I imagine I need to use non-classic Sinatra model for this, but could anyone point me in the right direction?
Thank you
If you want what I think you're wanting, I do this all the time. Initially for this scheme I used the travis-api source as a reference, but essentially what you want to do is extend Sinatra::Base in a "controller" class and then mount up your individual Sinatra "controllers" in rack, something like this:
module Endpoint
def self.included(base)
base.class_eval do
set(:prefix) { "/" << name[/[^:]+$/].downcase }
end
end
end
class Users < Sinatra::Base
include Endpoint
get '/' do
#logic here
end
get '/:id' do
#logic here
end
post '/' do
#logic here
end
patch '/:id' do
#logic here
end
end
class Posts < Sinatra::Base
include Endpoint
post '/' do
#logic here
end
end
and then something like this:
class App
require "lib/endpoints/users"
require "lib/endpoints/posts"
attr_reader :app
def initialize
#app = Rack::Builder.app do
[Users, Posts].each do |e|
map(e.prefix) { run(e.new) }
end
end
end
def call(env)
app.call(env)
end
end
You can adjust this to whatever you need, but the idea is the same, you separate your app into composable Sinatra applications that each have a prefix that they are mounted under using Rack. This particular example will give you routes for:
get '/users'
get '/users/:id'
post '/users'
patch '/users/:id'
get '/posts'
I'll give you a very simple example here:
Create a file controller.rb
get '/pages' do
#pages = Pages.all
erb :pages
end
Next create a views directory in the same folder as teh controller, and create a file named pages.html.erb
This is the corresponding view to your previously created controller action.
Here, you can type something like:
<% #pages.each do |p| %>
<%= p.title %>
<% end %>
Restart your server, visit localhost:PORT/pages and you will see a list of all your page titles.
You can check out this link for a simple sinatra tutorial - http://code.tutsplus.com/tutorials/singing-with-sinatra--net-18965
You can make this as complicated or as simple as you need. For example:
Rails makes a lot of magic happen under the hood, whereas Sinatra is more flexible at the cost of requiring you to implement some of this stuff yourself.
controller_map = {
'pages' => PagesController
}
post '/:controller/new' do
c = params[:controller]
module = controller_map[c]
module.create_new()
...
end
get '/:controller/:id/show' do
c = params[:controller]
id = params[:id]
module = controller_map[c]
module.get(id)
...
end

how to pass content to jekyll default converter after custom conversion?

I am trying to write a jekyll plugin which do something on markdown files first and passing the content back to the default converter
For example,
module Jekyll
class RMarkdownConverter < Converter
safe :false
priority :high
def matches(ext)
ext =~ /^\.(md|markdown)$/i
end
def output_ext(ext)
".html"
end
def convert(content)
# do something with content
# then pass it back to default converter
end
end
end
Right now, the closest thing that I could get it
converter = Jekyll::Converters::Markdown::KramdownParser.new(#config)
converter.convert(content)
But all the highlighting codes are losing color...and I suspect there are other problems...
My question is:
what is a correct way to invoke the default converter?
Here's how to do it:
module Jekyll
class MyConverter < Converter
safe :false
priority :high
def matches(ext)
ext =~ /^\.(md|markdown)$/i
end
def output_ext(ext)
".html"
end
def convert(content)
# do your own thing with the content
content = my_own_thing(content)
# Now call the standard Markdown converter
site = Jekyll::Site.new(#config)
mkconverter = site.getConverterImpl(Jekyll::Converters::Markdown)
mkconverter.convert(content)
end
end
end
Basically, you were right in using Jekyll::Converters::Markdown, but you need not specify KramdownParser, as your chosen parser will be automatically chosen from Jekyll::Site when you pass #config into the constructor.

Ruby Devise 2.2 add email address along with the user.email

Currently I am using ruby devise gem 2.2.3. And I tried to customize the confirmation_instructions for adding couple of email ids with the user email.
app/mailers/my_devise_mailer.rb
class MyDeviseMailer < Devise::Mailer
include Devise::Mailers::Helpers
def confirmation_instructions(record, opts={})
opts[:to] = "example1#mail.com, example2#mail.com"
super
end
end
config/initializers/devise.rb
config.mailer = "MyDeviseMailer"
And, I ran the following in my console
user = User.first
MyDeviseMailer.delay.confirmation_instructions(user)
I got a output without body message. PFA
Correct
Wrong
Can anyone tell me what I missed to add/configure?
You could create a new mailer instead and modify the headers of that one:
# app/mailers/my_mailer.rb
class MyMailer < Devise::Mailer
def headers_for(action, opts)
if action == :confirmation_instructions
super.merge!(to: ['example1#mail.com', 'example2#mail.com'])
else
super
end
end
end
Then tell Devise to use your mailer:
# config/initializers/devise.rb
config.mailer = MyMailer
super.merge!" will not work. Because it'll replace the value for the given key (:to). But, the requirement is to add two mail id's with 'To'. The following gist is working fine.
class MyMailer < Devise::Mailer
include Devise::Mailers::Helpers
def headers_for(action, opts={})
begin
super.merge!(to: [super[:to], 'example1#mail.com', 'example2#mail.com'], template_path: ["devise/mailer"]) if action == :confirmation_instructions
rescue Exception => e
super
end
end
end
Happy Coding!!

Access Sinatra settings from a model

I have a modular Sinatra app. I'm setting some custom variables in my configure block and want to access these settings in my model.
The problem is, I get a NoMethodError when I try and access my custom settings from MyModel. Standard settings still seem to work fine though. How can I make this work?
# app.rb
require_relative 'models/document'
class App < Sinatra::Base
configure do
set :resource_path, '/xfiles/i_want_to_believe'
end
get '/' do
#model = MyModel.new
haml :index
end
end
# models/my_model.rb
class MyModel
def initialize
do_it
end
def do_it
...
settings.resource_path # no method error
...
settings.root # works fine
end
end
i think that you should be able to access it via
Sinatra::Application.settings.documents_path
I ended up doing:
#document.rb
class Document
def self.documents_path=(path)
#documents_path = path
end
def self.documents_path
#documents_path
end
...
end
#app.rb
configure do
set :documents_path, settings.root + "/../documents/"
Document.documents_path = settings.documents_path
end
then just using Document.documents_path inside my find method.

Call Sinatra erb from another class

I need to render a Sinatra erb template inside a class in my controller. I'm having issues calling this though. I've looked in the Sinatra rdocs and have come up with this:
Sinatra::Templates.erb :template_to_render
When I do this, I get the following error:
undefined method `erb' for Sinatra::Templates:Module
Is there a way to call this from another class?
To imitate rendering behavior of Sinatra controller in some other class (not controller) you can create module like this:
module ErbRender
include Sinatra::Templates
include Sinatra::Helpers
include Sinatra::ContentFor
def settings
#settings ||= begin
settings = Sinatra::Application.settings
settings.root = "#{ROOT}/app"
settings
end
end
def template_cache
#template_cache ||= Tilt::Cache.new
end
end
Here you may need to tune settings.root
Usage example:
class ArticleIndexingPostBody
include ErbRender
def get_body
erb :'amp/articles/show', layout: :'amp/layout'
end
end
This will properly render templates with layouts including content_for
why you don't require 'erb' and after use only erb
## You'll need to require erb in your app
require 'erb'
get '/' do
erb :index
end
You could have your class return the template name and render it in the main app.
Of course that's not exactly an answer (I don't have enough rep to add a comment with this account) and you're probably doing just that by now anyway...

Resources