significa que example ruby hash sinatra sequel

que - hash.map ruby



Cortar hash de parámetros para valores específicos (5)

Aquí están mis implementaciones; Analizaré y aceptaré soluciones más rápidas (o suficientemente más elegantes):

# Implementation 1 class Hash def slice(*keys) Hash[keys.zip(values_at *keys)] end end # Implementation 2 class Hash def slice(*keys) {}.tap{ |h| keys.each{ |k| h[k]=self[k] } } end end # Implementation 3 - silently ignore keys not in the original class Hash def slice(*keys) {}.tap{ |h| keys.each{ |k| h[k]=self[k] if has_key?(k) } } end end

Resumen

Dado un Hash, ¿cuál es la forma más eficiente de crear un subconjunto Hash basado en una lista de claves para usar?

h1 = { a:1, b:2, c:3 } # Given a hash... p foo( h1, :a, :c, :d ) # ...create a method that... #=> { :a=>1, :c=>3, :d=>nil } # ...returns specified keys... #=> { :a=>1, :c=>3 } # ...or perhaps only keys that exist

Detalles

El conjunto de herramientas de la base de datos Sequel le permite a uno crear o actualizar una instancia modelo al pasar un Hash:

foo = Product.create( hash_of_column_values ) foo.update( another_hash )

El marco web de Sinatra pone a disposición un Hash llamado params que incluye variables de forma, parámetros de cadena de consulta y también enruta coincidencias.

Si creo un formulario que contenga solo campos con el mismo nombre que las columnas de la base de datos y lo publico en esta ruta, todo funciona muy cómodamente:

post "/create_product" do new_product = Product.create params redirect "/product/#{new_product.id}" end

Sin embargo, esto es frágil y peligroso. Es peligroso porque un pirata informático malintencionado podría publicar un formulario con columnas que no están destinadas a ser modificadas y actualizarlas. Es frágil porque usar la misma forma con esta ruta no funcionará:

post "/update_product/:foo" do |prod_id| if product = Product[prod_id] product.update(params) #=> <Sequel::Error: method foo= doesn''t exist or access is restricted to it> end end

Entonces, para ser robusto y seguro, quiero poder escribir esto:

post "/update_product/:foo" do |prod_id| if product = Product[prod_id] # Only update two specific fields product.update(params.slice(:name,:description)) # The above assumes a Hash (or Sinatra params) monkeypatch # I will also accept standalone helper methods that perform the same end end

... en lugar de la opción más detallada y no SECA:

post "/update_product/:foo" do |prod_id| if product = Product[prod_id] # Only update two specific fields product.update({ name:params[:name], description:params[:description] }) end end

Actualización: puntos de referencia

Estos son los resultados de la evaluación comparativa de las implementaciones (actuales):

user system total real sawa2 0.250000 0.000000 0.250000 ( 0.269027) phrogz2 0.280000 0.000000 0.280000 ( 0.275027) sawa1 0.297000 0.000000 0.297000 ( 0.293029) phrogz3 0.296000 0.000000 0.296000 ( 0.307031) phrogz1 0.328000 0.000000 0.328000 ( 0.319032) activesupport 0.639000 0.000000 0.639000 ( 0.657066) mladen 1.716000 0.000000 1.716000 ( 1.725172)

La segunda respuesta de @sawa es la más rápida de todas, un pelo frente a mi implementación basada en tap (basada en su primera respuesta). ¿Elegir agregar el cheque para has_key? agrega muy poco tiempo, y sigue siendo más del doble de rápido que ActiveSupport.

Aquí está el código de referencia:

h1 = Hash[ (''a''..''z'').zip(1..26) ] keys = %w[a z c d g A x] n = 60000 require ''benchmark'' Benchmark.bmbm do |x| %w[ sawa2 phrogz2 sawa1 phrogz3 phrogz1 activesupport mladen ].each do |m| x.report(m){ n.times{ h1.send(m,*keys) } } end end


Cambié por la mente. El anterior no parece ser bueno.

class Hash def slice1(*keys) keys.each_with_object({}){|k, h| h[k] = self[k]} end def slice2(*keys) h = {} keys.each{|k| h[k] = self[k]} h end end


Quizás

class Hash def slice *keys select{|k| keys.member?(k)} end end

O simplemente podría copiar el segmento Hash#slice ActiveSupport, se ve un poco más robusto.


Sequel tiene soporte incorporado para solo seleccionar columnas específicas al actualizar:

product.update_fields(params, [:name, :description])

Eso no hace exactamente lo mismo si: name o: description no está presente en params, sin embargo. Pero suponiendo que esperas que el usuario use tu formulario, eso no debería ser un problema.

Siempre podría expandir update_fields para tomar un hash de opciones con una opción que omitirá el valor si no está presente en el hash. Simplemente no he recibido una solicitud para hacer eso todavía.


Solo usaría el método de división provisto por active_support

require ''active_support/core_ext/hash/slice'' {a: 1, b: 2, c: 3}.slice(:a, :c) # => {a: 1, c: 3}

Por supuesto, asegúrese de actualizar su gemfile:

gem ''active_support''