rails query inner includes active ruby-on-rails rails-activerecord nomethoderror

ruby-on-rails - query - scope rails



¿Los rieles intentan el método de lanzar NoMethodError? (3)

¿Por qué se intenta lanzar un error? ¿Eso no derrota todo el propósito? Tal vez es sólo en la consola?

ruby-1.9.2-p180 :101 > User.first.try(:something) NoMethodError: undefined method `something'' for #<User:0x000001046ad128> from /Users/me/.rvm/gems/ruby-1.9.2-p180/gems/activemodel-3.0.10/lib/active_model/attribute_methods.rb:392:in `method_missing'' from /Users/me/.rvm/gems/ruby-1.9.2-p180/gems/activerecord-3.0.10/lib/active_record/attribute_methods.rb:46:in `method_missing'' from (irb):101 from /Users/me/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.10/lib/rails/commands/console.rb:44:in `start'' from /Users/me/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.10/lib/rails/commands/console.rb:8:in `start'' from /Users/me/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.10/lib/rails/commands.rb:23:in `<top (required)>'' from script/rails:6:in `require'' from script/rails:6:in `<main>''

EDITAR:

Gracias chicos, ahora lo entiendo.

¿Hay una manera de hacer lo que quería sin usar respond_to? , ¿tal que User.try(:something) devuelve nil lugar de lanzar el error?


Rieles 3

No entiendes cómo funciona el try , en el fino manual :

prueba (* a, & b)
Invoca el método identificado por el método de símbolo, pasándole cualquier argumento y / o el bloque especificado, tal como lo hace el Object#send regular de Object#send Ruby.

Sin embargo, a diferencia de ese método, una excepción NoMethodError no se generará y en su lugar se devolverá nil , si el objeto receptor es un objeto nil o NilClass .

Y la versión de try que está parcheada en NilClass :

prueba (* args)
Llamar try en nil siempre devuelve nil .

Así que try no ignora su intento de llamar a un método inexistente en un objeto, ignora su intento de llamar a un método en nil y devuelve nil lugar de generar una excepción. El método de try es solo una forma fácil de evitar tener que comprobar si hay nil en cada paso de una cadena de llamadas de método.

Rieles 4

El comportamiento de try ha cambiado en Rails 4 por lo que ahora:

Invoca el método público cuyo nombre public_send como primer argumento, como public_send hace public_send , excepto que si el receptor no responde, la llamada devuelve nil lugar de generar una excepción.

Así que ahora try cuidar ambos controles a la vez. Si quieres el comportamiento de Rails 3, ¡hay que try! :

Igual que try , pero generará una excepción NoMethodError si la recepción [sic] no es nil y no implementó [sic] el método probado.


Esto es lo que hace el intento.

Invoca el método identificado por el método de símbolo, pasándole cualquier argumento y / o el bloque especificado, tal como lo hace el envío regular de objetos Ruby. Sin embargo, a diferencia de ese método, una excepción NoMethodError no se generará y en su lugar se devolverá nil, si el objeto receptor es un objeto nil o NilClass.

Entonces, digamos que configura @user en su controlador pero no lo @user.try(:foo) => nil entonces @user.try(:foo) => nil lugar de

@user.foo NoMethodError: undefined method `foo'' for nil:NilClass

El punto importante aquí es que try es un método de instancia. Tampoco devuelve cero si el objeto que prueba no es nulo .


Sé que esto es viejo, pero puede ayudar a alguien más, porque esto es lo primero que apareció cuando busqué en Google este problema. "Tomé prestado" el código para intentarlo e implementé mi propio método try_method que funciona igual que el intento , excepto que primero verifica si el método existe antes de llamar a enviar . Implementé esto en Object y lo puse en un inicializador, y ahora puedo llamarlo en cualquier objeto.

class Object # Invokes the method identified by _method_, passing it any # arguments specified, just like the regular Ruby <tt>Object#send</tt> does. # # *Unlike* that method however, a +NoMethodError+ exception will *not* be raised # if the method does not exist. # # This differs from the regular Ruby <tt>Object#try</tt> method which only # suppresses the +NoMethodError+ exception if the object is Nil # # If try_method is called without a method to call, it will yield any given block with the object. # # Please also note that +try_method+ is defined on +Object+, therefore it won''t work with # subclasses of +BasicObject+. For example, using try_method with +SimpleDelegator+ will # delegate +try_method+ to target instead of calling it on delegator itself. # # ==== Examples # # Without +try_method+ # @person && @person.respond_to?(:name) && @person.name # or # (@person && @person.respond_to?(:name)) ? @person.name : nil # # With +try_method+ # @person.try_method(:name) # # +try_method+ also accepts arguments and/or a block, for the method it is trying # Person.try_method(:find, 1) # @people.try_method(:collect) {|p| p.name} # # Without a method argument try_method will yield to the block unless the receiver is nil. # @person.try_method { |p| "#{p.first_name} #{p.last_name}" } #-- # +try_method+ behaves like +Object#send+, unless called on +NilClass+ or a class that does not implement _method_. def try_method(method=nil, *args, &block) if method == nil && block_given? yield self elsif respond_to?(method) __send__(method, *args, &block) else nil end end end class NilClass # Calling +try_method+ on +nil+ always returns +nil+. # It becomes specially helpful when navigating through associations that may return +nil+. # # === Examples # # nil.try_method(:name) # => nil # # Without +try_method+ # @person && @person.respond_to(:children) && [email protected]? && @person.children.respond_to(:first) && @person.children.first.respond_to(:name) && @person.children.first.name # # With +try_method+ # @person.try_method(:children).try_method(:first).try_method(:name) def try_method(*args) nil end end