web-dev-qa-db-fra.com

Comment désinfecter un fragment SQL dans Rails

Je dois nettoyer une partie de la requête SQL. Je peux faire quelque chose comme ça:

class << ActiveRecord::Base
  public :sanitize_sql
end

str = ActiveRecord::Base.sanitize_sql(["AND column1 = ?", "two's"], '')

Mais ce n'est pas sûr parce que j'expose la méthode protégée. Quelle est la meilleure façon de le faire?

35
dimus

Vous pouvez simplement utiliser: 

ActiveRecord::Base::sanitize(string)
42
HashDog Team

ActiveRecord::Base.connection.quote fait le tour dans Rails 3.x

13
dimus

Cette question ne spécifie pas que la réponse doit provenir de ActiveRecord et ne précise pas non plus quelle version de Rails elle devrait être. Pour cette raison (et parce que c’est l’un des meilleurs), on explique comment assainir les paramètres dans Rails ...


Voici une solution qui fonctionne avec Rails 4:

Dans ActiveRecord::Sanitization::ClassMethods, vous avez sanitize_sql_for_conditions et ses deux autres alias): sanitize_conditions et sanitize_sql. Les trois font littéralement exactement la même chose.

sanitize_sql_for_conditions

Accepte un tableau, un hachage ou une chaîne de conditions SQL et désinfecte les dans un fragment SQL valide pour une clause WHERE.

Aussi dans ActiveRecord vous avez

sanitize_sql_for_assignment qui

Accepte un tableau, un hachage ou une chaîne de conditions SQL et les assainit dans un fragment SQL valide pour une clause SET.

  • Les méthodes ci-dessus sont incluses dans ActiveRecord :: Base par défaut et sont donc incluses dans tout modèle ActiveRecord.

Voir docs


Cependant, dans ActionController, vous avez ActionController::Parameters qui vous permet de

choisissez quels attributs doivent être ajoutés à la liste blanche pour la mise à jour en masse et évitez donc d'exposer accidentellement ce qui ne devrait pas être exposé . Fournit deux méthodes à cette fin: require et permit.

params = ActionController::Parameters.new(user: { name: 'Bryan', age: 21 })
req  = params.require(:user) # will throw exception if user not present
opt  = params.permit(:name)  # name parameter is optional, returns nil if not present
user = params.require(:user).permit(:name, :age) # user hash is required while `name` and `age` keys are optional

La "magie des paramètres" s’appelle Strong Parameters ( docs here ) et vous pouvez l’utiliser pour nettoyer les paramètres dans un contrôleur avant de l’envoyer à un modèle.

  • Les méthodes ci-dessus sont incluses par défaut dans ActionController::Base et sont donc incluses dans tout contrôleur Rails.

J'espère que cela aidera n'importe qui, ne serait-ce que pour apprendre et démystifier Rails! :)

8
Bryan Dimas

Vous pouvez contourner la valeur protectedness de la méthode en appelant indirectement:

str = ActiveRecord::Base.__send__(:sanitize_sql, ["AND column1 = ?", "two's"], '')

... ce qui vous évitera au moins de devoir refaire cette méthode en public.

(Je suis un peu méfiant sur le fait que vous ayez réellement besoin de faire ça, mais ça va marcher.)

4
pilcrow

A partir de Rails 5, la méthode recommandée consiste à utiliser: ActiveRecord::Base.connection.quote(string)

comme indiqué ici: https://github.com/Rails/rails/issues/28947

ActiveRecord::Base::sanitize(string) est obsolète

3
Lucian Tarna

Notez que lorsqu'il s'agit de nettoyer les conditions SQL WHERE, la meilleure solution étaitsanitize_sql_hash_for_conditions , car elle gérait correctement les conditions NULL (par exemple, générerait IS NULL au lieu de = NULL si un attribut nil était passé).

Pour une raison quelconque, il était obsolète dans Rails 5. J'ai donc lancé une version à l'épreuve du futur, voir ici: https://stackoverflow.com/a/53948665/165673

0
Yarin