쿼리와 같은 안전한 ActiveRecord


답변:


166

쿼리 문자열이 제대로 삭제되었는지 확인하려면 배열 또는 해시 쿼리 구문을 사용하여 조건을 설명합니다.

Foo.where("bar LIKE ?", "%#{query}%")

또는:

Foo.where("bar LIKE :query", query: "%#{query}%")

그것은이 가능성이있는 경우 query인클루드 수있는 %문자를 당신은 위생적으로 필요 querysanitize_sql_like첫째 :

Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%")
Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")

이것은 %쿼리 문자열에서 이스케이프되지 않습니다 . 임의의 "SQL 주입"은 아니지만 여전히 예기치 않게 작동 할 수 있습니다.
Beni Cherniavsky-Paskin 2011

@ BeniCherniavsky-Paskin : 그게 요점 입니다. 는 구문의 일부 %이기 때문에 를 이스케이프하고 싶지 않습니다 . 이스케이프하면 결과는 기본적으로 일반 쿼리가됩니다. %LIKE%=
스피커 맨

1
맞습니다. 패턴 템플릿에서 % 와일드 카드를 사용하고 싶지만 해당 패턴은 변수로 매개 변수화되며 query많은 경우 LIKE 메타 문자를 사용 query하지 않고 변수 의 문자열을 문자 그대로 일치 query시키려고합니다. % ... %에 대한보다 현실적인 예를 들어 보겠습니다. 문자열은 경로와 같은 구조를 가지고 있으며 /users/#{user.name}/tags/%. 내가 할 사용자 이름을 주선 이제 경우 fr%d%, 내가 관찰 할 수 있습니다 fredfrida의 태그 ...
베니 Cherniavsky-Paskin

2
좋아, 내가 추구 하는 것은이 질문을 stackoverflow.com/questions/5709887/… 과 결합 하는 것 sanitize_sql_like()입니다.
Beni Cherniavsky-Paskin

2
@ BeniCherniavsky-Paskin 이제 나는 당신이 어디에서 왔는지 이해하고 당신이 옳습니다. 이 문제를 해결하기 위해 답변을 업데이트했습니다.
spickermann 2011

34

Arel을 사용하면 다음과 같은 안전하고 이식 가능한 쿼리를 수행 할 수 있습니다.

title = Model.arel_table[:title]
Model.where(title.matches("%#{query}%"))

1
Arel은 sql-db-agnostic이고 내부 입력 정리 기능이 있기 때문에 이것이 바람직한 솔루션입니다. 또한 코드 스타일이 진행되는 한 IMHO는 훨씬 더 읽기 쉽고 일관성이 있습니다.
Andrew Moore

이것을 어떻게 부정합니까? (즉, NOT LIKE) Model.where(title.matches("%#{query}%").not)작동하지만 생성 된 SQL은 약간 어색합니다.WHERE (NOT (`models`.`title` LIKE '%foo%'))
Noach Magedman

아 ... 찾았다. Model.where(title.does_not_match("%#{query}%")). 생성 : WHERE (`models`.`title` NOT LIKE '%foo%')
Noach Magedman

주의- %신뢰할 수없는 입력 을 삭제하지 못함 : >> ActiveRecord::VERSION::STRING => "5.2.3" >> field = Foo.arel_table[:bar] >> Foo.where(field.matches('%')).to_sql => "SELECT `foos`.* FROM `foos` WHERE `foos`.`bar` LIKE '%'"
vjt

@NoachMagedman 또는 Model.where.not(title.matches("%#{query}%")). does_not_match그래도 IMO는 더 잘 읽습니다.
elquimista

7

PostgreSQL의 경우

Foo.where("bar ILIKE ?", "%#{query}%") 

1

넌 할 수있어

MyModel.where(["title LIKE ?", "%#{params[:query]}%"])

1
@mikkeljuhl 제 대답을주의 깊게 살펴보십시오.
Santhosh

0

중첩 된 연결에 대해 검색 쿼리를 수행하는 사람이있는 경우 다음을 시도하십시오.

Model.joins(:association).where(
   Association.arel_table[:attr1].matches("%#{query}%")
)

여러 속성의 경우 다음을 시도하십시오.

Model.joins(:association).where(
  AssociatedModelName.arel_table[:attr1].matches("%#{query}%")
    .or(AssociatedModelName.arel_table[:attr2].matches("%#{query}%"))
    .or(AssociatedModelName.arel_table[:attr3].matches("%#{query}%"))
)
 

AssociatedModelName모델 이름 으로 바꾸는 것을 잊지 마십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.