이번 글에서는 Rails 파라미터(params)에 대해 자세히 알아보겠습니다.
파라미터는 왜 중요할까요? 사용자는 웹 애플리케이션으로 데이터를 전송할 수 있는데, 그 방식은 크게 세 가지입니다.
사용자가 데이터를 전송하는 3가지 방법
- 쿼리 파라미터 —
"example.com/?q=bacon" - 폼(form) 제출 —
"/users/sign_in" - URL 자체에 포함된 값 —
"/books/1"
그렇다면 Rails에서는 이 데이터에 어떻게 접근할 수 있을까요? 바로 params를 사용하면 됩니다.
컨트롤러 액션 내부에서 params를 호출하면 폼 데이터와 URL 쿼리 데이터에 접근할 수 있습니다.
params란 정확히 무엇일까?
params는 ActionController::Parameters 객체를 반환하는 메서드입니다. 실제로는 해시(hash)와 매우 유사하게 동작합니다.
예를 들어, params에서 특정 값을 하나 읽어오고 싶다면 다음과 같이 작성합니다.
params[:id]
값이 존재하면 해당 값을 반환하고, 존재하지 않으면 nil을 반환합니다.
알아두면 좋은 특징
- 폼 필드가 비어 있는 채로 제출되면 빈 문자열("")이 반환됩니다.
params안의 모든 값은 문자열입니다. 정수로 제출되었더라도 마찬가지입니다.
Rails 파라미터를 제대로 이해하지 못하면 혼란스러운 상황이나 이상한 버그의 원인이 될 수 있으므로, 조금 더 깊이 살펴보겠습니다.
Rails 컨벤션: 폼 필드와 params의 관계
폼 필드와 URL 파라미터는 어떻게 params의 키(key)로 매핑될까요?
간단한 검색 폼 예시를 보겠습니다. 이 폼은 /search로 POST 요청을 전송합니다.
<form action="/search" method="post"> <input type="text" name="q"> </form>
요청 결과로 다음과 같은 params 객체를 얻게 됩니다.
{ "q"=>"", "controller"=>"books", "action"=>"search" }
여기서 "q"는 무엇일까요? 바로 HTML 폼에서 input 필드의 name 속성입니다. name 값은 원하는 대로 자유롭게 지정할 수 있습니다.
만약 form_for 헬퍼 메서드로 폼을 생성하면, name은 자동으로 생성되며 일정한 패턴을 따릅니다.
# form_for(@book)로 몇 개의 필드를 만들면 대략 아래처럼 생성됩니다 <input type="text" name="book[title]"> <input type="text" name="book[author]">
필드 이름의 book[title] 같은 형식은 값이 중첩된(nested) params 해시를 만들어냅니다.
예를 들어 사용자가 빈 폼을 제출하면 다음과 같은 구조가 됩니다.
{
"book"=>
{
"title"=>"",
"author"=>"",
"cover"=>"",
"language"=>"English"
}
}
컨트롤러에서는 다음과 같이 데이터에 접근합니다.
params[:book][:language] # "English" params[:book][:author] # ""
params는 해시처럼 동작하지만, 일반 해시와 달리 심볼(symbol)과 문자열(string) 키를 동등하게 취급한다는 점이 특별합니다. 즉, params["book"]과 params[:book]은 같은 결과를 반환합니다.
라우트에서 파라미터 허용하기
쿼리 파라미터 외에도 REST 스타일의 파라미터를 사용할 수 있습니다. Rails에서는 이를 "동적 세그먼트(dynamic segment)"라고 부릅니다.
예를 들어 다음과 같은 라우트가 있다고 가정해 보겠습니다.
get 'books/:id', to: 'books#show'
또는 리소스 라우팅을 사용할 수도 있습니다.
resources :books
이 경우 /books/1 같은 URL을 사용할 수 있습니다. 그리고 URL에 포함된 1, 즉 books/:id의 id 부분에 params로 접근할 수 있습니다.
params[:id]
이를 활용하면 사용자가 찾고 있는 특정 리소스를 조회할 수 있습니다.
Book.find(params[:id])
Strong Parameters 이해하기
다음으로 자주 마주치는 상황 하나를 살펴보겠습니다. 객체를 데이터베이스에 저장하려는데 저장이 되지 않는다면, Rails 서버 로그를 확인해 보세요.
아마 다음과 같은 메시지를 볼 수 있을 것입니다.
Unpermitted parameter: :language
이것은 무슨 의미일까요?
Rails 4부터 도입된 Strong Parameters(강력한 파라미터) 시스템은 보안 기능입니다. 이 시스템은 저장 가능한 속성을 화이트리스트(whitelist)로 명시적으로 지정하도록 강제합니다.
이를 통해 "대량 할당(mass assignment)"이라는 취약점을 방지할 수 있습니다. 대량 할당 취약점이 있으면 악의적인 사용자가 admin = true처럼 평소에는 접근 권한이 없는 필드를 임의로 설정할 수 있습니다.
화이트리스트 지정 방법
def book_params params.require(:book).permit(:title, :author, :cover, :language) end
동작 방식은 다음과 같습니다.
require메서드는params[:book]을 찾고, 없으면 에러를 발생시킵니다.permit메서드는 허용된(선택적인) 속성 목록을 지정합니다.
결과적으로 화이트리스트에 포함된 속성들만 담긴 새로운 params 해시가 반환되며, 이제 안전하게 데이터베이스에 저장할 수 있습니다.
Book.create(book_params)
참고로 일반 Ruby 해시는 이 보안 시스템을 우회합니다.
Book.create(title: "", author: "", cover: "")
속성 이름(예: author)이 코드에 하드코딩되어 있다면 이 방식도 문제없습니다.
정리
이번 글에서는 Rails 파라미터가 무엇인지, 어떻게 동작하는지, 그리고 Rails 프로젝트에서 올바르게 활용하는 방법까지 살펴보았습니다.
이제 직접 실습하고, 노트를 정리하며 복습해 보세요 🙂
읽어주셔서 감사합니다.