Truy vấn Rails 4 THÍCH - ActiveRecord thêm dấu ngoặc kép


127

Tôi đang cố gắng thực hiện một truy vấn như vậy

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

Nhưng khi nó được chạy, một cái gì đó đang thêm các trích dẫn làm cho câu lệnh sql xuất hiện như vậy

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

Vì vậy, bạn có thể thấy vấn đề của tôi. Tôi đang sử dụng Rails 4 và Postgres 9 cả hai điều này tôi chưa bao giờ sử dụng vì vậy không chắc chắn nếu đó là một thứ Activerecord hoặc có thể là một điều postgres.

Làm thế nào tôi có thể thiết lập điều này để tôi thích '%my_search%'trong truy vấn cuối?

Câu trả lời:


228

Trình giữ chỗ của bạn được thay thế bằng một chuỗi và bạn không xử lý đúng.

Thay thế

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

với

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

6
Đây không phải là dễ bị tổn thương với SQL Injection? Ý tôi là, những searchchuỗi đó được khử trùng?
jdscosta91

6
@ jdscosta91 ?, nơi sẽ chăm sóc vệ sinh
house9

7
@ house9 trường hợp %_bên trong searchsẽ không được vệ sinh, theo phương pháp này.
Barry Kelly

8
Khi đang sử dụng '?' theo cách này trong đường ray, nó được chuyển đổi thành một truy vấn được tham số hóa. Dữ liệu trong tham số không được khử trùng (%) nhưng không thể thay đổi ngữ cảnh ra khỏi truy vấn và biến nó thành các câu lệnh SQL được xử lý.
David Hoelzer 6/07/2015

50

Thay vì sử dụng conditionscú pháp từ Rails 2, hãy sử dụng wherephương thức của Rails 4 thay thế:

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

LƯU Ý: ở trên sử dụng cú pháp tham số thay vì? giữ chỗ: cả hai sẽ tạo ra cùng một 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

LƯU Ý: sử dụng ILIKEcho tên - phiên bản postgres trường hợp không nhạy cảm của THÍCH


Điều này vẫn còn hiệu lực cho Rails 5? Bởi vì nếu tôi có Movie.where("title ILIKE :s", s: search_string)nó được dịch sang SELECT 1 AS one FROM "movies" WHERE (title ILIKE 'test') LIMIT $1ActiveRecord (Rails 5.1.6) - xin lưu ý rằng không có ký hiệu phần trăm nào sau
ILIKE

@sekmo - Nó sẽ hoạt động, phần trăm sẽ đi vào search_stringbiến. Tôi nghĩ rằng SELECT 1 AS oneđầu ra chỉ trong bảng điều khiển rails hoặc bạn đang sử dụng limit(1)? FYI: Rails 5.1.6 có vấn đề về bảo mật, thay vào đó hãy sử dụng 5.1.6.2 hoặc 5.1.7
house9

22

Mặc dù phép nội suy chuỗi sẽ hoạt động, vì câu hỏi của bạn chỉ định đường ray 4, bạn có thể sử dụng Arel cho việc này và giữ cho cơ sở dữ liệu ứng dụng của bạn không bị nghi ngờ.

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

Thật sự dễ dàng để tạo một func để thực hiện điều này một cách linh hoạt với một danh sách các thuộc tính
cevaris

Chưa được kiểm tra, mặc dù nó có thể là một cái gì đó như thế này: scope search_attribut, -> (truy vấn, thuộc tính) {arel_attribut = Properties.map {| a | arel_table [a]} arel_queries = arel_attribut.map {| a | a.matches (truy vấn)} return where (arel_queries.reduce {| res, q | res.or q})}
Pedro Rolo

8

ActiveRecord đủ thông minh để biết rằng tham số được gọi bởi ?chuỗi là một chuỗi và do đó, nó nằm trong dấu ngoặc đơn. Bạn có thể như một bài viết gợi ý sử dụng phép nội suy chuỗi Ruby để đệm chuỗi với các %ký hiệu được yêu cầu . Tuy nhiên, điều này có thể khiến bạn bị tiêm SQL (điều này rất tệ). Tôi sẽ đề nghị bạn sử dụng CONCAT()hàm SQL để chuẩn bị chuỗi như vậy:

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


Tôi chỉ thực hiện điều này trong một ứng dụng và nó hoạt động rất tốt. Cảm ơn bạn John.
nhóm mờ

liên quan đến tiêm, không có nó và không trong mọi trường hợp điều này làm cho không có sự khác biệt. Chuỗi được chèn vào sql và đường ray nên đã xác nhận nó trước đó (không quan trọng nếu một %được nối / bổ sung hay không). Hoặc nó hoạt động như mong đợi hoặc đường ray có một lỗi lớn ảnh hưởng đến cả hai trường hợp.
Estani

5

Thử

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

Xem các tài liệu về điều kiện AREL để biết thêm.


-1
.find(:all, where: "value LIKE product_%", params: { limit: 20, page: 1 })
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.