好的,所以我想我明白了。
我正在考虑用中间件做点什么,但后来决定这可能不是这种功能的地方(因为我们需要访问 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 的这条有用推文