126

I'm writing a model that handles user input from a text area. Following the advice from http://blog.caboo.se/articles/2008/8/25/sanitize-your-users-html-input, I'm cleaning up the input in the model before saving to database, using the before_validate callback.

The relevant parts of my model look like this:

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

Needless to say, this doesn't work. I get the following error when I try and save a new Post.

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

Apparently, SanitizeHelper creates an instance of HTML::WhiteListSanitizer, but when I mix it into my model it can't find HTML::WhiteListSanitizer. Why? What can I do about this to fix it?

8 Answers 8

152

Just change the first line as follows :

include ActionView::Helpers

that will make it works.

UPDATE: For Rails 3 use:

ActionController::Base.helpers.sanitize(str)

Credit goes to lornc's answer

8
  • couldn't have said it better myself
    – Tilendor
    Jan 29, 2009 at 0:09
  • 1
    Thanks. I got it to work by moving the include to inside of the class definition. Jan 29, 2009 at 1:00
  • 1
    With this I get stack level too deep. It is in a before_save method.
    – Automatico
    Aug 1, 2013 at 0:35
  • 46
    Please don't mix view layer concerns with active record models. That's a terrible practice. A much better approach is to put a standalone input data sanitizer object in front of AR and retrieve "clean" attributes from it.
    – solnic
    Jul 29, 2014 at 10:52
  • 1
    This is a very bad solution and should be avoided like fire. Rails is based on MVC(Model View Controller) framework where helper comes in View part so you should not mix view helper methods with model.
    – jedi
    Jun 28, 2018 at 22:44
143

This gives you just the helper method without the side effects of loading every ActionView::Helpers method into your model:

ActionController::Base.helpers.sanitize(str)
3
  • 6
    For the slow people like me - you don't need to include anything, just use ActionController::Base.helpers.sanitize("On the string you want to sanitize")
    – Edward
    Apr 24, 2012 at 10:45
  • 1
    Thank you, worked in Rails 2.3.14 while the accepted answer did not. May 30, 2012 at 17:30
  • I added a method to the application_helper, but I wasn't able to access it from the model using ActionController::Base.helpers.my_method(options) using Rails 3.0.3?
    – Tom Rossi
    Oct 15, 2012 at 20:12
43

This works better for me:

Simple:

ApplicationController.helpers.my_helper_method

Advance:

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

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

2
  • 1
    The ApplicationController.master_helper_module does not exist any more in Rails 3 and 4 it appears. The ApplicationController.helpers is a nice one though.
    – Samuel
    Mar 4, 2015 at 13:43
  • I voted for this (the simple option) because it suited my needs - I only need one helper that is using information saved by a before filter in ApplicationController, so in my case making the association explicit is a reminder that there is a coupling. [Use case is multi domain app, that issues emails via a model notifier with a url link back to the app - this url changes depending on the domain of web request]
    – iheggie
    Mar 12, 2015 at 7:45
26

To access helpers from your own controllers, just use:

OrdersController.helpers.order_number(@order)
2
  • 2
    Just using ApplicationController.helpers.order_number(@order). That mean the order_number was locate on Order Helper
    – ksugiarto
    Oct 9, 2013 at 3:15
  • 4
    @rowanu He's saying "to access (helpers from your own controllers)", not "(to access helpers) from your own controllers".
    – Ajedi32
    Jan 12, 2015 at 17:48
20

If you want to use a the my_helper_method inside a model, you can write:

ApplicationController.helpers.my_helper_method
14

I wouldn't recommend any of these methods. Instead, put it within its own namespace.

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
3

In Rails 7:

full_sanitizer = Rails::Html::FullSanitizer.new
full_sanitizer.sanitize("<a href="javascript:alert('hacked!')">Some dangerous input</a>")

List of available sanitizers: https://github.com/rails/rails-html-sanitizer#sanitizers

Your model would then be:

class Post < ActiveRecord::Base {
  before_validation :clean_input

  ...

  protected

  def clean_input
    full_sanitizer = Rails::Html::FullSanitizer.new
    self.input = full_sanitizer.sanitize(self.input, :tags => %w(b i u))
  end
end
1

Many suggests include or extend the entire helper library within the class, which is overkill.

I recommend just delegating the helper methods you need.

For example

class Post < ActiveRecord::Base
  delegate :sanitize, to: 'ActionController::Base.helpers'
end

This will give you access to sanitize within the model.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.