Apartment ruby gem : Want to Catch an exception - ruby

I am using this apartment a ruby gem.
I have add this in application.rb file:
config.middleware.use 'Apartment::Elevators::Subdomain'
When i try hit this in browser url 'test.domain.local:3000' where sub domain 'test' schema does not exist in PostgreSQL, i see this error
Apartment::SchemaNotFound (One of the following schema(s) is invalid: test, "public")
I know this is normal behavior of gem but want to catch this exception and redirect user to some other page, how can i do that?

This is what I did:
Create file under lib/rescued_apartment_middleware.rb
module RescuedApartmentMiddleware
def call(*args)
begin
super
rescue Apartment::TenantNotFound
Rails.logger.error "ERROR: Apartment Tenant not found: #{Apartment::Tenant.current.inspect}"
return [404, {"Content-Type" => "text/html"}, ["#{File.read(Rails.root.to_s + '/public/404.html')}"] ]
end
end
end
and add to your Apartment initializer file following lines:
require 'rescued_apartment_middleware'
Rails.application.config.middleware.use 'Apartment::Elevators::Subdomain'
Apartment::Elevators::Subdomain.prepend RescuedApartmentMiddleware
This works like a charm! (Tested with ruby 2.1 and Rails 4.1)

Related

Raising 500 errors deliberately in Sinatra in order to test how they are handled

I want to write an RSpec test which verifies that, should a 500 error occur in my Sinatra-powered API, the error will be caught by a Sinatra error definition and returned to the client in a JSON format. That is, rather than returning some HTML error page, it returns JSON like this to conform with the rest of the API:
{
success: "false",
response: "Internal server error"
}
However, I'm unsure how to actually trigger a 500 error in my Sinatra app in order to test this behaviour with RSpec. I can't find a way to mock Sinatra routes, so currently my best idea is this route which deliberately causes a 500. This feels like a pretty dreadful solution:
get '/api/v1/testing/internal-server-error' do
1 / 0
end
Is there a way to mock Sinatra routes so that I can have, say, /'s route handler block raise an exception, therefore triggering a 500? If not, is there some other way to deliberately cause a 500 error in my app?
When facing a situation like this, what I usually do is separate concerns, and move logic outside of the Sinatra get ... block. Then, it is easy to stub it and make it raise an error.
For example, given this server code:
# server.rb
require 'sinatra'
class SomeModel
def self.some_action
"do what you need to do"
end
end
get '/' do
SomeModel.some_action
end
You can then use this code to have the model, or any other class/function you are using to actually generate the response, raise an error, using this spec:
# spec
describe '/' do
context 'on error' do
before do
allow(SomeModel).to receive(:some_action) { raise ArgumentError }
end
it 'errors gracefully' do
get '/'
expect(last_response.status).to eq 500
end
end
end
For completeness, here is a self contained file that can be tested to demonstrate this approach by running rspec thisfile.rb:
# thisfile.rb
require 'rack/test'
require 'rspec'
require 'sinatra'
# server
class SomeModel
def self.some_action
"do what you need to do"
end
end
get '/' do
SomeModel.some_action
end
# spec_helper
ENV['APP_ENV'] = 'test'
module RSpecMixin
include Rack::Test::Methods
def app() Sinatra::Application end
end
RSpec.configure do |c|
c.include RSpecMixin
end
# spec
describe '/' do
context 'on error' do
before do
allow(SomeModel).to receive(:some_action) { raise ArgumentError }
end
it 'errors gracefully' do
get '/'
expect(last_response.status).to eq 500
end
end
end
Use the halt method:
require 'sinatra'
get '/' do
halt 500, {
success: 'false',
response: 'Internal server error'
}.to_json
end

Configuring rack-test to start the server indirectly

