Sinatra App Template

A quick and dirty template for Sinatra apps with many of the features you can find in Rails. Supports: \* Slim views \* Sass stylesheets \* Coffee script \* [Compass](compass-style.org) \* Susy ([susy.oddbird.net](http://susy.oddbird.net)) \* Asset pipeline (Sprockets) \* View helpers \* A console \* I18n \* Logging \* ActiveRecord+migrations \* Debugging with Pry \* Flash messages \* Class reloading in development mode \* Security features such as CSRF, Cross Site Scripting, etc. All provided by Rack::Protection and Sinatra. Create app.rb: ```ruby require 'slim' require 'i18n' require 'mysql2' require 'sprockets' require 'sprockets-sass' require 'compass' require 'susy' require 'sinatra/base' require 'sinatra/cookies' require 'sinatra/content_for' require 'sinatra/activerecord' require 'sinatra/partial' require 'rack-flash' class App < Sinatra::Base enable :sessions, :logging register Sinatra::Partial use Rack::MethodOverride use Rack::Flash, :accessorize => [:info, :error, :success], :sweep => true use Rack::Protection::AuthenticityToken # HTML forms now require: input name="authenticity_token" value=session[:csrf] type="hidden" set :public_folder, File.dirname(__FILE__) + '/public' set :views, File.dirname(__FILE__) + '/app/views' set :slim, :layout_engine => :slim, :layout => :'layouts/default', :use_html_safe => true, :pretty => App.environment == :development set :partial_template_engine, :slim set :session_secret, "25729f31a6bc7c57f8575db9b79ee468...." # SecureRandom.hex(128) set :cookie_options, { path: '/'} def self.sprockets project_root = File.expand_path(File.dirname(__FILE__)) assets = Sprockets::Environment.new(project_root) assets.append_path('app/js') assets.append_path('app/css') # Twitter Bootstrap... assets.append_path('lib/bootstrap/js') assets.append_path('lib/bootstrap/css') assets end helpers Sinatra::Cookies helpers Sinatra::ContentFor helpers do def t(*args) ::I18n::t(*args) end def authenticity_token session[:csrf] = SecureRandom.hex(128) unless session.has_key?(:csrf) %Q{} end end configure do # Configure logging, WTF set :logging, false class ::Logger; alias_method :write, :<<; end logfile = File.join(App.root, 'log', "#{App.environment}.log") # Send STDs to log file $stdout.reopen(logfile) $stderr.reopen(logfile) $stderr.sync = true $stdout.sync = true # Weekly roll log = Logger.new(logfile, 'weekly') log.level = Logger::DEBUG # use Rack::CommonLogger, log set :log, log Compass.add_project_configuration(File.join(Sinatra::Application.root, 'config', 'compass.rb')) end configure :development do require "sinatra/reloader" register Sinatra::Reloader also_reload 'app/**/*.rb' also_reload 'lib/**/*.rb' also_reload 'conf/**/*.rb' set :raise_errors, true end [:error, :info, :success].each do |key| class_eval " def flash_#{key}(key, now=true) message(key, :#{key}, now) end " end def message(key, type=:notice, now=true) hash = now ? flash.now : flash hash[type] = I18n.t(key) end # Set view variables, e.g.: # - meta :title, "Page title" # Retrieve view variables, e.g.: # = meta :title def meta(key, value = nil) value ? content_for(key) { value } : yield_content(key) end # Helper method for creating HTML tags: # content_tag :a, 'Contact us', href: 'mailto:[email protected]' def content_tag(name, content, attributes = nil) name = html_escape(name) unless name.html_safe? content = html_escape(content) unless content.html_safe? attributes = attributes.map do |name, value| value = html_escape(value) unless value.html_safe? %Q{#{name}="#{value}"} end if attributes && attributes.any? start = [name, attributes.join(" ")].reject(&:nil?).join(' ') "<#{start}>#{content}" end def debug_something_with_pry Kernel.binding.pry end error do slim :'errors/500' end not_found do slim :'errors/404' end error ActiveRecord::RecordNotFound do slim :'errors/404' end before do I18n.locale = params[:locale] || I18n.default_locale end end # Require attr_accessible... ActiveRecord::Base.send(:attr_accessible, nil) # Move to config/init/db.rb if you like OpenStruct.new(YAML::load(File.open('config/database.yml'))[App.environment.to_s].symbolize_keys).tap do |config| ActiveRecord::Base.establish_connection( host: config.host, adapter: config.adapter, database: config.database, username: config.username, password: config.password ) end %w(models controllers concerns).each do |name| Dir[File.join('app', name, '**/*.rb')].each do |file| require_relative file end end # Move to config/init/i18n.rb if you like Dir[File.join(App.root, 'config', 'locales', '*.yml')].each do |file| I18n.backend.load_translations(file) end I18n.default_locale = :en # Move to app/controllers/root_controller.rb class RootController < App get '/' do flash_alert "Thanks for nothing" slim :'index' end end ``` Create Gemfile: ```ruby source :rubygems gem 'thin' gem 'slim' gem 'sass' gem 'sinatra' gem 'sprockets' gem 'sprockets-sass' gem 'compass' gem 'susy' gem 'sinatra-partial' gem 'coffee-script' gem 'therubyracer' group :development do gem 'sinatra-reloader' gem 'sinatra-activerecord' gem 'pry' end gem 'rack-flash3' gem 'awesome_print' gem 'mysql2' ``` Create Rakefile: ```ruby require 'bundler/setup' require 'sinatra/activerecord/rake' require 'pry' require './app' Dir[File.join('lib', 'tasks', '**', '*.rake')].each do |file| import file end task :console do binding.pry end # Asset pipeline (Sprockets) namespace :assets do task :precompile do App.sprockets['application.js'].write_to('public/assets/application.js') App.sprockets['application.css'].write_to('public/assets/application.css') end end ``` Create config/database.yml: ```ruby development: adapter: mysql2 database: xxx_development username: root password: host: localhost ``` Create config.ru: ```ruby require './app' map "/" do run RootController end map "/assets" do run App.sprockets end ``` Run: ```ruby mkdir -p app/controllers app/models app/concerns app/views/layouts app/css app/js lib tmp log public/img config/init db/migrate lib/tasks bundle bundle exec thin start -p 3000 ```