Can't load my custom module in Sinatra - ruby

I am trying to load my custom module in Sinatra but when loading the app I get
'include' : Wrong argument type String (expected Module)
So in my app.rb I have
require './config/config.rb'
include 'MyConfig'
and my Module looks like so
module MyConfig
def config
environment = ENV["RACK_ENV"] || "development"
YAML.load_file("/config/config.yml")[environment]
end
end
I am trying to use the config.yml file to load some variables (i.e email credentials).
What am I doing wrong?

include is not like require. Include must be part of another class or Module body.
Do this:
require './config/config.rb'
class App
include MyConfig
# more code here
end
Include basically functions as an inline extension of the class or module that is currently in scope. It allows you to mix functionality into objects from external code without extending that external code.

Related

Sinatra method `development?` undefined

The Sinatra docs say that development? will return true when the environment is development, but I receive an error stating that the method development? is undefined.
I tried skipping the shorthand and testing the ENV['RAKE_ENV'] variable itself, but it was just nil.
This is the error I'm getting:
undefined method `development?' for main:Object (NoMethodError)
and this is the code that is triggering the error:
require 'dm-sqlite-adapter' if development?
I am using the modular style app. The line above is an separate file that only manages the model. What's going on?
I struggled with this one, too. Here's what I discovered along the way.
You need to be "inside" a class that inherits from Sinatra::Base (such as Sinatra::Application, which inherits from Base) to be able to use the development? method, which is defined in base.rb.
In a classic Sinatra app you are already coding "inside" a class that inherits from Sinatra::Base. So development? will just work "anywhere".
In modular Sinatra the development? will only work in Sinatra::Base sub-classes, such as:
require 'sinatra/base'
# Placing
# require 'dm-sqlite-adapter' if development?
# here will not work.
class ApplicationController < Sinatra::Base
require 'dm-sqlite-adapter' if development? # But here it works
...
end
# Placing
# require 'dm-sqlite-adapter' if development?`
# AFTER the above class will still not work
class SomethingElse
# nor will `development?` work here, since it is called inside
# a class without Sinatra::Base inheritance
...
end
So basically you can use an ApplicationController class that inherits from Sinatra::Base and inside here check for development?. The same goes for sub-classes that inherits from your ApplicationController class:
class UserController < ApplicationController
require 'dotenv' if development?
...
end
For modular Sinatra, in the (main:Object) code text "outside" Sinatra::Base sub-classes, you need to follow Arup's instructions:
if Sinatra::Base.environment == :development
require 'awesome_print'
require 'dotenv'
Dotenv.load
...
end
Since you are using the modular style, you need to add the module namespace Sinatra::Base before the method.
So you will be able to access Sinatra::Base.development? anywhere in the app.

Error handlers don't run in modular Sinatra app

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.

Which is the right path to place an initializer in a Padrino sub application

I'm working with OmniAuth-Facebook and initializing it in mysubapp/app.rb:
require 'omniauth-facebook'
class MySubApp < Padrino::Application
register Padrino::Rendering
register Padrino::Mailer
register Padrino::Helpers
enable :sessions
SCOPE = 'email,read_stream'
ENV['APP_ID'] = '111111111111111'
ENV['APP_SECRET'] = '11111111111111111111111111111111'
use OmniAuth::Builder do
provider :facebook, ENV['APP_ID'], ENV['APP_SECRET'], :scope => SCOPE
end
end
I just want to know if this is the way you should work with Padrino. Is this the right place to put my initializers or, maybe, you can create an specific sub-application config.ru?
Placing code into boot.rb for multi-app deployments, or in the apps app.rb is the correct place to put things.
If you like things looking cleaner you could create a new config/initializers directory then add the following to boot.rb
Padrino.require_dependencies "#{Padrino.root}/config/initializers/**/*.rb"
Here is the Padrino guide for Special Folders which as a little bit more about loading or requiring additional paths.

Using custom classes with Sinatra

I'm developing a Sinatra application. To simplify the structure for an easier future support I added a few custom classes, located in separate files. What I'm trying to do is to make them use existing helpers and sinatra's own functionality (models, sessions, etc) without repeating the code.
For example, I have a helper to_html(text) and I'd like to use it both inside sinatra routes and in my own classes, which are also to be used inside routes.
My sinatra app is written in classic style (if it matters for your suggestion).
Is it possible?
Assuming you have a helpers directory in the root of the project, you could do something like this from inside your app file you use to run the server.
%w(helpers).each { |p| Dir[File.join(File.dirname(__FILE__), p, "*.rb")].each { |file| require file } }
You will need to include your routes below this for it to work. To make this even cleaner, you can also have a routes/controllers directory. Simply add 'routes' to that array as such:
%w(helpers routes).each { |p| Dir[File.join(File.dirname(__FILE__), p, "*.rb")].each { |file| require file } }
This will require all of your helpers THEN your routes.

Why is "url_for" undefined in my application?

I'm trying to use the url_for extension so my app can accurately find my static assets (tried the static assets extension as well, but it also complained of this same problem).
The problem is this:
undefined method `url_for' for Sinatra::Raffler:Class (NoMethodError)
Now, I've got the required modules listed, as per the url_for README:
require 'rubygems'
require 'sinatra/base'
require 'data_mapper'
require 'lib/authorization'
require 'pony'
gem 'emk-sinatra-url-for'
require 'sinatra/url_for'
But I'm still getting the NoMethodError when I try to call url_for
I have tried a couple of different things in regards to helpers. First, I have a helpers block for an authorization extension:
helpers do
include Sinatra::Authorization
end
So, I thought I could include the url_for helper in there:
helpers do
include Sinatra::Authorization
include Sinatra::UrlForHelper
end
But that didn't resolve the issue, so I just added the line:
helpers Sinatra::UrlForHelper
after that initial helpers do block, but still no resolution.
If you are subclassing Sinatra::Base, you need to include the helpers explicitly:
class Foobar < Sinatra::Base
helpers Sinatra::UrlForHelper
end

Resources