Использование помощников в модели: как включить вспомогательные зависимости?

102

Я пишу модель, которая обрабатывает ввод данных пользователем из текстовой области. Следуя совету http://blog.caboo.se/articles/2008/8/25/sanitize-your-users-html-input , я очищаю ввод в модели перед сохранением в базу данных, используя before_validate Перезвони.

Соответствующие части моей модели выглядят так:

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

Излишне говорить, что это не работает. Я получаю следующую ошибку, когда пытаюсь сохранить новое сообщение.

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

Очевидно, SanitizeHelper создает экземпляр HTML :: WhiteListSanitizer, но когда я добавляю его в свою модель, он не может найти HTML :: WhiteListSanitizer. Зачем? Что я могу сделать, чтобы это исправить?

О. Фрабжу-Дей
источник

Ответы:

134

Просто измените первую строку следующим образом:

include ActionView::Helpers

это заставит его работать.

ОБНОВЛЕНИЕ: для Rails 3 используйте:

ActionController::Base.helpers.sanitize(str)

Кредит идет на ответ Лорнка

Альфредд
источник
сам не мог бы сказать этого лучше
Tilendor
1
Спасибо. Я заставил его работать, переместив включение внутрь определения класса.
О. Фрабжу-Дей,
1
С этим я получаю stack level too deep. Он находится в методе before_save.
Automatico
42
Пожалуйста, не смешивайте проблемы слоя просмотра с активными моделями записи. Это ужасная практика. Гораздо лучший подход - поставить автономный объект дезинфицирующего средства входных данных перед AR и извлечь из него «чистые» атрибуты.
solnic
1
Это очень плохое решение, и его следует избегать, как огня. Rails основан на фреймворке MVC (Model View Controller), где помощник входит в часть представления, поэтому вам не следует смешивать вспомогательные методы представления с моделью.
jedi
132

Это дает вам только вспомогательный метод без побочных эффектов загрузки каждого метода ActionView :: Helpers в вашу модель:

ActionController::Base.helpers.sanitize(str)
Lornc
источник
6
Для медлительных людей вроде меня - вам не нужно ничего включать, просто используйте ActionController :: Base.helpers.sanitize («В строке, которую вы хотите дезинфицировать»)
Эдвард,
Спасибо, работал в Rails 2.3.14, а принятый ответ - нет.
ChrisInEdmonton
Я добавил метод в application_helper, но мне не удалось получить к нему доступ из модели с помощью ActionController :: Base.helpers.my_method (options) с использованием Rails 3.0.3?
Том Росси
36

Для меня это работает лучше:

Просто:

ApplicationController.helpers.my_helper_method

Заранее:

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

Источник: http://makandracards.com/makandra/1307-how-to-use-helper-methods-inside-a-model

skozz
источник
1
Он ApplicationController.master_helper_moduleбольше не существует в Rails 3 и 4, похоже. ApplicationController.helpersХороший один , хотя.
Самуэль
Я проголосовал за этот (простой вариант), потому что он соответствовал моим потребностям - мне нужен только один помощник, который использует информацию, сохраненную предварительным фильтром в ApplicationController, поэтому в моем случае явная привязка является напоминанием о наличии связи. [
Пример использования
24

Чтобы получить доступ к помощникам из ваших собственных контроллеров, просто используйте:

OrdersController.helpers.order_number(@order)
Тармо
источник
2
Просто использую ApplicationController.helpers.order_number(@order). Это означает, что он order_numberбыл расположенOrder Helper
ksugiarto
3
@rowanu Он говорит «для доступа (помощников из ваших собственных контроллеров)», а не «(для доступа к помощникам) из ваших собственных контроллеров».
Ajedi32
12

Если вы хотите использовать my_helper_methodвнутри модели, вы можете написать:

ApplicationController.helpers.my_helper_method
Атчют Нагабхайрава
источник
11

Я бы не рекомендовал ни один из этих методов. Вместо этого поместите его в собственное пространство имен.

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
источник