Cómo hacer attr_accessor_with_default en ruby?

Algún código que he tenido que utilizar attr_accessor_with_default en rails modelo es que ahora me da un mismo mensaje de advertencia, que me dice que «el Uso de Ruby en su lugar!»

Así, pensando que tal vez había un nuevo bits en ruby 1.9.2 que hizo attr_accessor manejar los valores predeterminados, la busqué en google, pero yo no lo veo. Me hizo ver un montón de métodos para anular attr_accessor para manejar los valores predeterminados sin embargo.

Es que lo que quieren decir cuando me dicen que «el Uso de Ruby?» O se supone que voy a escribir completo getters/setters ahora? O es que hay alguna nueva manera me puedo encontrar?

  • No creo que esta mejor práctica en cualquier forma. Aunque tengo curiosidad de por qué usted desea utilizar como un patrón.
  • Muy simplemente porque quiero un bool que por defecto true. ¿Por qué no ser esto una mejor práctica? En el momento en que fue una característica del lenguaje, muy conciso y fácil de leer.
InformationsquelleAutor Dave Sanders | 2011-08-13

7 Kommentare

  1. 13
    attr_accessor :pancakes
    
    def after_initialize
         return unless new_record?
         self.pancakes = 11
    end

    Esto asegura que el valor se inicializa a algunos predeterminado para un nuevo registro.

    • Este parece ser dependiente de ActiveRecord. FYI para la siguiente persona que venga.
  2. 29

    Este apidock página sugiere que acaba de hacer en el método initialize.

    class Something
      attr_accessor :pancakes
    
      def initialize 
        @pancakes = true
        super
      end
    end

    No olvide llamar super especialmente cuando se utiliza ActiveRecord o similar.

    • Por cierto: este debe ser validado respuesta, ya que viene sin ningún tipo de dependencia.
    • Esto no funciona en Rails 4.2. Conseguirá «número incorrecto de argumentos de error», en lugar de utilizar def initialize(atributos={}) Doc: api.rubyonrails.org/classes/ActiveModel/Model.html
  3. 4

    Puesto que usted probablemente sabe que sus datos bastante bien, puede ser bastante aceptable asumir nil no es un valor válido.

    Esto significa que usted puede hacer con una after_initialize, ya que este será ejecutado por cada objeto que se crea. Como varias personas han señalado, esto es potencialmente desastrosas para el rendimiento. También, inline el método como en el ejemplo está en desuso en Rails 3.1, de todos modos.

    A la «utilización de Ruby en lugar de’ me gustaría llevar este enfoque:

    attr_writer :pancakes
    
    def pancakes
      return 12 if @pancakes.nil?
      @pancakes
    end

    Para recortar el Rubí mágico sólo un poco y escribir sus propios votos. Después de todo esto es exactamente lo que usted está tratando de lograr, y es agradable y lo suficientemente simple para que cualquiera de envolver su cabeza alrededor.

    • Lo siento, pero eso es demasiado hinchazón/hace todo a lo complejo si se usa a menudo. Pero si usted realmente quiere tomar ese camino: def pancakes ; @pancakes || 12 ; end
    • Hola, gracias por la downvote (no)! Su «mejora» tiene un grave defecto. Devolverá true cuando el valor de la variable de instancia es falso. Usted ve que es exactamente equivocado? Gran. Esta es la razón por la que he añadido la «hinchazón» para comprobar nil lugar. Que, dependiendo de las circunstancias, puede ser bastante aceptable.
    • Yo upvoted, porque es una respuesta válida. Mi única pregunta sería, cuando el objeto se guarda, se va a utilizar ese defecto porque el ahorrar se va a utilizar ese descriptor de acceso? O usted todavía tiene que tener el defecto de la tabla, lo que significa el seguimiento en dos lugares, que es «malo». Supongo que yo pudiera ir a probarlo. 🙂 Y escribir la «hinchazón» en una sola línea puede escribir: def panqueques; @panqueques.nil? ? 12 : @panqueques; end. 🙂
    • Generalmente prefiero los chistes def pancakes ; @pancakes.nil? ? 12 : @pancakes ; end.
    • ¿Por qué alguien querría tener un campo booleano que tiene nil valores enmascarados como valor de 12? O. O Wow.. no hagas eso. Es una locura. La vida no necesita ser tan complicado.
    • Como me di cuenta, usted no debe usar este patrón si desea inicializar una matriz. No se si esperar << a trabajar como la primera matriz de la operación. Pensando, tiene sentido. def arr; @arr.nil? ? [] : @arr; end va a crear una nueva matriz cada vez que use <<, pero nada asigna la matriz de vuelta a @arr. Terminé con def arr; @arr ||= []; end como que le asigne @arr ronda por primera vez. Como para Joost la objeción, creo que si un atributo puede contener 12 y falsa, puede ser el momento de tener una larga, difícil buscar en el código… Pero en la (esperemos) raras ocasiones es necesario, hinchazón de distancia.

  4. 1

    Este es un ooooold pregunta, pero el problema general todavía cultivos hacia arriba y me encontré aquí.

    Las otras respuestas son variadas e interesantes, pero me he encontrado con problemas con todos ellos al inicializar matrices (especialmente en lo que yo quería ser capaz de utilizarlos en un nivel de clase antes de inicializar fue llamado en el ejemplo). He tenido éxito con:

    attr_writer :pancakes
    
    def pancakes
      @pancakes ||= []
    end

    Si utiliza = en lugar de ||= usted encontrará que la << el operador no para de agregar el primer elemento de la matriz. (Anónimo matriz se crea, se asigna un valor a la misma, pero nunca se asignó de nuevo a @panqueques.)

    Por ejemplo:

    obj.pancakes
    #=> []
    obj.pancakes << 'foo'
    #=> ['foo']
    obj.pancakes
    #=> [] 
    #???#!%$#@%FRAK!!!

    Como este es un problema sutil y podría causar algunos cabeza de arañazos, pensé que valía la pena mencionar aquí.

    Este patrón tendrá que ser alterado por un bool, por ejemplo si quieres por defecto false:

    attr_writer :pancakes
    
    def pancakes
      @pancakes.nil? ? @pancakes = false : @pancakes
    end

    Aunque se podría argumentar que la asignación no es estrictamente necesario cuando se trata de un bool.

  5. 0

    No hay nada mágico en 1.9.2 para inicializar las variables de instancia que se establece con attr_accessor. Pero no es el after_initialize de devolución de llamada:

    La after_initialize de devolución de llamada será llamado cada vez que un Registro Activo objeto es instanciado, ya sea directamente a través de nuevos o cuando un registro se carga desde la base de datos. Puede ser útil para evitar la necesidad de directamente anular su Registro Activo initialize método.

    Así:

    attr_accessor :pancakes
    after_initialize :init
    
    protected
    def init
        @pancakes = 11
    end

    Esto es más seguro que algo como esto:

    def pancakes
        @pancakes ||= 11
    end

    porque nil o false podría ser perfectamente válido de valores después de la inicialización y asumiendo que no puede causar algunos interesante errores.

    • Sólo una advertencia de que si no Post.all y devuelve un conjunto de 1.000 Post objetos, que va a ejecutar este after_initialize de devolución de llamada en todos ellos. No es el fin del mundo, pero algo a tener en cuenta cuando se cambia la escala.
    • Si usted Post.all en el código real, a continuación, un extra de 1000 llamadas de método es el menor de sus preocupaciones.
    • Cierto, pero si es en los Rieles Guía de inicio, es en muchos de los nuevos Carriles-desarrollador de códigos base. 😉
    • Tiene sentido, y yo no lo uso Posterior.todos. Sin embargo, con Rieles deseo de simplificar todo, ¿por qué diablos tendría que van a dejar de usar _with_default?
    • No sé, a veces los Rieles de la gente ave más la actitud de sentido (que debe conseguir un poco sucio se ve 🙂
    • sí, después de trabajar con RoR para un año o así, estoy bastante asustado de la plataforma sólo por el capricho de la naturaleza de la obsoletos y los principales cambios que ocurren en las versiones secundarias. La materia extraña.
    • No importa la falta de documentación de las interfaces, seguimiento a través de la fuente realmente no es un sustituto para un simple «se supone que se comportan como X» de la declaración. Y el fanboyism. Esperemos que crezcan.
    • Este parece ser dependiente de ActiveRecord. FYI para la siguiente persona que venga.

  6. 0

    Me pregunto si simplemente usando Rails aplicación funcione para usted:

    http://apidock.com/rails/Module/attr_accessor_with_default

    def attr_accessor_with_default(sym, default = nil, &block)
      raise 'Default value or block required' unless !default.nil? || block
      define_method(sym, block_given? ? block : Proc.new { default })
      module_eval(      def #{sym}=(value)                        # def age=(value)        class << self; attr_reader :#{sym} end  #   class << self; attr_reader :age end        @#{sym} = value                         #   @age = value      end                                       # end, __FILE__, __LINE__ + 1)
    end
  7. -1

    Puede especificar valores por defecto para las instancias de cualquier clase (no sólo ActiveRecords) después de aplicar el parche para Module:

    class Zaloop
    
      attr_accessor var1: :default_value, var2: 2
    
      def initialize
        self.initialize_default_values
      end
    
    end
    
    puts Zaloop.new.var1 # :default_value

    Parche para el módulo:

    Module.module_eval do
    
      alias _original_attr_accessor attr_accessor
      def attr_accessor(*args)
        attr_names = extract_default_values args
        _original_attr_accessor *attr_names
      end
    
      alias _original_attr_reader attr_reader
      def attr_reader(*args)
        attr_names = extract_default_values args
        _original_attr_reader *attr_names
      end
    
      def extract_default_values(args)
        @default_values ||= {}
        attr_names = []
        args.map do |arg|
          if arg.is_a? Hash
            arg.each do |key, value|
              define_default_initializer if @default_values.empty?
              @default_values[key] = value
              attr_names << key
            end
          else
            attr_names << arg
          end
        end
        attr_names
      end
    
      def define_default_initializer
        default_values = @default_values
        self.send :define_method, :initialize_default_values do
          default_values.each do |key, value|
            instance_variable_set("@#{key}".to_sym, value)
          end
        end
      end
    
      def initialize_default_values
        # Helper for autocomplete and syntax highlighters
      end
    
    end

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea