thoughtbot / griddler

Simplify receiving email in Rails (deprecated)
http://griddler.io/
MIT License
1.38k stars 199 forks source link

Usage with Sinatra #275

Closed adaam2 closed 7 years ago

adaam2 commented 7 years ago

Hi there,

I was just wondering if it would be possible to use this in a Sinatra application! Please let me know - otherwise I will have to piece apart the source code and formulate my own solution.

Adam

wingrunr21 commented 7 years ago

You'd need to implement something along the lines of Griddler::EmailsController inside your Sinatra app but the rest of Griddler should be usable as-is.

adaam2 commented 7 years ago

@wingrunr21 Thanks!

There is the added complication that Griddler::EmailsController inherits from the Rails ActionController class, but I found this glue code online that enables you to implement ActionController in a Sinatra app:

require 'rubygems'
require 'sinatra/base'

# ActionPack is a gem that is part of Rails. It includes ActionController and ActionView
require 'action_pack'

# Rack::Test is not used in this file but ActionController will yell if we don't require it
require 'rack/test'

# This is part of the ActionPack gem
require 'action_controller'

module RailsIntegrationHelpers
  # Connect a Sinatra endpoint to an ActionController action
  # @param [Symbol] method The HTTP method to match
  # @param [String] path A Sinatra-compatibile path to match
  # @param [Hash] options Configuration for the route.
  #   Requires at least one key (:to), whose value must either be a String of the form 'controller_name#action_name'
  #   or a hash with keys :controller and :action.
  #   In either case, controller_name should be a snake case representation of the name of the controller class,
  #   without the `_controller` suffix.
  #   For example, { to: 'hello_world#test' } maps to HelloWorldController#test
  #   All other options will be passed as usual to the Sinatra processor.
  def rails_route(method, path, options)
    options = options.with_indifferent_access
    to = options.delete(:to)
    controller_name, action_name = to.is_a?(String) ? to.split('#') : [to[:controller], to[:action]]
    controller_klass = "#{ controller_name.camelize }Controller".constantize
    route method.to_s.upcase, path, options do
      # Make sure that our parsed URL params are where Rack (and ActionDispatch) expect them
      action_request = ActionDispatch::Request.new \
        request.env.merge 'rack.request.query_hash' => params
      controller_klass.new.dispatch action_name, action_request
    end
  end
end

# A real Rails controller!
class TestController < ActionController::Base
  # A dumb filter to prove that our dispatcher is working
  before_filter :test

  def hello
    render text: "<h1>Hello from #{ @framework }</h1>"
  end

  def greeting
    render text: "<h1>Hello from #{ params[:name] } and #{ @framework }</h1>"
  end

  private

  def test
    # This isn't TECHNICALLY Rails, so use scare quotes
    @framework = '"Rails"'
  end
end

# A Sinatra app; the status quo
class SomeApp < Sinatra::Base
  extend RailsIntegrationHelpers

  # Here it is: a proposal for tying Sinatra::Base and ActionController::Base together
  # This syntax is similar to what the Rails router uses; let's get some practice in.

  # This will direct requests for /hello to TestController#hello
  rails_route :get, '/hello', to: 'test#hello'
  # And this will direct requests for /hello/:name to TestController#greeting,
  # passing params[:name] as expected
  rails_route :get, '/hello/:name', to: 'test#greeting'

  # This is just how you run a modular Sinatra app with `ruby file.rb`
  run! if app_file == $0
end

Source: https://gist.github.com/johnholdun/bafbb4131f1812bb2ae8

Thank you for your help.

wingrunr21 commented 7 years ago

Glad you got it working. The EmailsController is pretty straightforward though. Rather than pulling in several Rails dependencies I'd just duplicate the logic.