I have a Sinatra Ruby app with the ActionMailer gem for sending emails. The email sending functionality works fine, but I can't figure out how to use the preview functionality for development. My mailer mailer.rb is located in lib/companyname/mailers, and my preview mailer_preview.rb is located in spec/companyname/mailers/previews. When I run my app and navigate to http://localhost:26250/rails/mailers I get a 404 "Sinatra doesn't know this ditty" page.
What do I need to do to be able to see the previews in my browser?
mailer.rb
module CompanyName
class Mailer < ActionMailer::Base
def test_email(recipient_email_address)
email = mail(to: recipient_email_address, from: "no-reply#companyname.com", subject: "Testing ActionMailer") do |format|
format.html { "<h1>Testing</h1>" }
end
email.deliver_now
end
end
end
mailer_preview.rb
module CompanyName
class MailerPreview < ActionMailer::Preview
def test_email
Mailer.test_email("test#email.com")
end
end
end
After looking at the code for ActionMailer I couldn't find any non-Rails method of configuration, so it looks like this isn't currently possible*. I ended up setting up a Sinatra endpoint to load the HTML from the MailerPreview class and just display it in the browser:
mailers_controller.rb
get "/emails/:email_name" do
halt 404 unless ENV["ENABLE_MAIL_TEST_ENDPOINT"] == "true"
email_preview = CompanyName::MailerPreview.public_send(params["email_name"])
email_preview.html_part.decoded # Note: I switched to the Mail gem instead of ActionMailer, so the code may not be identical
end
*I am not a Rails expert so this may not be the case, however to the best of my abilities I could not see a solution.
Related
I started to build a website with padrino. At the moment the main class of my app is the simplest thing in the world:
class App < Padrino::Application
enable :sessions
get :index do
send_file 'public/view/index.html'
end
error 404 do
send_file 'public/view/errors/404.html'
end
end
So the views are simply htmls - the idea behind it is to use angularjs to render all the thingies provided by a rest api. I guess that's fairly standard.
My problem is - although it works fine for rendering the home page (localhost:3000/), the custom error doesn't work at all; let's say I try localhost:3000/test - the standard "Sinatra doesn’t know this ditty" page is rendered instead.
I'm running padrino 0.12.4 with WEBrick 1.3.1. What am I doing wrong here?
I believe what's going on here is that when you go to localhost:3000/test, your Sinatra app is looking for the "test" action under your App Controller. Obviously this action is not being found because it's not listed as a route! Therefore explicitly tell Sinatra to return a 404 page if the diddy wasn't found:
error Sinatra::NotFound do
content_type 'text/plain'
[404, 'Not Found']
end
I have a Sinatra application that uses the modular style. Everything works fine apart from my error handler blocks which don't get invoked. Here's the relevant code:
app.rb
require_relative './routes/base'
require_relative './routes/routing'
module Example
class App < Sinatra::Application
use Routes::Base
use Routes::Routing
end
end
base.rb
require 'sinatra/base'
module Example
module Routes
class Base < Sinatra::Application
configure do
# etc.
end
# Error pages.
error 404 do # <- Doesn't get invoked.
erb :not_found
end
error 500 do # <- Doesn't get invoked.
erb :internal_server_error
end
end
end
end
routing.rb
module Example
module Routes
class Routing < Base
get '/?' do
erb :home
end
end
end
end
Why don't my error handlers work?
Thanks in advance.
The use method is for adding middleware to an app, you can’t use it to compose an app like this.
In your example you actually have three different Sinatra applications, two of which are being run as middleware. When a Sinatra app is run as middleware then any request that matches one of its routes is handled by that app, otherwise the request is passed to the next component in the Rack stack. Error handlers will only apply if the request has been handled by the same app. The app that you have defined the error handlers in has no routes defined, so all requests will be passed on down the stack — the error handlers will never be used.
One way to organise a large app like this would be to simply use the same class and reopen it in the different files. This other question has an example that might be useful: Using Sinatra for larger projects via multiple files.
I've converted a classic Sinatra application to a modular application. Now suddenly my put, patch and delete routes stopped working. get and post work fine. Is there something I need to do to get these to work in a modular app that is different from classic?
%form{action: "/addsomething", method: 'post'}
%input{type: 'hidden', name: '_method', value: 'put'}
I get a 404 now when I attempt to access one of the above mentioned routes.
require 'sinatra/base'
class MyClass < Sinatra::Base
put '/addsomething' do
'HELLO WORLD!'
end
get '/hello' do
'hello world'
end
end
The method_override setting (that allows the _method field to override the HTTP method) is false by default in modular style. You need to enable it with:
enable :method_override
You can still inherit from Sinatra::Application in the modular style to keep the default settings:
require 'sinatra/base'
class MyClass < Sinatra::Application
put '/addsomething' do
'HELLO WORLD!'
end
get '/hello' do
'hello world'
end
end
I want to verify that a method was called on a service I want to inject into a Sinatra application using rspec but I can't find an example of how this is done. Here is my spec...
RSpec.configure do |config|
config.include Rack::Test::Methods
end
def app
App
end
describe 'Login' do
context 'when the user is logged out' do
describe 'POST on /signup' do
it 'invokes signup on the user service with the correct parameters' do
service = double('user_service').as_null_object
service.should_receive(:signup).with(:username => 'RobA2345')
post '/signup'
end
end
end
end
Here the App is a modular Sinatra app. I come from a .NET background and I'd use constructor injection here to solve this problem but I know this isn't the ruby way to do it.
Help, as always, is appreciated.
Assuming that you're expecting to receive the message on a new instance of UserService, there are a couple of ways to do this. If you are using a recent version of rspec, this should work:
it 'invokes signup on the user service with the correct parameters' do
UserService.any_instance.should_receive(:signup).with(:username => 'RobA2345')
post '/signup'
end
Alternatively, this should work in just about any version of rspec:
it 'invokes signup on the user service with the correct parameters' do
service = double('user_service').as_null_object
UserService.stub(:new).and_return(service)
service.should_receive(:signup).with(:username => 'RobA2345')
post '/signup'
end
Testing a Ruby on Rails application, I have working tests (also asa logged in user), however as soon as I put the ":js=>true" option behind a test
it "does", :js => true do
activate_authlogic
visit '/'
end
a get the web page with an internal error back
You must activate the Authlogic::Session::Base.controller with a controller object before creating objects
How can I get this to work? How can I determine the error more closely?
By now it works for me, I think because of this dirty snippet
module Authlogic
module Session
module Activation
module ClassMethods
def controller
if !Thread.current[:authlogic_controller]
Thread.current[:authlogic_controller] = Authlogic::TestCase::MockController.new
end
Thread.current[:authlogic_controller]
end
end
end
end
end
witch comes from the question SO: authlogic-with-capybara-cucumber-selenium-driver-not-working