2

StackOverflow 似乎有这种风格的问题路线:

/questions/:id/*slug

这很容易实现,无论是在路线上还是在to_param.

但是,当仅传递一个 ID 时,StackOverflow 似乎也会重定向到该路径。

例子:

stackoverflow.com/questions/6841333 

重定向到:

stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result/

蛞蝓的任何变化也是如此

stackoverflow.com/questions/6841333/some-random-stuff

仍将重定向到相同的 URL。

我的问题是:这种类型的重定向通常在控制器中处理(将请求与路由进行比较)还是有办法做到这一点routes.rb

我认为routes.rb文件中不可能发生这种情况的原因是,通常您无权访问该对象(因此您无法根据 ID 获取 slug,对吗?)

对于任何感兴趣的人,Rails 3.2.13 并使用FriendlyID

4

1 回答 1

3

好的,所以我想我明白了。

我正在考虑用中间件做点什么,但后来决定这可能不是这种功能的地方(因为我们需要访问 ActiveRecord)。

所以我最终构建了一个服务对象,称为PathCheck. 该服务如下所示:

class PathCheck
  def initialize(model, request)
    @model = model
    @request = request
  end 

  # Says if we are already where we need to be
  # /:id/*slug
  def at_proper_path?
    @request.fullpath == proper_path
  end

  # Returns what the proper path is
  def proper_path
    Rails.application.routes.url_helpers.send(path_name, @model) 
  end

private
  def path_name
    return "edit_#{model_lowercase_name}_path" if @request.filtered_parameters["action"] == "edit"
    "#{model_lowercase_name}_path"
  end

  def model_lowercase_name
    @model.class.name.underscore
  end
end

这很容易在我的控制器中实现:

def show
  @post = Post.find params[:post_id] || params[:id]
  check_path
end

private
  def check_path
    path_check = PathCheck.new @post, request
    redirect_to path_check.proper_path if !path_check.at_proper_path?
  end

||find方法是因为为了维护资源丰富的路线,我做了类似...

resources :posts do
  get '*id' => 'posts#show'
end

这将使路线如下/posts/:post_id/*id/posts/:id

这样,数字 id 主要用于查找记录(如果可用)。这允许我们松散匹配/posts/12345/not-the-right-slug以被重定向到/posts/12345/the-right-slug

该服务以通用方式编写,因此我可以在任何资源丰富的控制器中使用它。我还没有找到破解它的方法,但我愿意更正。

资源

Railscast #398: Ryan Bates 的服务对象

Jared Fine 的这条有用推文

于 2013-05-21T14:35:27.633 回答