require "html_terminator/version" require 'sanitize' module HtmlTerminator SANITIZE_OPTIONS = { :elements => ["b", "em", "i", "strong", "u", "br"] } def self.sanitize(val) if val.is_a?(String) && !skip_sanitize?(val) Sanitize.fragment(val, SANITIZE_OPTIONS).strip.gsub(/&/, "&") else val end end # Don't sanitize if only one bracket is present. # Without this, "1 < 2" gets incorrectly sanitized as "1". def self.skip_sanitize?(val) val.count("<") + val.count(">") == 1 end module ClassMethods def terminate_html(*args) class_attribute :html_terminator_fields # Table may not exist yet when schema is initially getting loaded if self.table_exists? # By default all fields are to be seen by the terminator self.html_terminator_fields = self.columns.inject([]) do |list, col| if col.type == :string or col.type == :text list << col.name.to_sym end list end if args.length == 1 if args[0].is_a?(Symbol) self.html_terminator_fields = args elsif args[0].is_a?(Object) self.html_terminator_fields -= (args[0][:except] || []) end elsif args.length > 1 self.html_terminator_fields = args end unless self.html_terminator_fields.empty? # sanitize writes before_validation :terminate_html # sanitize reads self.html_terminator_fields.each do |attr| define_method(attr) do |*rargs| # sanitize it HtmlTerminator.sanitize super(*rargs) end end end end end end module InstanceMethods def terminate_html self.html_terminator_fields.each do |field| value = self[field] unless value.nil? self[field] = HtmlTerminator.sanitize(value) end end end end def self.included(base) base.send :extend, ClassMethods base.send :include, InstanceMethods end end ActiveRecord::Base.send :include, HtmlTerminator