Define sinatra request routes in included files - ruby

I am using Sinatra and I would like to have my project structed in a way that keeps all requests for a specific action in separated files.
The problem I'm running into is that the routes aren't registered with sinatra, and it always 404s and runs my not_found handler, even though I've included a file with the route.
Here's an example of what I'm trying to achieve; Rackup would start the Info app which requires user and post. Info only contains a error and not found handler, and the related routes go in the corresponding required file.
config.ru:
require 'rubygems'
require 'bundler'
Bundler.require
require 'rack'
require './info.rb'
run Info
info.rb:
require 'rubygems'
require 'bundler'
require 'sinatra'
class Info < Sinatra::Base
require './user.rb'
require './post.rb'
# 500 handler
error StandardError do
status 500
content_type :json
return '{"error": "Internal server error", "code": 500}'
end
not_found do
status 404
content_type :json
return '{"error": "Page not found", "code": 404}'
end
end
And user.rb (post.rb would look the same):
require 'rubygems'
require 'bundler'
require 'sinatra'
get '/1/user/:userid' do
# request stuff
end

require doesn’t work the way you seem to think it does. When you call require './user.rb', even though you do it inside the body of class Info < Sinatra::Base, its contents are not loaded as if they were inside that class. Instead they are parsed at the top level, and the routes are added to the default Sinatra::Application and not your application class.
You will have to have your user and post routes defined inside the same class body:
#info.rb
require 'sinatra/base' # Require 'sinatra/base' if you are using modular style.
class Info < Sinatra::Base
# It's a bit unusual to have require inside a class, but not
# wrong as such, and you might want to have the class defined
# before loading the other files.
require_relative 'user.rb' # require_relative is probably safer here.
require_relative 'post.rb'
# ... error handlers etc.
end
#user.rb
require 'sinatra/base'
# The routes need to be in the same class.
class Info < Sinatra::Base
get '/1/user/:userid' do
# request stuff
end
end

Related

Sinatra I18n Fallbacks using Rack::Locale

I'm trying to set up a simple Sinatra app with I18n, following the recommended Sinatra recipe, and using Rack:Locale to determine the language.
My app.rb:
require 'rubygems'
require 'sinatra'
require 'rack/contrib'
require 'i18n'
require 'i18n/backend/fallbacks'
require 'tilt/haml'
use Rack::Locale
configure do
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
I18n.load_path = Dir[File.join(settings.root, 'locales', '*.yml')]
I18n.backend.load_translations
end
helpers do
def t(*args)
I18n.t(*args)
end
end
get '/' do
haml :index
end
My locales/en.yml:
en:
welcome: "Welcome!"
When I run rackup and visit the root path of my Sinatra app, I get the following:
I18n::InvalidLocale at /
"en-US" is not a valid locale
file: i18n.rb location: enforce_available_locales! line: 284
I thought that the I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) would handle this, by not finding en-US and falling back to en (which I have), but apparently not. What am I missing?
Add:
I18n.enforce_available_locales = false

How to set authentication in Sinatra?

I need simple authentication for blog. For a single person. Just login to the website
Can't configure sinatra_warden. Write the line
require 'rubygems'
require 'sinatra'
require 'pry-byebug'
require "sinatra/activerecord"
require "carrierwave"
require "carrierwave/orm/activerecord"
require 'sinatra_warden'
require 'warden'
register Sinatra::Warden
use Rack::Session::Pool
in app.rb, but I get an error
NoMethodError: undefined method `register' for main:Object
the gem sinatra_warden has installed. as well written require "warden" & require "sinatra_warden"
sinatra_warden 0.3.2
warden 1.2.6
When I add the authorize! method in controller, I get an error
undefined method `authorize!'
Because you didn't use the sinatra/base you should add sinatra/namespace. Add to your app.rb this require require "sinatra/namespace".
Sinatra::Namespace is an extension that adds namespaces to an
application. This namespaces will allow you to share a path prefix for
the routes within the namespace, and define filters, conditions and
error handlers exclusively for them. Besides that, you can also
register helpers and extensions that will be used only within the
namespace.
Or change your application to the modular style:
require "sinatra/base"
class MyApp < Sinatra::Base
register Sinatra::Warden
# The rest of your modular application code goes here...
end

route giving 404 in sinatra

