rails query errors ruby-on-rails ruby hashmap null

ruby-on-rails - query - rails errors



¿Hay alguna manera clara de evitar llamar a un método en nil en un hash de parámetros anidado? (12)

  1. Puedes usar #try , pero no creo que sea mucho mejor:

    params[:subject].try(:[], :name)

  2. O usa #fetch con el parámetro predeterminado:

    params.fetch(:subject, {}).fetch(:name, nil)

  3. O puede configurar #default= a hash vacío nuevo, pero luego no intente modificar los valores devueltos por esto:

    params.default = {} params[:subject][:name]

    También rompe todas las pruebas simples de existencia, por lo que no puedes escribir:

    if params[:subject]

    porque devolverá hash vacío, ahora tienes que agregar #present? llamar a cada prueba.

    También esto siempre devuelve hash cuando no hay ningún valor para la clave, incluso cuando espera una cadena.

Pero por lo que veo, intentas extraer el parámetro anidado, en lugar de asignarlo al modelo y ubicar tu lógica. Si tiene un modelo de Subject , simplemente asigne:

@subject = Subject.new(params[:subject])

shuld extraerá todos los parámetros que el usuario haya rellenado. Luego intente guardarlos para ver si el usuario pasó valores válidos.

Si está preocupado por acceder a los campos que el usuario no debe configurar, agregue la lista blanca attr_accessible para los campos a los que se les debe permitir asignarlos en masa (como en mi ejemplo, con @subject.attributes = params[:subject] para la actualización)

Estoy interesado en obtener el parámetro "nombre" anidado de hash de params. Llamando algo así como

params[:subject][:name]

arroja un error cuando params [: subject] está vacío. Para evitar este error, suelo escribir algo como esto:

if params[:subject] && params[:subject][:name]

¿Hay una manera más limpia de implementar esto?


Compruebe Ick es tal vez . No es necesario refactorizar significativamente su código, simplemente intercalar los proxies cuando sea necesario:

params[:subject].maybe[:name]

El mismo autor ( raganwald ) también escribió andand , con la misma idea.


Cuando tengo el mismo problema en la codificación, a veces uso `rescue ''.

name = params[:subject][:name] rescue "" # => ""

Esto no es buenos modales, pero creo que es una manera simple.

EDITAR: Ya no uso esta manera a menudo. Recomiendo try o fetch .


Escribí a Dottie solo para este caso de uso: profundizar en un hash sin saber primero si existe todo el árbol esperado. La sintaxis es más sucinta que usar try (Rails) o maybe (Ick). Por ejemplo:

# in a Rails request, assuming `params` contains: { ''person'' => { ''email'' => ''[email protected]'' } } # there is no ''subject'' # standard hash access (symbols will work here # because params is a HashWithIndifferentAccess) params[:person][:email] # => ''[email protected]'' params[:subject][:name] # undefined method `[]'' for nil:NilClass # with Dottie Dottie(params)[''person.email''] # => ''[email protected]'' Dottie(params)[''subject.name''] # => nil # with Dottie''s optional class extensions loaded, this is even easier dp = params.dottie dp[''person.email''] # => ''[email protected]'' dp[''subject.name''] # => nil dp[''some.other.deeply.nested.key''] # => nil

Consulte los documentos si desea ver más: Dottie


Lo crucé por mi respuesta aquí:

¿Cómo verificar si params [: some] [: field] es nil?

He estado buscando una mejor solución también.

Así que pensé que vamos a usar una forma diferente de probar una clave anidada que se está configurando:

params[:some].try(:has_key?, :field)

No está mal. Obtienes nil vs. false si no está configurado. También se true si el parámetro está establecido en nil .


O bien, agregue [] a ella.

class NilClass; def [](*); nil end end params[:subject][:name]


Puede evitar el doble acceso hash con una asignación en línea:

my_param = subj_params = params[:subject] && subj_params[:name]



Ruby 2.3.0 hace que esto sea muy fácil de hacer con #dig

h = {foo: {bar: {baz: 1}}} h.dig(:foo, :bar, :baz) #=> 1 h.dig(:foo, :zot, :baz) #=> nil


Solía:

params = {:subject => {:name => "Jack", :actions => {:peaceful => "use internet"}}} def extract_params(params, param_chain) param_chain.inject(params){|r,e| r=((r.class.ancestors.include?(Hash)) ? r[e] : nil)} end extract_params(params, [:subject,:name]) extract_params(params, [:subject,:actions,:peaceful]) extract_params(params, [:subject,:actions,:foo,:bar,:baz,:qux])

da:

=> "Jack" => "use internet" => nil


params[:subject].try(:[], :name) es la forma más limpia


class Hash def fetch2(*keys) keys.inject(self) do |hash, key| hash.fetch(key, Hash.new) end end end

p.ej

require ''minitest/autorun'' describe Hash do it "#fetch2" do { yo: :lo }.fetch2(:yo).must_equal :lo { yo: { lo: :mo } }.fetch2(:yo, :lo).must_equal :mo end end