Rails 8 Strong Parameters: 중첩 속성을 위한 이중 대괄호 수정
Source: Dev.to
위의 링크에 포함된 전체 텍스트를 제공해 주시면, 해당 내용을 한국어로 번역해 드리겠습니다. (코드 블록, URL 및 마크다운 형식은 그대로 유지됩니다.)
Problem
Rails 8로 업그레이드할 때 params.expect를 사용하기 시작할 수 있습니다—보통 RuboCop의 Rails/StrongParametersExpect에 의해 촉구됩니다—강한 파라미터 계약을 더 명확하게 만들기 위해.
인덱스 해시 형태로 제출된 중첩 속성에서는 날카로운 문제가 나타납니다: 이들은 조용히 필터링될 수 있어, 검증이 명확하지 않은 방식으로 실패하게 됩니다.
모델
class Invoice {
"date" => "2026-01-11",
"due_date" => "2026-01-12",
"client_id" => "123",
"line_items_attributes" => {
"0" => {
"description" => "Web Development",
"quantity" => "10",
"unit_price" => "150"
},
"1" => {
"description" => "UI Design",
"quantity" => "5",
"unit_price" => "200"
}
}
}
⚠️ 중요:
line_items_attributes는 배열이 아니라 동적 숫자 문자열("0","1", …)을 키로 하는 해시입니다. 이 구분이 버그의 근본 원인입니다.
require/permit 사용 (작동)
def invoice_params
params.require(:invoice).permit(
:date,
:due_date,
:client_id,
line_items_attributes: [:description, :quantity, :unit_price, :_destroy]
)
end
permit를 사용하면 중첩 속성이 올바르게 할당되고 검증을 통과합니다.
expect 사용 (실패)
def invoice_params
params.expect(
invoice: [
:date,
:due_date,
:client_id,
line_items_attributes: [:description, :quantity, :unit_price, :_destroy]
]
)
end
- 강한 파라미터 오류가 발생하지 않는다.
line_items_attributes가 필터링되어 라인 아이템이 할당되지 않는다.validates :line_items, presence: true가 실패하고 인보이스가 저장되지 않는다.
결과 확인:
invoice_params[:line_items_attributes]
# => #
line_items_attributes: [:description, :quantity, :unit_price] 선언은 Rails에 해당 키들을 가진 단일 중첩 해시가 예상된다고 알려준다. 그러나 들어오는 데이터는 인덱스된 해시 컬렉션이다.
해결 방법: 컬렉션을 위한 이중 대괄호
“중첩된 해시들의 컬렉션”을 표현하려면 내부 배열을 또 다른 배열로 감싸야 합니다:
def invoice_params
params.expect(
invoice: [
:date,
:due_date,
:client_id,
line_items_attributes: [[
:id,
:description,
:quantity,
:unit_price,
:_destroy
]]
]
)
end
- Inner array → 각 라인 아이템에 허용되는 키.
- Outer array → 반복/컬렉션과 같은 구조를 나타냅니다.
이는 다음 두 경우 모두에 매치됩니다:
- 인덱스가 있는 해시 (
"0" => {...}) - 해시 배열 (
[{...}, {...}])
수정 전후 테스트
# Before fix – no line items created
expect {
post invoices_path, params: valid_params
}.to not_change(Invoice, :count)
.and change(LineItem, :count).by(0)
# After fix – line items created
expect {
post invoices_path, params: valid_params
}.to change(Invoice, :count).by(1)
.and change(LineItem, :count).by(2)
Shape vs. Declaration 요약
| Shape | expect declaration |
|---|---|
| 단일 중첩 해시 | line_items_attributes: [:description] |
인덱스된 해시 ("0"=>…) | line_items_attributes: [[:description]] |
| 해시 배열 | line_items_attributes: [[:description]] |
중첩 레코드가 사라지거나 검증이 예상치 않게 실패할 경우, 값만이 아니라 들어오는 파라미터의 shape을 확인하세요.
Guidance for Rails 8 Migration
- RuboCop은 종종
params.require(...).permit(...)를params.expect(...)로 교체하라고 제안합니다. - Rails/StrongParametersExpect cop은 Rails 중첩 폼(
*_attributes)에서 사용되는 인덱스‑해시 형식을 자동으로 처리하지 못합니다. 순진한 재작성은 동작을 바꿀 수 있습니다. has_many중첩 속성의 경우, 항상 이중 대괄호 구문([[...]])을 사용하세요.- 매우 동적이거나 복잡한 파라미터를 다룰 때는
require/permit을 유지하거나, 해당 cop을 로컬에서 비활성화하는 것이 합리적일 수 있습니다.
Takeaways
params.expect는permit보다 더 엄격하며 명시적인 구조를 요구합니다.- 중첩 해시 컬렉션에는
[[...]]를 사용하세요. - 검증 실패는 조용히 무시된 중첩 속성의 유일한 증상일 수 있습니다.
- 강력 파라미터 처리를 변경할 때는 요청 스펙이 필수적입니다.
이 내용이 시간을 절약했든, 찾기 전에 비용을 들였든, 당신만 그런 것이 아닙니다.