这个问题与this one相当,但我再次提出这个问题,因为提供的答案并没有解决问题,并且正如提出问题的人总结的那样:它可能是Rails中的一个错误(但没有后续跟进)就此而言。)
我有这些路线:
resources :books, controller: :projects, type: "Book" do
resources "", as: :book_chapters, controller: :contributions, type: "BookChapter", except: :index, constraints: IdConstraint
end
这是IdConstraint:
class IdConstraint
INVALID_IDS = %w[edit series new]
def self.matches?(request)
!INVALID_IDS.include? request.params[:id]
end
end
我使用的是friedly_id,因此:id
参数是一个基于书籍或书籍章节标题的字符串。
现在,/books/friendly-id-of-book/friendly-id-of-chapter
之类的请求会路由到book_chapters控制器上的show
操作。
但我还希望/books/friendly-id-of-book/edit
路由到图书控制器上的edit
操作,因为book_chapters路线上的约束将edit
排除为id。这不起作用,似乎问题出在IdConstraint
。如果我将matches?
方法中的一行替换为false
:
class IdConstraint
INVALID_IDS = %w[edit series new]
def self.matches?(request)
false
end
end
.../edit
路由正确路由到图书控制器上的编辑操作。
但是当我只在原始行之后添加false
行:
class IdConstraint
INVALID_IDS = %w[edit series new]
def self.matches?(request)
!INVALID_IDS.include? request.params[:id]
false
end
end
路由失败,即路由到id为“edit”的book_chapters控制器,而我真的希望它仍然返回false,从而路由到books控制器的编辑操作。
我无法弄清楚这里出了什么问题。有什么想法吗?
答案 0 :(得分:1)
在我看来,你正在遇到的是一个范围问题。 INVALID_IDS是在self.matches?()之外定义的,所以它在self.matches中不可用?()。
你可以尝试:
class IdConstraint
def self.matches?(request)
INVALID_IDS = %w[edit series new]
!INVALID_IDS.include? request.params[:id]
end
end
或者,如果你真的需要在IdConstraint的其他地方使用INVALID_IDS,你可以这样做:
# Note that you'll need to use IdConstraint.new as your constraint for
# this one, not IdConstraint
class IdConstraint
def initialize
@INVALID_IDS = %w[edit series new]
end
def matches?(request)
!@INVALID_IDS.include? request.params[:id]
end
end
Rails Guide上有第二种方法的好例子。
是的,你对request.params的错误是正确的。目前,这似乎相对较好:
class IdConstraint
INVALID_IDS = %w[edit series new]
def self.matches?(request)
end_of_path = request.path.split('/').last
!INVALID_IDS.include? end_of_path
end
end
答案 1 :(得分:1)
这是由Rails 3.1 master(在0e19c7c414bb)中的错误引起的。见the bug report on GitHub。在修复之前,您可以使用request.path_parameters[:id]
代替request.params[:id]
暂时规避它。