Here is my rack application:
class MainAppLogic
def initialize
Rack::Server.start(:app =>Server, :server => "WEBrick", :Port => "8080")
end
end
class Server
def self.call(env)
return [200, {},["Hello, World"]]
end
end
When actually run, it behaves as it should and returns "Hello World" to all requests. I'm having trouble convincing rack-test to work with it. Here are my tests:
require "rspec"
require "rack/test"
require "app"
# Rspec config source: https://github.com/shiroyasha/sinatra_rspec
RSpec.configure do |config|
config.include Rack::Test::Methods
end
describe MainAppLogic do
# App method source: https://github.com/shiroyasha/sinatra_rspec
def app
MainAppLogic.new
end
it "starts a server when initialized" do
get "/", {}, "SERVER_PORT" => "8080"
last_response.body.should be != nil
end
end
When I test this, it fails complaining that MainAppLogic is not a rack server, specifically, that it doesn't respond to MainAppLogic.call. How can I let it know to ignore that MainAppLogic isn't a rack server and just place a request to localhost:8080, because there server has started?
First thing: why the custom class to run the app? You can use the rackup tool, which is the de-facto standard for running Rack apps. Some more details on it here.
Your app code then becomes:
class App
def call(env)
return [200, {}, ['Hello, World!']]
end
end
and with the config.ru
require_relative 'app'
run App.new
you can start the app by running rackup in your project's directory.
As for the error, the message is pretty clear. rack-test expects, that the return value of app method would be an instance of a rack app (an object that responds to call method). Take a look what happens in rack-test internals (it's pretty easy to follow, as a tip—focus on these in given order: lib/rack/test/methods.rb#L30 lib/rack/mock_session.rb#L7 lib/rack/test.rb#L244 lib/rack/mock_session.rb#L30. Notice how the Rack::MockSession is instantiated, how it is used when processing requests (e.g. when you call get method in your tests) and finally how the call method on your app is executed.
I hope that now it's clear why the test should look more like this (yes, you don't need to have a server running when executing your tests):
describe App do
def app
App.new
end
it "does a triple backflip" do
get "/"
expect(last_response.body).to eq("Hello, World")
end
end
P.S.
Sorry for the form of links to rack-test, can't add more than 2 with my current points :P
Your app should be the class name, for example instead of:
def app
MainAppLogic.new
end
You have to use
def app
MainAppLogic
end
You shouldn't need to indicate the port for doing the get, because the rack app runs in the context of the tests; so this should be right way:
it "starts a server when initialized" do
get "/"
last_response.body.should be != nil
end
Also, as a recommendation prefer to use the new expect format instead of the should, see http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
And your MainAppLogic, should be something like:
class MainAppLogic < Sinatra::Base
get '/' do
'Hello world'
end
end

Remote_table in spree 0.70.7 controller: #<TypeError: Zip is not a module>

I'm include gem 'remote_table' in my Gemfile (Rails 3.1.12)
In spree admin i'd create new controller:
class Admin::XlsPriceLoadsController < Admin::BaseController
def upload
source_xls = RemoteTable.new(filename)
source_xls.each do |row|
....
end
end
end
but when this action fired, i'm see the next:
TypeError (Zip is not a module):
app/controllers/admin/xls_price_loads_controller.rb:26:in `upload'
...
when i'm explore the source_xls object, a frozen? property of them is true.
So, can any soul write me, why the parsed object is frozed?
And, if i run this code
source_xls = RemoteTable.new(filename)
source_xls.each do |row|
....
end
from lib/tasks as rake task - all work fine!
Thanks for all advice!
Whereabouts does the filename method/attribute come from? Is that something from spree? What value does it have at the point #upload is called?
Regarding
app/controllers/admin/xls_price_loads_controller.rb:26:inupload'`
What's on line 26?

Ldap gem throws no connection to server exception in Rails

Trying to establish a connection from a module in Rails and get no connection to server. I have tested the same code outside Rails and it works fine.
require 'rubygems'
require 'net-ldap'
module Foo
module Bar
class User
attr_reader :ldap_connection
def initialize
#ldap = Net::LDAP.new(:host => "<ip-number>", :port => 389)
#treebase = "ou=People, dc=foo, dc=bar"
username = "cn=Manager"
password = "password"
#ldap.auth username, password
begin
if #ldap.bind
#ldap_connection = true
else
#ldap_connection = false
end
rescue Net::LDAP::LdapError
#ldap_connection = false
end
end
end
end
end
Getting Net::LDAP::LdapError: no connection to server exception.
I found a solution/workaround for my problem with auto-loading in Rails. Added a new initializer to ensure that all Ruby files under lib/ get required:
Added config/initializers/require_files_in_lib.rb with this code
Dir[Rails.root + 'lib/**/*.rb'].each do |file|
require file
end
Read more about the workaround: Rails 3 library not loading until require

ruby on rails 3.1 global exception handler

I'm developing an app with Rails 3.1.2 but I can't find some documentation that works with errors / exception (like 404) on this version of rails.
i have tried things like:
In application controller
rescue_from ActiveRecord::RecordNotFound,ActionController::RoutingError,
ActionController::UnknownController, ActionController::UnknownAction, :NoMethodError, :with => :handle_exception
def handle_exception
render :template => 'error_pages/error'
end
environment/development.rb
config.consider_all_requests_local = false
Where can I find a solution?
Thanks in advance...
This should work:
In application controller
class NotFound < StandardError; end
rescue_from NotFound, :with => :handle_exception
def handle_exception
render :template => 'error_pages/error'
end
Look at action_dispatch/middleware/show_exceptions.
From the documentation in the source:
# This middleware rescues any exception returned by the application
# and wraps them in a format for the end user.
Short story short, it renders ActionDispatch::ShowExceptions.render_exception when the wrapped application (Rails, in your case), encounters an unrescued exception.
If you look through the default implementation, it ends up rendering something like public/500.html, which is what you see in the production environment. Overwrite the method or method chain it as you see fit to add your own implementation.

Resources