2011-08-22 22 views
16

Có cách nào để vệ sinh sql trong đường ray phương pháp find_by_sql?Đường ray, cách vệ sinh SQL trong find_by_sql

Tôi đã thử giải pháp này: Ruby on Rails: How to sanitize a string for SQL when not using find?

Nhưng nó không thành công tại

Model.execute_sql("Update users set active = 0 where id = 2") 

Nó ném một lỗi, nhưng mã sql được thực hiện và người dùng với ID 2 bây giờ có một tài khoản người tàn tật.

Simple find_by_sql cũng không hoạt động:

Model.find_by_sql("UPDATE user set active = 0 where id = 1") 
# => code executed, user with id 1 have now ban 

Edit:

Vâng khách hàng của tôi yêu cầu để thực hiện chức năng đó (chọn bởi sql) trong bảng quản trị để thực hiện một số truy vấn phức tạp (tham gia, điều kiện đặc biệt, vv). Vì vậy, tôi thực sự muốn find_by_sql đó.

Second Edit:

Tôi muốn đạt được điều đó 'ác' mã SQL sẽ không được thực thi.

Trong bảng quản trị, bạn có thể nhập truy vấn ->Update users set admin = true where id = 232 và tôi muốn chặn bất kỳ lệnh UPDATE/DROP/ALTER SQL nào. Chỉ muốn biết, ở đây bạn chỉ có thể thực hiện SELECT.

Sau một số lần thử, tôi kết luận sanitize_sql_array unfortunatelly không làm điều đó.

Có cách nào để thực hiện điều đó trong Rails không ??

Xin lỗi vì sự nhầm lẫn ..

Trả lời

13

Hãy thử điều này:

connect = ActiveRecord::Base.connection(); 
connect.execute(ActiveRecord::Base.send(:sanitize_sql_array, "your string")) 

Bạn có thể lưu nó trong biến và sử dụng cho mục đích của bạn.

+0

Kết quả: 'phương pháp bảo vệ 'sanitize_sql_array' kêu gọi ActiveRecord :: Base: Class' –

+1

Tôi đã cập nhật bài đăng của mình. Tôi hy vọng nó sẽ giúp bạn – bor1s

+0

..hoặc bạn có thể sử dụng điều này: 'ActiveRecord :: Base.send (: sanitize_sql_array," chuỗi của bạn ")' – bor1s

9

Tôi đã tạo một đoạn mã nhỏ cho điều này mà bạn có thể đặt vào bộ khởi tạo.

class ActiveRecord::Base 
    def self.escape_sql(array) 
    self.send(:sanitize_sql_array, array) 
    end 
end 

Ngay bây giờ bạn có thể thoát khỏi truy vấn của bạn với điều này:

query = User.escape_sql(["Update users set active = ? where id = ?", true, params[:id]]) 

Và bạn có thể gọi truy vấn bất kỳ cách nào bạn thích:

users = User.find_by_sql(query) 
+2

Điều này sẽ hiệu quả, nhưng chỉ cần lưu ý , bạn sẽ không cần "gửi". Việc gọi một phương thức được bảo vệ được cho phép bởi người nhận khi người gọi là cùng một lớp. Tức là, bạn sẽ chỉ cần định nghĩa phương thức là: "def self.escape_sql (obj); sanitize_sql_array obj; kết thúc;" (dấu chấm phẩy được sử dụng từ SO bình luận xuống cho phép dòng trả lại) –

+0

[Tôi thấy điều này liên quan đến việc thay thế cho vá khỉ] (https://stackoverflow.com/a/2329394/673826) – mlt

+0

Cảm ơn bạn đã thực hiện thêm và đưa ra ví dụ về cách sử dụng nó. –

8

Hơi nhiều mục đích chung:

class ActiveRecord::Base 
    def self.escape_sql(clause, *rest) 
    self.send(:sanitize_sql_array, rest.empty? ? clause : ([clause] + rest)) 
    end 
end 

Điều này cho phép bạn gọi nó giống như bạn nhập vào một mệnh đề where, không có dấu ngoặc đơn phụ và sử dụng kiểu mảng? hoặc nội suy kiểu băm.

+0

Cảm ơn, điều này đã làm việc hoàn hảo. Chỉ cần thêm rằng điều này đi trong initializer. – KPheasey

1

Mặc dù ví dụ này là dành cho truy vấn INSERT, người ta có thể sử dụng cách tiếp cận tương tự cho truy vấn UPDATE.Chèn số lượng lớn SQL thô:

users_places = [] 
users_values = [] 
timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S') 
params[:users].each do |user| 
    users_places << "(?,?,?,?)" # Append to array 
    users_values << user[:name] << user[:punch_line] << timestamp << timestamp 
end 

bulk_insert_users_sql_arr = ["INSERT INTO users (name, punch_line, created_at, updated_at) VALUES #{users_places.join(", ")}"] + users_values 
begin 
    sql = ActiveRecord::Base.send(:sanitize_sql_array, bulk_insert_users_sql_arr) 
    ActiveRecord::Base.connection.execute(sql) 
rescue 
    "something went wrong with the bulk insert sql query" 
end 

Đây là reference to sanitize_sql_array method in ActiveRecord::Base, nó tạo chuỗi truy vấn thích hợp bằng cách thoát dấu nháy đơn trong chuỗi. Ví dụ: punch_line "Đừng để họ đưa bạn xuống" sẽ trở thành "Đừng để họ đưa bạn xuống".

Các vấn đề liên quan