Rails Sinatra 的 app 模板,提供一些胶水代码支持类似 Rails 的体验

Mark24 · September 14, 2021 · Last by crazyjacky replied at September 17, 2021 · 677 hits

Sinatra 的 app 模板,提供一些胶水代码支持类似 Rails 的体验

如果你想灵活的开展工作,又觉得 Rails 过于庞大(比如 Rails6+ 携带一个 Node)、文档要读很久,正在犹豫当中。

你恰巧知道 Sinatra 的存在,15 分钟读完的 Sinatra/README 又觉得自己行了,可是 Sinatra 似乎太简单了,你想要是 Sinatra 有 MVC 和开箱即用的 ORM 就好了。

这是最近做一个简单后端项目的沉淀,可以作为一个简单的起点。

一切基于 Sinatra+Rack,用一些胶水代码 把 Rack/Sinatra + 配置 + 文件目录 联系在一起开始工作。容易更改,简单明了。

分享一下,可能不够成熟,欢迎碰撞,让我可以学习更多~

github:https://github.com/Mark24Code/sinatra-app-template

geeknote: https://geeknote.net/mark24/posts/283

Sinatra App Template

Lightweight web framework codebase. Just clone and develop on it.

Tech component: Rack+Sinatra+Sequel and default use Postgresql database.

Add rails-like migration command line helpers.

Openbox Features

Apps

  • [x] Multi Env Configuration
  • [x] Multi router DSL base on Rack
  • [x] CORS support
  • [x] Hot reload
  • [x] Custom logger
  • [x] ORM base on Sequel'

Tasks

  • [x] Rails-like migration helpers
  • [x] Test
  • [x] Seed

CI&CD

  • [x] Dockerfile

Find helpful rake tasks

rake or rake -T

Run server & develop

rake server:run

Production Server & deploy

APP_ENV=production bundle exec rake server:run

you can also use docker

docker built -t <what your docker image label> .

Custom server & database

You can use DSL to config Key:Value , then you application just use.

Config::Default.configure do
  set :app_env, ENV.fetch('APP_ENV'){ 'development' }
  set :bind, ENV.fetch('HOST') { '0.0.0.0' }
  set :port, ENV.fetch('PORT') { 3000 }
  set :secrets, ENV.fetch('SECRETS') { 'YOU CANNOT GUESS ME' }
  set :max_threads, ENV.fetch('MAX_THREADS') { 5 }

  set :database_url, ENV['DATABASE_URL']
end

Config::Development.configure do 
  set :database_url, 'ENV['DATABASE_URL']'
end

Config::Test.configure do 
  set :database_url, ENV['DATABASE_URL']
end

Config::Production.configure do 
  # set :database_url, ENV['DATABASE_URL']
end

They have an inheritance relationship

Development < Default
Test < Default
Production < Default

In your code, just use Config directly. core/bootstrap do a work that loaded all necessery mods before your code.

Config.current  # current env configuration

Config::Development.database_url

Config::Development

Config::Development.database_url

You can also create your own Config for your single Application:

class MyConfig < Config::Base

end

MyConfig.configure do 
  # set :database_url, ENV['DATABASE_URL']
end

Mount different Sinatra web application

Edit config.ru

Lark also is Rack application. We can use Rack middlewares.

require_relative './cores/bootstrap'
Bootstrap.rack 

# you can load Rack middleware here

# mount applications
require 'controllers/root_controller'
# routers(handy config)
map '/' do
  run RootController 
end

Base

bases directory are use for Application Base Class.

You can make different Configured Sinatra Application class here, then your application/controller just inherit the Base Class to create Application.

It will share Config, and make less code.

# Sinatra Doc http://sinatrarb.com/intro.html
require 'sinatra/base'
require 'json'

class BaseController < Sinatra::Base
  # Inject config

  # Config & register Sinatra Extensions

  # Rewrite Views dir
  settings.views = File.expand_path(File.join($PROJECT_DIR, 'views'))

  configure :development do
    require 'sinatra/reloader'
    register Sinatra::Reloader
  end

  # mount Sinatra Helpers

  # mount Sinatra middlewares

end


# Share Configuration

class MyPageServer < BaseController
end

class MyApiServer < BaseController
end

ORM & Tools

Provide rails-like rake task help you build app quickly.

