常见问题解答

如何使我的 Sinatra 应用程序在更改时重新加载?

首先,在 Ruby 中进行进程内代码重新加载很困难,并且找到适用于所有场景的解决方案在技术上是不可能的。

这就是我们建议您进行进程外重新加载的原因。

首先,如果您还没有安装 rerun,则需要安装它

$ gem install rerun

现在,如果您像这样启动您的 Sinatra 应用程序

$ ruby app.rb

您要做的就是进行重新加载,而不是这样做

$ rerun 'ruby app.rb'

例如,如果您使用的是 rackup,请执行以下操作

$ rerun 'rackup'

您明白了。

如果您仍然想要进行进程内重新加载,请查看 Sinatra::Reloader

我的部署选项有哪些?

请参阅 书籍

如何使用会话?

会话默认情况下是禁用的。您需要启用它们,然后从路由和视图中使用 session 哈希

enable :sessions

get '/foo' do
  session[:message] = 'Hello World!'
  redirect to('/bar')
end

get '/bar' do
  session[:message]   # => 'Hello World!'
end

请参阅 Sinatra 自述文件,了解如何为会话设置其他参数,例如会话密钥或过期日期。

您也可以直接使用 Rack::Session::Cookie,而不是使用 enable :sessions(来自 Rack 文档的示例)。

use Rack::Session::Cookie, :key => 'rack.session',
                           :domain => 'foo.com',
                           :path => '/',
                           :expire_after => 2592000, # In seconds
                           :secret => 'change_me'

如何使用基于会话的闪存?

使用 Rack::Flash

我可以在 Ruby 1.9 下运行 Sinatra 吗?

是的。从 Sinatra 0.9.2 开始,Sinatra 完全兼容 Ruby 1.9 和 Rack 1.0。从 1.1 版本开始,您无需自行处理编码,除非您想这样做。

如何获取当前页面的“路由”?

request 对象可能包含您要查找的内容。

get '/hello-world' do
  request.path_info   # => '/hello-world'
  request.fullpath    # => '/hello-world?foo=bar'
  request.url         # => 'https://example.com/hello-world?foo=bar'
end

有关 request 对象支持的方法的详细列表,请参阅 Rack::Request

如何在视图中访问助手?

调用它们!视图自动访问所有辅助方法。事实上,Sinatra 在同一个对象上下文中评估路由、视图和辅助方法,因此它们都能够访问相同的方法和实例变量。

hello.rb

helpers do
  def em(text)
    "<em>#{text}</em>"
  end
end

get '/hello' do
  @subject = 'World'
  haml :hello
end

views/hello.haml

%p= "Hello " + em(@subject)

如何渲染部分?

Sinatra 的模板系统非常简单,可以用于页面和片段级别的渲染任务。 erbhaml 方法只返回一个字符串。

从 Sinatra 1.1 版本开始,您可以使用与在路由中使用的相同的调用来调用部分。

<%= erb :mypartial %>

在 1.1 版本之前的版本中,您需要确保禁用布局渲染,如下所示

<%= erb :mypartial, :layout => false %>

我可以让多个 URL 触发相同的路由/处理程序吗?

当然可以。

["/foo", "/bar", "/baz"].each do |path|
  get path do
    "You've reached me at #{request.path_info}"
  end
end

说真的。

如何使尾部斜杠可选?

在它后面加上一个问号。

get '/foo/bar/?' do
  "Hello World"
end

该路由匹配 "/foo/bar""/foo/bar/"

如何渲染嵌套在子目录中的模板?

Sinatra 应用程序通常在 views 下没有非常复杂的目录层次结构。首先,考虑您是否真的需要子目录。如果是,您可以使用 views/foo/bar.haml 文件作为模板,使用

get '/' do
  haml :'foo/bar'
end

这与将 #to_sym 发送到文件名基本相同,也可以写成

get '/' do
  haml 'foo/bar'.to_sym
end

我正在运行 Thin,发生错误但没有输出

尝试使用 --debug 参数启动 Thin。

thin --debug --rackup config.ru start

这应该会在 stderr 上为您提供异常和回溯。

如何从 Sinatra 发送电子邮件?

如何使用 Pony (sudo gem install pony)

require 'pony'
post '/signup' do
  Pony.mail :to => '[email protected]',
            :from => '[email protected]',
            :subject => 'Howdy, Partna!'
end

