2011-08-22 58 views
16

有沒有辦法在rails方法find_by_sql中清理sql?Rails,如何在find_by_sql中清理SQL

我試過這個解決方案: Ruby on Rails: How to sanitize a string for SQL when not using find?

但在

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

它拋出一個錯誤失敗,但執行的SQL代碼,並與ID 2用戶現在有一個禁用的帳戶。

簡單find_by_sql也不起作用:

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

編輯:

那麼我的要求,使該功能(通過SQL SELECT)的管理面板,使一些複雜的查詢客戶端(連接,特殊條件等)。所以我真的想find_by_sql那個。

第二個編輯:

我想實現這個「邪惡」的SQL代碼不會被執行。

在管理面板中,您可以鍵入查詢 - >Update users set admin = true where id = 232,我想阻止任何UPDATE/DROP/ALTER SQL命令。 只是想知道,在這裏你只能執行SELECT。

經過一番嘗試,我得出結論sanitize_sql_array不幸的是不這樣做。

有沒有辦法在Rails中做到這一點?

很抱歉的混亂..

回答

13

試試這個:

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

您可以將其保存在變量,並使用你的目的。

+0

結果:'保護方法 'sanitize_sql_array' 稱爲ActiveRecord的::基地:Class' –

+1

我已更新我的帖子。我希望它會幫助你 – bor1s

+0

..或者你可以使用這個:'ActiveRecord :: Base.send(:sanitize_sql_array,「你的字符串」)' – bor1s

9

我爲此做了一個小小的片段,您可以將它們放入初始化程序中。

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

現在你可以用這個逃避查詢:

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

而且你可以打電話查詢您喜歡的任何方式:

users = User.find_by_sql(query) 
+2

這將工作,但只是一個擡頭,你將不需要「發送」。當調用者是同一個類時,接收者允許調用受保護的方法。也就是說,您只需要將方法定義爲: 「def self.escape_sql(obj); sanitize_sql_array obj; end;」 (使用分號,因爲SO註釋允許返回行) –

+0

[我發現這個有關替代猴子修補的相關內容](https://stackoverflow.com/a/2329394/673826) – mlt

+0

感謝您的額外和舉例關於如何使用它。 –

8

稍微更通用:

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

這一個讓你像調用where子句一樣調用它,而不使用額外的括號,並使用數組樣式?或散列式插值。

+0

謝謝,這工作完美。只要補充一點,這是在初始化器中。 – KPheasey

1

儘管此示例適用於INSERT查詢,但可以使用類似的方法進行UPDATE查詢。原始SQL BULK INSERT:

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 

這裏是reference to sanitize_sql_array method in ActiveRecord::Base,它通過轉義字符串中的單引號生成適當的查詢字符串。例如punch_line「不要讓他們讓你失望」會變成「不要讓他們讓你失望」。