I have just started working on sinatra, now my application is not able to navigate upto route and get data from db, I am always getting 404. This is what I am doing.
File Structure
app
|---->helpers
|----->models
|----->public
|----->routes
| |------->candidate.rb
| |------->init.rb
|----->app.rb
|----->config.ru
config.ru
require './app'
run MyApp
app.rb
require 'json'
require 'sinatra'
require 'data_mapper'
require 'dm-migrations'
require 'sinatra/cross_origin'
require 'logger'
require './models/init'
require './helpers/init'
require './routes/init'
class MyApp < Sinatra::Base
configure :development do
enable :cross_origin
DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(
:default,
'mysql://root:#localhost/hackerrank'
)
end
get '/' do
File.read(File.join('public', 'index.html'))
end
DataMapper.finalize
end
Command
bundle exec rackup -p 4567 config.ru
api in candidate.rb are correct but if i try to access the resource as http://localhost:4567/#/recruiter I am getting 404 .
I am not able to figure out what is wrong I am doing here.
You're getting a 404, since GET '/' only works for the root page and you're trying to load /recruiter. You can change it to GET '/:pagename' and that would fix the 404 problem instantly.
Your codebase looks fine. When you're running your Sinatra app from the terminal, each request shows a log line such as
127.0.0.1 - - [02/Jan/2016 00:43:53] "GET / HTTP/1.1" 200 - 0.0033
Ensure that the HTTP verb and or endpoint/route you see is the one you are expecting (perhaps you are making a POST request when accessing the resource?)

Sinatra commands do not work in modules

I have a Sinatra app which requires a module in a different file. When I use Sinatra commands in that module (e.g. redirect "http://facebook.com"), I get a NoMethodError. To illustrate the problem, I have made a simplified version:
--- mainapp.rb ---
#config
require './redirector.rb'
get '/' do
Redirector::redirect_to_stackoverflow
end
--- redirector.rb ---
module Redirector
require 'sinatra'
def self.redirect_to_stackoverflow
redirect "http://stackoverflow.com"
end
end
--- config.ru ---
require 'rubygems'
require 'sinatra'
require File.dirname(__FILE__) + "/ptt.rb"
run Sinatra::Application
What is wrong? Is there a place where I haven't required something properly?
The call to redirect inside the Redirector module is sent to the Redirector Module object, where the method does not exist. require 'sinatra' inside module Redirector is not necessary, and does not do any kind of method composition.
You probably could compose Sinatra methods into your Redirector module, but that is not normal practice. Usually it's the other way around - you write "helper" modules that are composed in to your Sinatra application in various ways.
This is a similar example application, with a more usual approach to composition:
app.rb
require 'sinatra'
require_relative 'redirect.rb'
class MyApp < Sinatra::Application
include Redirector
get '/' do
redirect_to_stackoverflow
end
end
redirect.rb
module Redirector
def redirect_to_stackoverflow
redirect "http://stackoverflow.com"
end
end
config.ru
require File.dirname(__FILE__) + "/app.rb"
run MyApp
#Neil Slater's explanation is correct, but I'd suggest you also make it an Sinatra extension, e.g.
require 'sinatra/base'
module Sinatra
module Redirector
def redirect_to_stackoverflow
redirect "http://stackoverflow.com"
end
end
helpers Redirector
end
Then (for a classic app) all you need to do is require it.
require 'sinatra/redirector'
get "/" do
redirect_to_stackoverflow
end

issues finding public folder when requiring sinatra/base

I have found that in my Sinatra app, when I require 'sinatra', I can access my public folder as expected, but when I require 'sinatra/base' I can't. Here is my relevant code (which works until I change to /base):
config.ru
root = ::File.dirname(__FILE__)
require ::File.join( root, 'app' )
run MyApp.new
app.rb
require 'sinatra'
require 'sinatra/namespace'
require 'haml'
class MyApp < Sinatra::Application
# ...
end
require_relative 'models/init'
require_relative 'helpers/init'
require_relative 'routes/init'
script.haml
%script(type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js")
%script(type="text/javascript" src="/js/table.js")
%link(rel="stylesheet" type="text/css" href="/css/table.css")
And yes, I have the correct directory structure in place. Like I said, it works using require sinatra. Anyone know why this is occurring and what I can do to fix it?
Requiring Sinatra::Base does not set any of the default configuration settings that requiring Sinatra does. You'll need to set :public_folder ... to a suitable value yourself, e.g:
set :public_folder, 'public'

Resources