2011-08-22 11 views
16

Czy istnieje sposób na dezynfekcję sql w metodzie szyn find_by_sql?Szyny, jak dezynfekować SQL w find_by_sql

Próbowałem tego rozwiązania: Ruby on Rails: How to sanitize a string for SQL when not using find?

Ale to nie na

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

zgłasza błąd, ale kod SQL jest wykonywane, a użytkownik o identyfikatorze 2 ma teraz konto niepełnosprawnego.

Proste find_by_sql też nie działa:

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

Edit:

Więc mój klient poprosił o możliwość takiej funkcji (wybór przez SQL) w panelu administratora, aby trochę skomplikowany kwerendy (przyłącza, specjalne warunki itp.). Naprawdę chcę to znaleźć.

Druga Edycja:

chcę osiągnąć, że „zło” kod SQL nie zostanie wykonana.

W panelu administracyjnym można wpisać zapytanie ->Update users set admin = true where id = 232 i chcę zablokować dowolne polecenie aktualizacji UPDATE/DROP/ALTER. Chcę tylko wiedzieć, że tutaj możesz wykonać WYŁĄCZ TYLKO.

Po kilku próbach stwierdzam, że nie robię tego. sanitize_sql_array

Czy istnieje sposób, aby to zrobić w Rails?

Przepraszamy za zamieszanie ..

Odpowiedz

13

Spróbuj tego:

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

Można zapisać go w zmiennej i wykorzystać do swoich celów.

+0

Wynik: 'metoda chronione 'sanitize_sql_array' wezwał do ActiveRecord :: Base: Class' –

+1

Zaktualizowałem swój post. Mam nadzieję, że to ci pomoże – bor1s

+0

..lub możesz użyć tego: 'ActiveRecord :: Base.send (: sanitize_sql_array," twój ciąg ")' – bor1s

9

Zrobiłem mały fragment, który można umieścić w inicjalizatorach.

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

Teraz można uciec zapytanie z tego:

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

I można nazwać zapytaniu dowolny sposób:

users = User.find_by_sql(query) 
+2

To zadziała, ale tylko heads-up , nie będziesz potrzebować "wysłać". Wywołanie metody chronionej jest dozwolone przez odbiorcę, gdy wywołujący jest tą samą klasą. Oznacza to, że będziesz potrzebować tylko definicji metody: "def self.escape_sql (obj); sanitize_sql_array obj; koniec;" (średniki używane od momentu, w którym komentarze SO zezwalają na linie powrotne) –

+0

[Znalazłem, że dotyczy to alternatywy dla poprawek małpich] (https://stackoverflow.com/a/2329394/673826) – mlt

+0

Dziękuję za odejście i podanie przykładu o tym, jak z niego korzystać. –

8

Nieco bardziej ogólnego przeznaczenia:

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

Ten pozwala nazwij go tak, jakbyś wpisał klauzulę where, bez dodatkowych nawiasów i używając stylu tablicowego? lub interpolacje w stylu hash.

+0

Dzięki, to działało idealnie. Wystarczy dodać, że to idzie w inicjatora. – KPheasey

1

Chociaż ten przykład dotyczy zapytania INSERT, można zastosować podobne podejście do zapytań UPDATE.Raw wkładka SQL luzem:

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 

Oto reference to sanitize_sql_array method in ActiveRecord::Base generuje właściwą ciąg kwerendy przez ucieczki apostrofów w struny. Na przykład, punch_line "Nie pozwól im się zepsuć" stanie się "Nie pozwól im się zepsuć".