Korzystanie z pomocników w modelu: jak uwzględnić zależności pomocników?

100

Piszę model, który obsługuje dane wejściowe użytkownika z obszaru tekstowego. Zgodnie z radą z http://blog.caboo.se/articles/2008/8/25/sanitize-your-users-html-input , czyszczę dane wejściowe w modelu przed zapisaniem do bazy danych, używając metody before_validate oddzwonić.

Odpowiednie części mojego modelu wyglądają następująco:

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

Nie trzeba dodawać, że to nie działa. Gdy próbuję zapisać nowy wpis, pojawia się następujący błąd.

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

Wygląda na to, że SanitizeHelper tworzy instancję HTML :: WhiteListSanitizer, ale kiedy mieszam ją z moim modelem, nie może znaleźć HTML :: WhiteListSanitizer. Czemu? Co mogę z tym zrobić, aby to naprawić?

O. Frabjous-Dey
źródło

Odpowiedzi:

133

Po prostu zmień pierwszą linię w następujący sposób:

include ActionView::Helpers

to sprawi, że to zadziała.

AKTUALIZACJA: Do użytku w Rails 3:

ActionController::Base.helpers.sanitize(str)

Zasługa odpowiedź lornc za

Alfreddd
źródło
sam nie mógłbym tego lepiej
wyrazić
1
Dzięki. Mam to do pracy, przenosząc dołączenie do wewnątrz definicji klasy.
O. Frabjous-Dey
1
Dzięki temu dostaję stack level too deep. Znajduje się w metodzie before_save.
Automatico
42
Nie mieszaj problemów dotyczących warstwy widoku z modelami aktywnych rekordów. To straszna praktyka. Znacznie lepszym podejściem jest umieszczenie samodzielnego obiektu sanityzatora danych wejściowych przed AR i pobranie z niego „czystych” atrybutów.
solnic
1
To bardzo złe rozwiązanie i należy go unikać jak ognia. Railsy są oparte na frameworku MVC (Model View Controller), w którym pomocnik znajduje się w części View, więc nie należy mieszać metod pomocniczych widoku z modelem.
jedi
132

To daje tylko metodę pomocniczą bez efektów ubocznych ładowania każdej metody ActionView :: Helpers do twojego modelu:

ActionController::Base.helpers.sanitize(str)
lornc
źródło
6
Dla powolnych ludzi, takich jak ja - nie musisz niczego dołączać, po prostu użyj ActionController :: Base.helpers.sanitize ("Na łańcuchu, który chcesz wyczyścić")
Edward
Dziękuję, pracowałem w Railsach 2.3.14, podczas gdy zaakceptowana odpowiedź nie.
ChrisInEdmonton
Dodałem metodę do application_helper, ale nie mogłem uzyskać do niej dostępu z modelu za pomocą ActionController :: Base.helpers.my_method (opcje) przy użyciu Rails 3.0.3?
Tom Rossi
35

To działa lepiej dla mnie:

Prosty:

ApplicationController.helpers.my_helper_method

Postęp:

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

Źródło: http://makandracards.com/makandra/1307-how-to-use-helper-methods-inside-a-model

skozz
źródło
1
ApplicationController.master_helper_moduleNie istnieje dłużej w Rails 3 i 4 wydaje. Ale ApplicationController.helpersjest ładny.
Samuel
Głosowałem na tę (prostą opcję), ponieważ odpowiadała moim potrzebom - potrzebuję tylko jednego pomocnika, który korzysta z informacji zapisanych przez filtr before w ApplicationController, więc w moim przypadku jawne przypisanie jest przypomnieniem, że istnieje sprzężenie. [Przykład zastosowania to aplikacja z wieloma domenami, która wysyła e-maile za pośrednictwem powiadamiacza modelu z linkiem URL do aplikacji - ten adres URL zmienia się w zależności od domeny żądania internetowego]
iheggie
24

Aby uzyskać dostęp do pomocników z własnych kontrolerów, po prostu użyj:

OrdersController.helpers.order_number(@order)
Tarmo
źródło
2
Po prostu używam ApplicationController.helpers.order_number(@order). To znaczy, że order_numberzlokalizowano dniaOrder Helper
ksugiarto
3
@rowanu Mówi „aby uzyskać dostęp (pomocnicy z twoich własnych kontrolerów)”, a nie „(aby uzyskać dostęp do pomocników) z twoich własnych kontrolerów”.
Ajedi, 32
11

Nie polecałbym żadnej z tych metod. Zamiast tego umieść go we własnej przestrzeni nazw.

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
źródło
11

Jeśli chcesz skorzystać z modelu my_helper_methodinside a, możesz napisać:

ApplicationController.helpers.my_helper_method
Atchyut Nagabhairava
źródło