您甚至可以使用模板来渲染正文。在 email.erb

Good day <%= params[:name] %>,

Thanks for signing my guestbook. You're a doll.

Frank

mailerapp.rb

post '/guestbook/sign' do
  Pony.mail :to => params[:email],
            :from => "[email protected]",
            :subject => "Thanks for signing my guestbook, #{params[:name]}!",
            :body => erb(:email)
end

如何转义 HTML?

在你的助手方法中使用 Rack::Utils,如下所示

helpers do
  def h(text)
    Rack::Utils.escape_html(text)
  end

  def hattr(text)
    Rack::Utils.escape_path(text)
  end
end

现在,你可以通过以下两种方式之一在模板中转义输出文本中的 HTML 实体

<div><%= h scary_output %></div>

或者使用 <%== 功能

<div><%== scary_output %></div>

你也可以在模板中像这样转义元素属性中的文本

<a href="<%= hattr scary_output %>" >A nice safe link!</a>

感谢 Chris Schneider 的提示!

如何自动转义 HTML?

需要 ErubisErubi 并将 escape_html 设置为 true

require 'erubis' # or 'erubi'
set :erb, :escape_html => true

然后,使用 Erubis 渲染的任何模板都会自动转义

get '/' do
  erb :index
end

Tilt Google Group 上了解更多详细信息。

如何使用 ActiveRecord 迁移?

来自 Adam Wiggins 的博客

要将 ActiveRecord 的迁移与 Sinatra(或其他非 Rails 项目)一起使用,请将以下内容添加到你的 Rakefile 中

namespace :db do
  desc "Migrate the database"
  task(:migrate => :environment) do
    ActiveRecord::Base.logger = Logger.new(STDOUT)
    ActiveRecord::Migration.verbose = true
    ActiveRecord::Migrator.migrate("db/migrate")
  end
end

这假设你有一个名为 :environment 的任务,它加载你的应用程序的环境(需要正确的文件,设置数据库连接等)。

现在,你可以创建一个名为 db/migrate 的目录,并在其中填写你的迁移。我通常将第一个迁移命名为 001_init.rb。(我更喜欢使用旧的顺序方法来对迁移进行编号,而不是自 Rails 2.1 以来使用的日期时间方法,但两种方法都可以。)

有关其他选项,请查看 Sinatra ActiveRecord 扩展

如何使用 HTTP 身份验证?

你至少有两种选择可以在你的应用程序中实现基本访问身份验证(基本 HTTP 身份验证)。

I. 当你想要保护应用程序中的所有请求时,只需通过 use 指令将 Rack::Auth::Basic 中间件放入请求处理链中

require 'sinatra'

use Rack::Auth::Basic, "Restricted Area" do |username, password|
  username == 'admin' and password == 'admin'
end

get '/' do
  "You're welcome"
end

get '/foo' do
  "You're also welcome"
end

II. 当你想要保护应用程序中的某些 URL,或者想要更复杂的授权时,你可以使用类似于以下内容

require 'sinatra'

helpers do
  def protected!
    return if authorized?
    headers['WWW-Authenticate'] = 'Basic realm="Restricted Area"'
    halt 401, "Not authorized\n"
  end

  def authorized?
    @auth ||=  Rack::Auth::Basic::Request.new(request.env)
    @auth.provided? and @auth.basic? and @auth.credentials and @auth.credentials == ['admin', 'admin']
  end
end

get '/' do
  "Everybody can see this page"
end

get '/protected' do
  protected!
  "Welcome, authenticated client"
end

如何测试 HTTP 身份验证?

假设你在你的 application.rb 中有这个简单的 HTTP 身份验证实现

require 'sinatra'

use Rack::Auth::Basic do |username, password|
  username == 'admin' and password == 'admin'
end

get '/protected' do
  "You're welcome"
end

你可以使用 Rack::Test 像这样测试它

ENV['APP_ENV'] = 'test'
require 'test/unit'
require 'rack/test'

require 'application'

class ApplicationTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  def test_without_authentication
    get '/protected'
    assert_equal 401, last_response.status
  end

  def test_with_bad_credentials
    authorize 'bad', 'boy'
    get '/protected'
    assert_equal 401, last_response.status
  end

  def test_with_proper_credentials
    authorize 'admin', 'admin'
    get '/protected'
    assert_equal 200, last_response.status
    assert_equal "You're welcome", last_response.body
  end
end