Two Sinatra Apps, shared datamapper DB - ruby

I'm trying to think of a good way of using Sinatra and Datamapper to create a solid web app that shares a database. I started using just one app, but I'm thinking about splitting the admin aspect to it's own app with a different mapping in a config.ru file.
So, config.ru will map the root route to the main app, and '/admin' to the Admin app. The main app will be responsible for showing data from the db to any user, and the Admin app is responsible for allowing admins to add content to the db. My reasoning behind this is to allow me more flexibility and reusability with the admin app.
The main app has the Datamapper classes responsible for defining my model, though I am sure I could move that to the admin app without a problem. Is there a way/reason to move it to it's own separate .rb file?
Obviously new to this platform, but I'm loving it. Any help is greatly appreciated.

You can have one project with as many sinatra apps as you like. for your project, you can set it up like this:
# site.rb
require 'config/boot'
class Site < Sinatra::Base
...
end
# admin.rb
require 'config/boot'
class Admin < Sinatra::Base
...
end
# config/boot.rb
require 'model/user.rb'
require 'model/post.rb'
# config.ru
require 'admin'
require 'site'
run Rack::URLMap.new("/" => Site.new, "/admin" => Admin.new)
The key is to put both apps in the same project / version control.

Related

serving static files on sinatra

I'm working on a Sinatra app for the first time and am stumbling into an issue with serving a javascript asset.
I am following the Sinatra convention of putting the static files in “public” folder and it works locally but when we create a Docker image, we get a 404 while this works with localhost.
I see where I can set the public_folder which I have tried like this:
http://sinatrarb.com/configuration.html
but still 404'ing. Is there a way to get the top-level object and ask it where it expects the public_folder to be (like Rails.env)?
You can check the settings object.
irb(main):001:0> require "sinatra"
=> true
irb(main):002:0> settings.public_folder
=> "/usr/lib/ruby/2.5.0/irb/public"
This allows you to create a route which returns the path, something like this
require 'sinatra'
get '/' do
settings.public_folder
end
Without more information I would guess that your public folder points to a wrong directory inside your docker because the project :root points to a different directory that what you expect.

How to migrate a modular Sinatra app to AWS Lambda

I have a modular Sinatra app that runs fine under rackup, that is with a config.ru that has three 'use' statements and one run statement. I am trying to get my head around how to port the application to AWS lambda where API_gateway will provide web server services and just call my app.
I am using the recommended lambda.rb script from https://github.com/aws-samples/serverless-sinatra-sample/blob/master/lambda.rb as my entrypoint. What I don't get is how, in the AWS Lambda micro-clime, do I assemble the modules/layers of my application without rackup and config.ru?
I assume that my noob brain is just missing something really basic in spite of the fact that I have read every blog post, bit of Sinatra and Rack documentation I know of, and the great "Sinatra Up and Running" book. What am I missing?
Upon re-reading the book, "Sinatra: Up and Running" again, it seems that there is a fairly elegant solution. If I set up my lambda.handler entrypoint to point to a simple Sinatra router, then it will be the router that composes the individual controllers into a 'system' which will handle all of my end points. the example from the book:
Example 4-32. Using Sinatra as router
require 'sinatra/base'
class Foo < Sinatra::Base
get('/foo') { 'foo' }
end
class Bar < Sinatra::Base
get('/bar') { 'bar' }
end
class Routes < Sinatra::Base
get('/foo') { Foo.call(env) }
get('/bar') { Bar.call(env) }
end
run Routes
Of course, in my case, I won't need the 'run Routes' line. I will just have my lambda.handler call Routes, as in Routes.call. This seems very doable!

Strange issue in Sinatra

ok so this is very strange (well is to me), everything in my master branch works fine, I then created a new branch called twitter to conduct some twitter feed implementation. I have done this and was working yesterday on my linux machine.. I have pulled the branch today in a windows environment but when i load the app i now get the regular Sinatra 404 Sinatra doesn’t know this ditty.
This is my profile.rb file
require 'bundler/setup'
Bundler.require(:default)
require 'rubygems'
require 'sinatra'
require './config/config.rb' if File.exists?('./config/config.rb')
require 'sinatra/jsonp'
require 'twitter'
require 'sinatra/static_assets'
class Profile < Sinatra::Base
helpers Sinatra::Jsonp
enable :json_pretty
register Sinatra::StaticAssets
##twitter_client = Twitter::Client.new(
:consumer_key => ENV["CONSUMER_KEY"],
:consumer_secret => ENV["CONSUMER_SECRET"],
:oauth_token => ENV["OAUTH_TOKEN"],
:oauth_token_secret => ENV["OAUTH_SECRET"],
)
get '/' do
erb :index
end
get '/feed' do
jsonp ##twitter_client.user_timeline('richl14').map(&:attrs)
end
end
Config.ru
require './profile'
run Profile
Does anyone have any ideas of what i need to be looking at to solve this? Can anyone speak from experience with this?
Thanks
When you use the classic Sinatra style you use require 'sinatra' and then add routes to the top level. These routes get added to the Sinatra::Application. When you directly run this file, e.g. with ruby my_app.rb, Sinatra runs a built in web server, which will serve the Sinatra::Application app.
When you use the modular style, you use require 'sinatra/base', and then add routes to your Sinatra::Base subclass. In this case directly executing the file doesn’t start the built in server.
In your case you are using the modular style, but have used require 'sinatra'. You create your Profile app, but when you run the file directly Sinatra launches the built in server and serves the Sinatra::Application app. Since you haven’t added any routes to this (they’ve all been added to Profile) it runs but all requests return 404.
One way to get your app to launch you is to use rackup. This will launch the Profile app that you have explicitly set in your config.ru. (Explicitly starting your webserver will also work, e.g. using thin start).
Another possibility would be to add a line like this to the end of your Profile class:
run! if app_file == $0
This tells Sinatra to start the build in server running the Profile app if the file is the same as the Ruby file being executed, in a similar way to how the classic style app is launched. If you use this method you should change require 'sinatra' to require 'sinatra/base' otherwise you will get two servers launched, one after the other (in fact you should probably make that change anyway).
See the Sinatra docs for more info about the difference between classic and modular style.

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.

Resources