Rails: ¿valor predeterminado en text_field pero solo para new_record?

En un modelo de contenido, tenga un atributo llamado slug. Al crear un nuevo registro, quiero usar un ayudante para completar este campo, pero en un registro existente quiero usar el valor de la base de datos.

Actualmente tengo:

<% if @content.new_record? %>
  <%= f.text_field :slug, :value => "#{generate_slug(6)}" %>
<% else %>
  <%= f.text_field :slug %>
<% end %>

Pero eso parece un poco detallado. ¿Es esta la mejor manera o no hay otra manera? (Rails newb solo estoy tratando de encontrar el "camino de Rails" en problemas de los que no estoy seguro)


Editar

Debo señalar que el ayudante se encuentra actualmente en /app/helpers/application_helper.rb Movido para ser una acción privada en el controlador de contenido. La respuesta de David funcionó muy bien.

preguntado el 09 de enero de 11 a las 04:01

3 Respuestas

En tu controlador

@content.slug ||= generate_slug(6)

Esto asignará un valor a la slug atributo si no hay ninguno presente

Entonces, en su opinión, simplemente puede usar

<%= f.text_field :slug %>

Respondido el 09 de enero de 11 a las 07:01

Esto se ve increíble. ¿Cómo puedo hacer que mi ayudante sea accesible dentro del controlador? (generate_slug (6) es un ayudante). yo obtengo undefined method generate_slug 'para # `- José

Borre eso, lo agregué como una acción privada en el controlador de Contenido. ¡No me importa! ¡Gracias por la respuesta! - José

Como señaló carpeliam, dependiendo de cómo y con qué frecuencia usará esta funcionalidad, es posible que desee incluir el modelo como método (`def slug; slug || = generate_slug (6); end). - David Sulc

Opciones

  1. Pruebe after_initialize callback en su modelo.
  2. Intente crear un método en su modelo en el que establezca valores predeterminados y llámelo en su nueva acción en el controlador. También llame a este método si su creación falla y renderiza nuevo. Recuerde establecer el valor predeterminado solo cuando no exista ningún valor mediante el operador || =.

Ejemplo a seguir. ¡Estoy escribiendo en el teléfono!

Respondido el 09 de enero de 11 a las 07:01

after_initialize probablemente no sea su mejor opción, ya que también se llamará cada vez que recupere un objeto de la base de datos. ¿A menos que eso es lo que quieres? - David Sulc

Yo uso jQuery en mis proyectos, así que cuando quiero alguna funcionalidad como esta, suelo usar algo como etiquetar. Entonces, usaría algo como <%= f.text_field :slug, :title => generate_slug(6) %>. (Sugerencia: no es necesario que coloques la llamada #generate_slug dentro de una cadena si devuelve algo que se resolverá en una cadena por sí misma, de hecho, es más eficaz si no lo haces).

Si no desea utilizar el enfoque de jQuery, es posible que desee envolver esta pieza de lógica en su modelo.

def Content < ActiveRecord::Base
  def slug
    self.new_record? ? self.slug_for_new_record : attributes[:slug]
  end

  private
  def slug_for_new_record
    # I don't know what you're doing in generate_slug, but it sounds model-
    # related, so if so, put it here and not in a helper
  end
end

Si realmente pertenece a la vista, otra opción es hacer tu Ruby un poco más conciso (tendrás que juzgar si esto es más legible):

<%= f.text_field :slug, :value => (generate_slug(6) if @content.new_record?) %>

No olvides los parens que rodean (generate_slug(6) if @content.new_record?). Si lo hace, el if se aplicará al campo de texto, que no es lo que desea.

Pero todavía hay más formas de hacerlo. La línea de código anterior no es excelente si su lógica puede cambiar y está pegando este código en todo su proyecto de rieles. Cuando quise agregar una clase 'requerida' a mis campos de texto, pero solo si eran un nuevo registro (teníamos algunos datos heredados que no queríamos que la gente limpiara), creé mi propio generador de formularios con un required_field método que acaba de llamar text_field y agregó una clase 'requerida' si el artículo era un nuevo registro. Esto puede parecer un trabajo, pero tenemos alrededor de 20 formularios diferentes, cada uno con varios campos obligatorios potencialmente, y es mucho más fácil cambiar la lógica empresarial en un solo lugar. Entonces, si realmente cree que esta lógica pertenece a la vista, pero tiene un montón de estas líneas de código y no quiere tener que cambiarlo en un millón de lugares, FormBuilder es el camino a seguir. Creo que en la mayoría de los casos esto es más bonito y más apropiado que un ayudante, pero nuevamente, la belleza está en los ojos del espectador. Aquí está mi código algo adaptado para su caso:

# config/environment.rb
ActionView::Base.default_form_builder = NamespacesAreFun::FormBuilder

# lib/namespaces_are_fun/form_builder.rb
module NamespacesAreFun
  class FormBuilder < ActionView::Helpers::FormBuilder
    def slug_field(method, options = {})
      opts = options.to_options
      opts.merge!(:value => generate_slug) if self.object.new_record?
      text_field(method, opts)
    end
  end
end

# views/.../your_view.html.erb
<%= f.slug_field :slug %>

Con suerte, en todos estos enfoques diferentes es uno que se adapta a su proyecto.

Respondido el 09 de enero de 11 a las 08:01

No tengo privilegios para dejar comentarios sobre la respuesta de David, pero este parece un lugar en el que quizás quieras aplicar "Controlador flaco modelo gordo". weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model - carpeliam

Comenté mi respuesta en ese sentido. Aunque esto debe incluirse en el modelo solo si se usa con frecuencia. Si (por ejemplo) solo se usa como un atributo predeterminado en un solo lugar (por ejemplo, el usuario elige un slug al registrarse, con un valor predeterminado proporcionado para él), debería ir en el controlador en (solo) esa acción específica. - David Sulc

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.