rake db:check                   # Checking for current migrations
rake db:connect                 # Connect database
rake db:console                 # Database Console
rake db:create[database_name]   # Create database
rake db:create_migration[name]  # Create a migration
rake db:drop[database_name]     # Drop database
rake db:ls                      # List database tables
rake db:migrate[version]        # Run migrations
rake db:rollback[version]       # Rollback to migration
rake db:version                 # Prints current schema version
rake list                       # List all tasks
rake seed:all                   # Seed: run all seeds
rake seed:run[seed_name]        # Seed: run seed
rake server:run                 # Run server
rake test                       # Run tests

Project Structure

.
├── Dockerfile # Common Dockerfile
├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile # Rake Task Index File.
├── bases # Base configured class. You can make different BaseClasses then reuse them.
│   └── base_controller.rb # You contoller can inherit it or write yourself.
├── config.ru # Application index. You can mount controllers and routes here.
├── configs # You can make different configs for applications
│   └── config.rb # Base config
├── controllers 
│   └── root_controller.rb
├── cores # Inject ENVS and autoloads files, make MVC works
│   ├── 01_config.rb # Names can controller mount order
│   └── bootstrap.rb
├── dbs # You can make multi database here
│   ├── default_db.rb # default database connect instance
│   └── migrations # save database migrations
├── docs
│   └── good.feature
├── log # Directory for save logs by default
│   └── development.log
├── loggers # Loggers for application
│   └── default_logger.rb
├── public # Public resources
│   └── favicon.svg
├── seeds # Seeds
├── tasks # Rake helpful tasks 
│   ├── db_task.rb
│   ├── seed_task.rb
│   ├── server_task.rb
│   └── test_task.rb
├── tests # Test cases
│   └── test_demo.rb
└── views # views template
    ├── base.erb
    └── root.erb

Bootstrap & Load orders

For Rake

require_relative './cores/bootstrap'
Bootstrap.rake

It will auto load files make sure rake task can work.

In rake we can use Config.current to read configuration.

DB also available.

For Rack/Applications

In the same way

require_relative './cores/bootstrap'
Bootstrap.rack
# OR
# Bootstrap.apps

It will autoload all dep mods. Share with a context.

Change load orders

cores/bootstrap.rb defines different load orders, you can change.

In anther way, you can change filename to e.g 00_before_all.rb01_first_load.rb to control mods load order.

sinatra 用 ar+reloader+slim 很少的代码实现拍黄片一大堆代码的效果,流行不起来的原因,主要是 DSL 写法太花哨了,各种花式 set/use ,

get :sample, :map => '/sample/url', :provides => [:any, :js] do
   case content_type
     when :js then ...
     else ...
end

这些写法 要拿个小本本记下来, 不报错一切太平,报个错码农一脸懵逼,想改代码都不知道从哪里改。各种 get/post 都挂在 app 下面,写一两个 action 的时侯看着还行 业务稍微复杂一点,满屏的 end (跟够烂满屏的 err 有一拼)找个路由参数都费劲。只适合用来开发个人业余项目,就算耽误时间也不用担心扣钱

公司业务还是用 flame / rambutan / scorched 这种套个 Controller 帽子的,分门别类设置路由 调试和维护都比较方便 ,app.rb 中只放路由,只有两级 end 相当于 group

require "flame"

Dir[File.join(".", "controllers/*.rb")].map { |file| require file }

class App < Flame::Application
  mount IndexController do
    get "/", :dashboard
  end
  mount UserController do
    get "/login", :login
    post "/login", :logon
  end
end

其实可以试试 Hanami

还可以试试 padrino

Reply to crazyjacky

脚手架生成可以选 Sequel 吗?

Reply to tablecell

可以吧

padrino g project cool --orm sequel
Reply to crazyjacky

Error: Sequel::AdapterNotFound: LoadError: cannot load such file -- sequel/adapters/sqlite3

gem install sequel-adapters-sqlite3

ERROR: Could not find a valid gem 'sequel-adapters-sqlite3' (>= 0) in any repository

Reply to tablecell

我的情况类似 padrino 当时没跑通,放弃了。

Reply to Mark24

padrino 在 sinatra 上面套了个外壳,里面还是 sinatra,报错信息跟 sinatra 一模一样,就是集成了外围组件,集成了 admin cache mailer 和脚手架,高仿 rails
命令行生成这种方式明显是过度设计,多增加了一些 Gem 依赖和学习成本 论效率远不如 git clone 一个项目 boilerplate

Reply to tablecell

我没碰到这个问题唉,我刚又试了一下,还是可以创建新的 project

You need to Sign in before reply, if you don't have an account, please Sign up first.