Usando ayudantes en el modelo: ¿cómo incluyo las dependencias de ayuda?

100

Estoy escribiendo un modelo que maneja la entrada del usuario desde un área de texto. Siguiendo el consejo de http://blog.caboo.se/articles/2008/8/25/sanitize-your-users-html-input , estoy limpiando la entrada en el modelo antes de guardarla en la base de datos, usando before_validate llamar de vuelta.

Las partes relevantes de mi modelo se ven así:

include ActionView::Helpers::SanitizeHelper

class Post < ActiveRecord::Base {
  before_validation :clean_input

  ...

  protected

  def clean_input
    self.input = sanitize(self.input, :tags => %w(b i u))
  end
end

No hace falta decir que esto no funciona. Recibo el siguiente error cuando intento guardar una publicación nueva.

undefined method `white_list_sanitizer' for #<Class:0xdeadbeef>

Aparentemente, SanitizeHelper crea una instancia de HTML :: WhiteListSanitizer, pero cuando lo mezclo con mi modelo no puede encontrar HTML :: WhiteListSanitizer. ¿Por qué? ¿Qué puedo hacer al respecto para solucionarlo?

O. Frabjous-Dey
fuente

Respuestas:

133

Simplemente cambie la primera línea de la siguiente manera:

include ActionView::Helpers

eso hará que funcione.

ACTUALIZACIÓN: Para Rails 3 use:

ActionController::Base.helpers.sanitize(str)

El crédito va a la respuesta de lornc

Alfreddd
fuente
Yo
1
Gracias. Lo hice funcionar moviendo la inclusión dentro de la definición de la clase.
O. Frabjous-Dey
1
Con esto lo consigo stack level too deep. Está en un método before_save.
Automatico
42
No mezcle las preocupaciones de la capa de vista con los modelos de registros activos. Esa es una práctica terrible. Un enfoque mucho mejor es colocar un objeto desinfectante de datos de entrada independiente frente a AR y recuperar atributos "limpios" de él.
solnic
1
Esta es una muy mala solución y debe evitarse como el fuego. Rails se basa en el marco MVC (Model View Controller) donde el ayudante viene en la parte de Vista, por lo que no debe mezclar los métodos de ayuda de vista con el modelo.
jedi
132

Esto le brinda solo el método auxiliar sin los efectos secundarios de cargar cada método ActionView :: Helpers en su modelo:

ActionController::Base.helpers.sanitize(str)
lornc
fuente
6
Para la gente lenta como yo, no es necesario que incluya nada, solo use ActionController :: Base.helpers.sanitize ("En la cadena que desea desinfectar")
Edward
Gracias, funcionó en Rails 2.3.14 mientras que la respuesta aceptada no lo hizo.
ChrisInEdmonton
Agregué un método a application_helper, pero no pude acceder a él desde el modelo usando ActionController :: Base.helpers.my_method (opciones) usando Rails 3.0.3?
Tom Rossi
35

Esto funciona mejor para mí:

Sencillo:

ApplicationController.helpers.my_helper_method

Avanzar:

class HelperProxy < ActionView::Base
  include ApplicationController.master_helper_module

  def current_user
    #let helpers act like we're a guest
    nil
  end       

  def self.instance
    @instance ||= new
  end
end

Fuente: http://makandracards.com/makandra/1307-how-to-use-helper-methods-inside-a-model

skozz
fuente
1
La ApplicationController.master_helper_moduleno existe más en los carriles 3 y 4 que aparece. Sin ApplicationController.helpersembargo, es bueno.
Samuel
Voté por esto (la opción simple) porque se adaptaba a mis necesidades: solo necesito un ayudante que use la información guardada por un filtro anterior en ApplicationController, por lo que en mi caso, hacer la asociación explícita es un recordatorio de que hay un acoplamiento. [El caso de uso es una aplicación de varios dominios, que emite correos electrónicos a través de un notificador de modelo con un enlace de URL a la aplicación; esta URL cambia según el dominio de la solicitud web]
iheggie
24

Para acceder a los ayudantes desde sus propios controladores, simplemente use:

OrdersController.helpers.order_number(@order)
Tarmo
fuente
2
Solo usando ApplicationController.helpers.order_number(@order). Eso significa que se order_numberubicó elOrder Helper
ksugiarto
3
@rowanu Está diciendo "para acceder a (ayudantes desde sus propios controladores)", no "(para acceder a ayudantes) desde sus propios controladores".
Ajedi32
11

No recomendaría ninguno de estos métodos. En su lugar, colóquelo dentro de su propio espacio de nombres.

class Post < ActiveRecord::Base
  def clean_input
    self.input = Helpers.sanitize(self.input, :tags => %w(b i u))
  end

  module Helpers
    extend ActionView::Helpers::SanitizeHelper
  end
end
axsuul
fuente
11

Si desea utilizar el my_helper_methodinterior de un modelo, puede escribir:

ApplicationController.helpers.my_helper_method
Atchyut Nagabhairava
fuente