Rails 4 LIKE 쿼리-ActiveRecord는 따옴표를 추가합니다


127

나는 같은 쿼리를하려고합니다.

def self.search(search, page = 1 )
  paginate :per_page => 5, :page => page,
    :conditions => ["name LIKE '%?%' OR postal_code like '%?%'", search, search],   order => 'name'
end

그러나 실행될 때 따옴표를 추가하면 sql 문이 이렇게 나타납니다.

SELECT COUNT(*)
FROM "schools" 
WHERE (name LIKE '%'havard'%' OR postal_code like '%'havard'%')):

내 문제를 볼 수 있습니다. Rails 4와 Postgres 9를 사용하고 있습니다.

'%my_search%'최종 쿼리에서 와 같이 이것을 어떻게 설정 합니까?

답변:


228

자리 표시자가 문자열로 바뀌고 올바르게 처리하지 못합니다.

바꾸다

"name LIKE '%?%' OR postal_code LIKE '%?%'", search, search

"name LIKE ? OR postal_code LIKE ?", "%#{search}%", "%#{search}%"

6
이것이 SQL 인젝션에 취약하지 않습니까? 내 말은, 그 search줄은 위생 처리되어 있습니까?
jdscosta91

6
@ jdscosta91는 ?어디에서 위생 관리를 할
것인가

7
이 접근법에 따라 @ house9 인스턴스 %_내부 search는 삭제되지 않습니다.
Barry Kelly

8
사용할 때 '?' 이러한 방식으로 레일에서 매개 변수화 된 쿼리로 변환됩니다. 매개 변수 내의 데이터는 삭제되지 않지만 (%) 쿼리에서 컨텍스트를 변경하여 처리 된 SQL 문으로 바꿀 수 없습니다.
David Hoelzer

50

conditionsRails 2 의 구문 을 사용하는 대신 Rails 4의 where메소드를 대신 사용하십시오.

def self.search(search, page = 1 )
  wildcard_search = "%#{search}%"

  where("name ILIKE :search OR postal_code LIKE :search", search: wildcard_search)
    .page(page)
    .per_page(5)
end

참고 : 위의? 대신 매개 변수 구문을 사용합니다. 자리 표시 자 : 둘 다 동일한 SQL을 생성해야합니다.

def self.search(search, page = 1 )
  wildcard_search = "%#{search}%"

  where("name ILIKE ? OR postal_code LIKE ?", wildcard_search, wildcard_search)
    .page(page)
    .per_page(5)
end

참고 : ILIKE이름 사용 -postgres 대소 문자를 구분하지 않는 LIKE 버전


이것이 여전히 Rails 5에 유효합니까? 내가 ActiveRecord Movie.where("title ILIKE :s", s: search_string)SELECT 1 AS one FROM "movies" WHERE (title ILIKE 'test') LIMIT $1의해 번역 된 경우 (레일 5.1.6)
-ILIKE

@ sekmo-작동해야하며 백분율은 search_string변수에 들어갑니다 . SELECT 1 AS one출력이 레일 콘솔에만 있거나 사용 하고 있다고 생각 limit(1)합니까? 참고 : 대신 5.1.6이 보안 문제, 사용 5.1.6.2 또는 5.1.7 레일
house9

22

문자열 보간이 작동하지만 질문에 레일 4가 지정되어 있으므로 Arel을 사용하고 앱 데이터베이스를 무시할 수 있습니다.

def self.search(query, page=1)
  query = "%#{query}%"
  name_match = arel_table[:name].matches(query)
  postal_match = arel_table[:postal_code].matches(query)
  where(name_match.or(postal_match)).page(page).per_page(5)
end

속성 목록을 사용하여이 기능을 동적으로 수행하는 기능을 쉽게 만들 수 있어야합니다.
cevaris

테스트되지 않았지만 다음과 같이 될 수 있습니다. scope search_attributes,-> (query, attributes) {arel_attributes = attributes.map {| a | arel_table [a]} arel_queries = arel_attributes.map {| a | a.matches (query)} return where (arel_queries.reduce {| res, q | res.or q})}
Pedro Rolo

8

ActiveRecord는에 의해 참조되는 매개 변수 ?가 문자열 이라는 것을 알기에 충분히 영리 하므로 작은 따옴표로 묶습니다. 당신은 할 수 하나의 게시물 패드에 필요로 문자열을 사용 루비 문자열 보간을 건의 %문자. 그러나 이로 인해 SQL 주입 (나쁜)에 노출 될 수 있습니다. SQL CONCAT()함수를 사용 하여 문자열을 준비하는 것이 좋습니다 .

"name LIKE CONCAT('%',?,'%') OR postal_code LIKE CONCAT('%',?,'%')", search, search)


방금 응용 프로그램에서 이것을 구현했으며 훌륭하게 작동했습니다. 고마워요 존
fuzzygroup

주사와 관련하여, 그것은 아닙니다. 어쨌든 이것은 아무런 차이가 없습니다. 문자열은 SQL에 삽입되며 레일은 이전에 유효성을 검사해야합니다 (a %가 추가 / 추가 되었는지 여부는 중요 하지 않음). 예상대로 작동하거나 레일에 두 경우 모두에 영향을 미치는 주요 버그가 있습니다.
estani

5

시험

 def self.search(search, page = 1 )
    paginate :per_page => 5, :page => page,
      :conditions => ["name LIKE  ? OR postal_code like ?", "%#{search}%","%#{search}%"],   order => 'name'
  end

자세한 내용은 AREL 조건에 대한 문서 를 참조하십시오 .


-1
.find(:all, where: "value LIKE product_%", params: { limit: 20, page: 1 })
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.