【问题标题】:Rails REST routing: dots in the resource item IDRails REST 路由:资源项 ID 中的点
【发布时间】:2011-07-10 12:21:24
【问题描述】:

我的 routes.rb 中有以下内容:

resources :users, :except => [:new, :create] do
    get 'friends', :as => :friends, :on => :member, :to => "users#friends"
end

并在我的 user.rb 中关注:

def to_param
  self.login
end

例如,当登录中带有点的用户(例如“any.thing”)来自 facebook 时,rails 会给出路由错误(找不到路由,我想这是因为它可以将点之后的任何内容识别为格式,或者因为路线限制)。我该如何解决这个错误?

【问题讨论】:

标签: ruby-on-rails ruby-on-rails-3 rest url-routing


【解决方案1】:

您可以用另一个字符替换句点:

def to_param
  login.gsub(/\./,"-") # note: 'self' is not needed here
end

user = User.find_by_login("bart.simpson")
user_path(user) # => "/users/bart-simpson"

编辑

您是对的,这无法处理映射到相同值的唯一登录。也许更好的方法是在路线中使用分段约束:

  match 'users/(:id)' => 'users#show', 
    :constraints => { :id => /[0-9A-Za-z\-\.]+/ }

这应该允许"/users/bart-simpson"/users/bart.simpson" 分别生成:id => "bart-simpson":id => "bart.simpson"。您必须更改正则表达式才能为 URL 添加所有可接受的字符。

请注意,Rails Routing Guide 第 3.2 节中提到了这一点:

默认情况下,动态段不接受点 - 这是因为 dot 用作格式化路线的分隔符。如果您需要使用 动态段中的点添加一个覆盖它的约束 - 例如:id => /[^\/]+/ 允许除斜线之外的任何内容。

【讨论】:

  • 用另一个字符替换点不是解决方案,因为 1)我们通过许多 oauth 提供程序使用连接,并且“bart.simpson”和“bart-simpson”可能是两个不同的用户 2)它变成在显示操作中从用户中搜索更复杂(例如 User.find_by_login("bart-simpson") 将找不到登录为 "bart.simpson" 的用户)。 self 可以省略,但将它留在那里是一种很好的技术,因为它使方法上下文更加清晰,而且在我们公司它是一种标准的编码风格
  • 好点。请参阅我的编辑以获取替代方法。我必须说我不同意不需要 self 的编码标准,但这并不重要。
  • 有没有办法在 id 中允许点,并且还接受有限范围的格式?
  • 要使用第一种技术并拥有唯一的 id,首先将 '-' 替换为 '$-',然后替换 '.'和 '%-'。没有测试 $ 和 % 是否有效,这只是一个例子,但这使得 - 和 .对应一个唯一值,可以向后转换。
  • @emptywalls 答案是正确的,但是在渲染时斜线被删除了。我将其更改为使用反引号来保留所有字符。感谢您指出这一点!
【解决方案2】:

要允许:id 段包含除'/' 之外的任何字符:

match 'users/(:id)' => 'users#show', :constraints => {:id => /[^\/]+/}

它写在一个答案的其他地方,但这是 IMO 最简单的方法。

【讨论】:

    【解决方案3】:

    以下约束定义允许 id 中的点以及除斜线以外的任何字符。

    必须明确定义支持的格式(此处为 .html 和 .json)以不被 id 采用。

    resources :foobars,
      :constraints => { :id => /[^\/]+(?=\.html\z|\.json\z)|[^\/]+/ }
    

    该约束定义适用于 Rails 3.1

    对于早期的 Rails 版本,您可能需要在 regin gem 中向后移植前瞻支持(它在 rack-mount gem 中提供)

    【讨论】:

    • 很棒的提示。谢谢你:)
    • :constraints => {:id => /[^\/]+(?=#{ ActionController::Renderers::RENDERERS.map{|e| "\\.#{e}\\z"}.join("|") })|[^\/]+/}
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-12
    • 2018-12-15
    • 2014-12-24
    • 1970-01-01
    相关资源
    最近更新 更多