所以,我有一种情况,我需要在将请求发送到任何路由之前确定一些请求。目前,这是使用几个全部命中数据库的约束来实现的,我想将数据库命中减少到一个。不幸的是,在routes.rb
中内联它不起作用,因为routes.rb
中的局部变量不会在请求之间刷新;所以,如果我这样做:
# Database work occurs here, and is then used to create comparator lambdas.
request_determinator = RequestDeterminator.new(request)
constraint(request_determinator.lambda_for(:ninja_requests)) do
# ...
end
constraint(request_determinator.lambda_for(:pirate_requests)) do
# ...
end
这在第一个请求上运行良好,但随后的请求将被路由为第一个请求。 (D'哦。)
我的下一个想法是编写一个Rack中间件来向env
哈希添加“确定器”,但是这有两个问题:首先,它似乎根本没有粘在哈希中,规格甚至没有经过Rack中间件,所以没有办法真正测试它。
我是否有一个简单的机制我可以插入,例如,ActionDispatch的一个钩子可以向请求添加内容,或者只是对Rails路由说:“在路由之前执行此操作?”
我正在使用Rails 3.2和Ruby 1.9。
答案 0 :(得分:2)
执行此操作的一种方法是将您的决定程序存储在请求的env对象上(自ActionDispatch::Request
为Rack::Request
的子类以来):
class RequestDeterminator
def initialize(request)
@request = request
end
def self.for_request(request)
request.env[:__determinator] ||= new(request)
end
def ninja?
query_db
# Verify ninjaness with @request
end
def pirate?
query_db
# Verify piratacity with @request
end
def query_db
@result ||= begin
# Some DB lookup here
end
end
end
constraint lambda{|req| RequestDeterminator.for_request(req).ninja? } do
# Routes
end
constraint lambda{|req| RequestDeterminator.for_request(req).pirate? } do
# Routes
end
这样,您只需实例化一个确定器,它可以跨越约束检查缓存您的数据库请求。
答案 1 :(得分:0)
如果您真的要拦截请求,请尝试使用机架,因为它是第一个在任何Rails应用程序中处理请求的机器...请参阅http://railscasts.com/episodes/151-rack-middleware以了解机架如何工作....
希望它有所帮助。