Примечание Первоначально это был вопрос 404 ошибок, но теперь вопрос, почему патч, который я применил, будет иметь значение.
Как получить кэшированное действие, возвращающее 404 для всех запросов, которые вызывают исключение ActiveRecord :: RecordNotFound, а не только для первого запроса?
Например, если вы запускаете пустой проект rails, добавляете модель продукта и контроллер, настраиваете свой database.yml, настраиваете бэкэнд своего кэша в production.rb, rake db: migrate, затем запускаете в производство и заходите на сайт для несуществующий объект, например http://localhost:3000/product/show/1234
class ProductController < ApplicationController
caches_action :show
def show
@product = Product.find(params[:id])
render :text => "asdf"
end
end
При первом обращении к странице возвращается страница 404, как и ожидалось. Однако каждый последующий переход по этому URL возвращает пустую страницу с 200 OK. Как вы получаете, чтобы он возвращал 404 каждый раз?
Вот запросы CURL, за которыми следуют журналы
~ $ curl -I http://0.0.0.0:3000/product/show/1234
HTTP/1.1 404 Not Found
Connection: close
Date: Mon, 20 Apr 2009 22:49:18 GMT
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
Content-Length: 14097
~ $ curl -I http://0.0.0.0:3000/product/show/1234
HTTP/1.1 200 OK
Connection: close
Date: Mon, 20 Apr 2009 22:49:19 GMT
X-Runtime: 6
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
Content-Length: 0
Второй ответ явно неверен.
Вот копия журнала для 2 запросов:
Processing ProductController#show (for 127.0.0.1 at 2009-04-20 17:35:24) [GET]
Parameters: {"id"=>"1234"}
ActiveRecord::RecordNotFound (Couldn't find Product with ID=1234):
app/controllers/product_controller.rb:6:in `show'
Rendering rescues/layout (not_found)
Processing ProductController#show (for 127.0.0.1 at 2009-04-20 17:35:30) [GET]
Parameters: {"id"=>"1234"}
Filter chain halted as [#<ActionController::Caching::Actions::ActionCacheFilter:0x23e36d4 @options={:cache_path=>nil, :store_options=>{}, :layout=>nil}>] rendered_or_redirected.
Filter chain halted as [#<ActionController::Filters::AroundFilter:0x23e3580 @kind=:filter, @options={:unless=>nil, :if=>nil, :only=>#<Set: {"show"}>}, @method=#<ActionController::Caching::Actions::ActionCacheFilter:0x23e36d4 @options={:cache_path=>nil, :store_options=>{}, :layout=>nil}>, @identifier=nil>] did_not_yield.
Completed in 12ms (View: 0, DB: 0) | 200 OK [http://0.0.0.0/product/show/1234]
Действительно, если вы извлечете кэшированное действие из кэша, там будет какой-то пустой мусор.
cache.fetch("views/0.0.0.0:3000/product/show/1234")
=> ["", nil, [], []]
Что я здесь не так делаю?
Редактировать
Я подтвердил, что в Rails 2.1.2 и 2.2.2 такого поведения нет, а в 2.3.2. (то есть старые версии не хранят пустой ответ в кеше, и они действительно выбрасывают 404 для последующих запросов)
У меня проблемы с тестированием на пограничных Rails, потому что при его загрузке возникает следующая ошибка при запуске сервера:
foobar / vendor / rails / activesupport / lib / active_support / dependencies.rb: 440: в `load_missing_constant ': неинициализированная константа ActionController :: Failsafe (NameError)
Я проверил по текущей главе 2-3-стабильной ветви, 375e8976e3, и она тоже демонстрирует такое поведение.
Редактировать # 2
Я попытался отследить, когда произошло изменение в кодовой базе Rails, чтобы определить, было ли оно намеренным. Кажется, что этот, казалось бы, безобидный коммит - это то место, где начинается ошибка.
Вот подробности деления пополам, где 404 обозначает желаемое поведение, а 200 нежелательно.
2-3-stable branch
375e8976e3 - 200
b1c989f28d - 200
beca1f2e15 - 200
f1fff0a48 - 200
f1e20ce9a7 - 200
a5004573d8 - 200
2e1132fad8 - 200 - the difference seems to start at this commit
c69d8c043f - 404
d961592886 - 404
276ec16007 - 404
0efec6452 - 404
13c6c3cfc5 - 404
fb2325e35 - 404
2-2 stable
3cb89257b4 - 404
Вот патч, который отменяет изменение, которое при применении к тегу v2.3.2.1, то есть dc88847e5ce392eed210b97525c14fca55852867, устраняет проблему. Я, однако, не достаточно умен, чтобы понять, почему это, казалось бы, маленькое изменение действительно имеет значение! Возможно, кто-то умнее меня мог бы пролить свет на ситуацию?
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 0facf70..0790807 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -1403,12 +1403,9 @@ module ActionController #:nodoc:
end
Base.class_eval do
- [ Filters, Layout, Benchmarking, Rescue, Flash, MimeResponds, Helpers,
- Cookies, Caching, Verification, Streaming, SessionManagement,
- HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods,
- RecordIdentifier, RequestForgeryProtection, Translation
- ].each do |mod|
- include mod
- end
+ include Filters, Layout, Benchmarking, Rescue, Flash, MimeResponds, Helpers
+ include Cookies, Caching, Verification, Streaming, SessionManagement
+ include HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods
+ include RecordIdentifier, RequestForgeryProtection, Translation
end
end
Редактировать # 3
Похоже, что патч также исправляет связанную с этим ошибку, показанную выше, в которой «Завершено в XYms (DB: Z) | 404 Not Found [http://0.0.0.0/product/1234]"» не отображалось в журнале.
Редактировать # 4
Вышеупомянутый патч сломал другие вещи в ActionPack, поэтому я углубился и создал исправление для проблемы, которая не наносит сопутствующий ущерб. Патч и все последующие обновления будут на рельсовом маяке