Class: RuboCop::Cop::DevDoc::Style::AvoidHeadResponse
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::DevDoc::Style::AvoidHeadResponse
- Defined in:
- lib/rubocop/cop/dev_doc/style/avoid_head_response.rb
Overview
Avoid head() with error or no-content status codes in controllers.
Rationale
Using head() for error responses returns an empty body with no
useful information for the client. Error handling should be delegated
to Rails exceptions (e.g. ActiveRecord::RecordNotFound) or model
validations instead, which give the client more context.
head :no_content (and :reset_content) is flagged for a different
reason: in a backend-driven JSON UI a bodyless "success" is
ambiguous — the client needs a response body (even an empty action
spec) to know what to do. A production head :no_content escape
hatch surfaced as an error snackbar in front of a customer before
this was flagged.
Success statuses that normally carry a body (:ok, :accepted)
are legitimate uses of head() and are not flagged.
The set of flagged statuses is configurable via FlaggedStatuses:.
❌ Manually returns 404 with no body
def show
@user = User.find_by(id: params[:id])
head(:not_found) unless @user
end
✔️ Let Rails raise RecordNotFound — it renders the standard 404
def show
@user = User.find(params[:id])
end
❌ Bodyless success — a JSON-driven client learns nothing
def destroy
@resource.destroy!
head :no_content
end
✔️ Tell the client what to do, even when that is "nothing"
def destroy
@resource.destroy!
render json: {}
end
Constant Summary collapse
- MSG =
'Avoid `head(%<status>s)` for error handling. ' \ 'Delegate to Rails exceptions or model validations instead.'.freeze
- NO_CONTENT_MSG =
'Avoid `head(%<status>s)`: a bodyless response tells a JSON-driven ' \ 'client nothing. Render an action response (even an empty one) instead.'.freeze
- RESTRICT_ON_SEND =
%i[head].freeze
- NO_CONTENT_STATUSES =
%w[no_content reset_content 204 205].freeze
- DEFAULT_FLAGGED_STATUSES =
(%w[ not_found unprocessable_entity forbidden unauthorized bad_request conflict gone method_not_allowed 404 422 403 401 400 409 410 405 ] + NO_CONTENT_STATUSES).freeze
Instance Method Summary collapse
Instance Method Details
#on_send(node) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/rubocop/cop/dev_doc/style/avoid_head_response.rb', line 80 def on_send(node) # `self.head(...)` is the same controller call — a bare receiver # check would make explicit-self a one-token dodge. return unless node.receiver.nil? || node.receiver.self_type? status_node = node.arguments.first return unless status_node return unless flagged_literal?(status_node) template = NO_CONTENT_STATUSES.include?(status_node.value.to_s) ? NO_CONTENT_MSG : MSG add_offense(node.loc.selector, message: format(template, status: status_display(status_node))) end |