您如何将命名参数解析为 Sinatra 中的路由?

How do you parse a named parameter into a route in Sinatra?

我正在创建一个书签管理器应用程序,它提供 link 的列表。每个 link 有一个或多个标签。我想让网站用户能够按标签过滤 links。用户应该能够键入标签的名称,然后单击标有 'Filter by tag' 的按钮。这应该仅提供具有该标签的 link 的列表。

因此,我的html表格如下:

<form action='/tags/:name’ method='get'>
  <label for='name'>
    Tag:
    <input type='text' name='name'>
  </label>
  <input type='submit' value='Filter by tag'>
</form>

我的控制器如下:

class BookmarkManager < Sinatra::Base
  get '/tags/:name’ do
    tag = Tag.first(name: params[:name])
    @links = tag ? tag.links : []
    erb :'links/index'
  end
end

我 运行 rackup,并尝试使用标签过滤我的 link。当我输入并提交标签名称时,提交的名称是“:name”而不是输入的文本。因此,没有显示与特定标签相关的 link,而是没有显示 link。

与其使用魔法路由 /:name,我建议您将 name 作为 queryString 参数传递。如果您将 HTML 更改为:

,您的应用应该可以正常工作
<form action='/tags' method='get'>
  <label for='name'>
    Tag:
    <input type='text' name='name'>
  </label>
  <input type='submit' value='Filter by tag'>
</form>

并将 sinatra 路由更改为:

class BookmarkManager < Sinatra::Base
  get '/tags’ do
    raise ArgumentError, "Name is required in order to show a tag" unless params[:name]
    tag = Tag.first(name: params[:name])
    @links = tag ? tag.links : []
    erb :'links/index'
  end
end

此外,如果名称未传递给路由,路由现在会抛出异常。这是验证您的输入的好方法。

成功解决问题如下:

在html中:

<form action='/tags' method='get'>
  <label for='name'>
    Tag:
    <input type='text' name='name'>
  </label>
  <input type='submit' value='Filter by tag'>
</form>

在控制器中:

class BookmarkManager < Sinatra::Base
  get '/tags' do
    redirect "/tags/#{params[:name]}"
  end
  get '/tags/:name' do
    tag = Tag.first(name: params[:name])
    @links = tag ? tag.links : []
    erb :'links/index'
  end
end

所以现在当我按标签过滤时,我的 URL 将显示标签名称。