tamed_beast 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/README +12 -0
- data/Rakefile +2 -0
- data/app/controllers/forums_controller.rb +60 -0
- data/app/controllers/posts_controller.rb +98 -0
- data/app/controllers/topics_controller.rb +94 -0
- data/app/models/forum.rb +23 -0
- data/app/models/post.rb +26 -0
- data/app/models/topic.rb +97 -0
- data/app/views/forums/_form.html.erb +21 -0
- data/app/views/forums/edit.html.erb +12 -0
- data/app/views/forums/index.html.erb +63 -0
- data/app/views/forums/new.html.erb +10 -0
- data/app/views/forums/show.html.erb +81 -0
- data/app/views/posts/_edit.html.erb +38 -0
- data/app/views/posts/edit.html.erb +14 -0
- data/app/views/posts/index.html.erb +1 -0
- data/app/views/topics/_form.html.erb +17 -0
- data/app/views/topics/edit.html.erb +10 -0
- data/app/views/topics/index.html.erb +2 -0
- data/app/views/topics/new.html.erb +18 -0
- data/app/views/topics/show.html.erb +175 -0
- data/config/conf.rb +0 -0
- data/lib/generators/tamed_beast/install_generator.rb +56 -0
- data/lib/generators/tamed_beast/migration_generator.rb +26 -0
- data/lib/generators/tamed_beast/templates/migration.rb +57 -0
- data/lib/generators/tamed_beast/templates/routes.rb +9 -0
- data/lib/tamed_beast.rb +7 -0
- data/lib/tamed_beast/application_helper.rb +18 -0
- data/lib/tamed_beast/auth.rb +24 -0
- data/lib/tamed_beast/engine.rb +7 -0
- data/lib/tamed_beast/version.rb +3 -0
- data/tamed_beast.gemspec +23 -0
- data/test/fixtures/forums.yml +19 -0
- data/test/fixtures/posts.yml +34 -0
- data/test/fixtures/topics.yml +29 -0
- data/test/fixtures/users.yml +9 -0
- data/test/functional/forums_controller_test.rb +51 -0
- data/test/functional/posts_controller_test.rb +54 -0
- data/test/functional/topics_controller_test.rb +55 -0
- data/test/unit/forum_test.rb +10 -0
- data/test/unit/post_test.rb +32 -0
- data/test/unit/topic_test.rb +33 -0
- data/vendor/plugins/white_list/README +29 -0
- data/vendor/plugins/white_list/Rakefile +22 -0
- data/vendor/plugins/white_list/init.rb +2 -0
- data/vendor/plugins/white_list/lib/white_list_helper.rb +97 -0
- data/vendor/plugins/white_list/test/white_list_test.rb +132 -0
- data/vendor/plugins/white_list_formatted_content/init.rb +27 -0
- metadata +161 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TopicsControllerTest < ActionController::TestCase
|
4
|
+
fixtures :posts
|
5
|
+
fixtures :topics
|
6
|
+
fixtures :forums
|
7
|
+
fixtures :users
|
8
|
+
|
9
|
+
test "show action lists posts in a topic" do
|
10
|
+
f = forums(:one)
|
11
|
+
t = topics(:one)
|
12
|
+
get :show, :id => t.id, :forum_id => f.id
|
13
|
+
assert_response :success
|
14
|
+
assert_equal Post.where(:topic_id => t.id).count, assigns(:posts).size
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
test "create action" do
|
19
|
+
f = forums(:one)
|
20
|
+
u = users(:one)
|
21
|
+
sign_in(u)
|
22
|
+
|
23
|
+
assert_difference "Topic.where(:forum_id => #{f.id}).count" do
|
24
|
+
post :create, :forum_id => f.id, :topic => {:title => 'test test', :body => 'test test body body'}
|
25
|
+
t = Topic.where(:forum_id => f.id).last
|
26
|
+
|
27
|
+
assert_redirected_to forum_topic_path(f,t)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
test "update action" do
|
32
|
+
f = forums(:one)
|
33
|
+
t = topics(:one)
|
34
|
+
u = users(:one)
|
35
|
+
sign_in(u)
|
36
|
+
|
37
|
+
put :update, :id => t.id, :forum_id => f.id, :topic => {:title => 'test test'}
|
38
|
+
assert_redirected_to forum_topic_path(f,t)
|
39
|
+
end
|
40
|
+
|
41
|
+
test "destroy action" do
|
42
|
+
f = forums(:one)
|
43
|
+
t = topics(:one)
|
44
|
+
u = users(:one)
|
45
|
+
sign_in(u)
|
46
|
+
|
47
|
+
delete :destroy, :id => t.id, :forum_id => f.id
|
48
|
+
assert_redirected_to forum_path(f)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def sign_in(u)
|
53
|
+
session[:user_id] = u.id
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class PostTest < ActiveSupport::TestCase
|
4
|
+
test "validates presence of user" do
|
5
|
+
p = Post.new
|
6
|
+
p.body = "lorem ipsum dolor sit amet..."
|
7
|
+
p.topic_id = 1
|
8
|
+
assert !p.valid?
|
9
|
+
p.user_id = 1
|
10
|
+
assert p.valid?
|
11
|
+
end
|
12
|
+
|
13
|
+
test "validates presence of body" do
|
14
|
+
p = Post.new
|
15
|
+
p.topic_id = 1
|
16
|
+
p.user_id = 1
|
17
|
+
assert !p.valid?
|
18
|
+
|
19
|
+
p.body = "lorem ipsum dolor sit amet..."
|
20
|
+
assert p.valid?
|
21
|
+
end
|
22
|
+
|
23
|
+
test "validates presence of topic" do
|
24
|
+
p = Post.new
|
25
|
+
p.user_id = 1
|
26
|
+
p.body = "lorem ipsum dolor sit amet..."
|
27
|
+
assert !p.valid?
|
28
|
+
|
29
|
+
p.topic_id = 1
|
30
|
+
assert p.valid?
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TopicTest < ActiveSupport::TestCase
|
4
|
+
test "validates presence of user" do
|
5
|
+
t = Topic.new
|
6
|
+
t.title = "A new topic"
|
7
|
+
t.forum_id = 1
|
8
|
+
assert !t.valid?
|
9
|
+
|
10
|
+
t.user_id = 1
|
11
|
+
assert t.valid?
|
12
|
+
end
|
13
|
+
|
14
|
+
test "validates presence of forum" do
|
15
|
+
t = Topic.new
|
16
|
+
t.title = "A new topic"
|
17
|
+
t.user_id = 1
|
18
|
+
assert !t.valid?
|
19
|
+
|
20
|
+
t.forum_id = 1
|
21
|
+
assert t.valid?
|
22
|
+
end
|
23
|
+
|
24
|
+
test "validates presence of title" do
|
25
|
+
t = Topic.new
|
26
|
+
t.user_id = 1
|
27
|
+
t.forum_id = 1
|
28
|
+
assert !t.valid?
|
29
|
+
|
30
|
+
t.title = "A new topic"
|
31
|
+
assert t.valid?
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
WhiteList
|
2
|
+
=========
|
3
|
+
|
4
|
+
This White Listing helper will html encode all tags and strip all attributes that aren't specifically allowed.
|
5
|
+
It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any
|
6
|
+
tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out
|
7
|
+
the extensive test suite.
|
8
|
+
|
9
|
+
<%= white_list @article.body %>
|
10
|
+
|
11
|
+
You can add or remove tags/attributes if you want to customize it a bit.
|
12
|
+
|
13
|
+
Add table tags
|
14
|
+
|
15
|
+
WhiteListHelper.tags.merge %w(table td th)
|
16
|
+
|
17
|
+
Remove tags
|
18
|
+
|
19
|
+
WhiteListHelper.tags.delete 'div'
|
20
|
+
|
21
|
+
Change allowed attributes
|
22
|
+
|
23
|
+
WhiteListHelper.attributes.merge %w(id class style)
|
24
|
+
|
25
|
+
white_list accepts a block for custom tag escaping. Shown below is the default block that white_list uses if none is given.
|
26
|
+
The block is called for all bad tags, and every text node. node is an instance of HTML::Node (either HTML::Tag or HTML::Text).
|
27
|
+
bad is nil for text nodes inside good tags, or is the tag name of the bad tag.
|
28
|
+
|
29
|
+
<%= white_list(@article.body) { |node, bad| white_listed_bad_tags.include?(bad) ? nil : node.to_s.gsub(/</, '<') } %>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the white_list plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the white_list plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'WhiteList'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module WhiteListHelper
|
2
|
+
@@protocol_attributes = Set.new %w(src href)
|
3
|
+
@@protocol_separator = /:|(�*58)|(p)|(%|%)3A/
|
4
|
+
mattr_reader :protocol_attributes, :protocol_separator
|
5
|
+
|
6
|
+
def self.contains_bad_protocols?(white_listed_protocols, value)
|
7
|
+
value =~ protocol_separator && !white_listed_protocols.include?(value.split(protocol_separator).first)
|
8
|
+
end
|
9
|
+
|
10
|
+
klass = class << self; self; end
|
11
|
+
klass_methods = []
|
12
|
+
inst_methods = []
|
13
|
+
[:bad_tags, :tags, :attributes, :protocols].each do |attr|
|
14
|
+
# Add class methods to the module itself
|
15
|
+
klass_methods << <<-EOS
|
16
|
+
def #{attr}=(value) @@#{attr} = Set.new(value) end
|
17
|
+
def #{attr}() @@#{attr} end
|
18
|
+
EOS
|
19
|
+
|
20
|
+
# prefix the instance methods with white_listed_*
|
21
|
+
inst_methods << "def white_listed_#{attr}() ::WhiteListHelper.#{attr} end"
|
22
|
+
end
|
23
|
+
|
24
|
+
klass.class_eval klass_methods.join("\n"), __FILE__, __LINE__
|
25
|
+
class_eval inst_methods.join("\n"), __FILE__, __LINE__
|
26
|
+
|
27
|
+
# This White Listing helper will html encode all tags and strip all attributes that aren't specifically allowed.
|
28
|
+
# It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any
|
29
|
+
# tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out
|
30
|
+
# the extensive test suite.
|
31
|
+
#
|
32
|
+
# <%= white_list @article.body %>
|
33
|
+
#
|
34
|
+
# You can add or remove tags/attributes if you want to customize it a bit.
|
35
|
+
#
|
36
|
+
# Add table tags
|
37
|
+
#
|
38
|
+
# WhiteListHelper.tags.merge %w(table td th)
|
39
|
+
#
|
40
|
+
# Remove tags
|
41
|
+
#
|
42
|
+
# WhiteListHelper.tags.delete 'div'
|
43
|
+
#
|
44
|
+
# Change allowed attributes
|
45
|
+
#
|
46
|
+
# WhiteListHelper.attributes.merge %w(id class style)
|
47
|
+
#
|
48
|
+
# white_list accepts a block for custom tag escaping. Shown below is the default block that white_list uses if none is given.
|
49
|
+
# The block is called for all bad tags, and every text node. node is an instance of HTML::Node (either HTML::Tag or HTML::Text).
|
50
|
+
# bad is nil for text nodes inside good tags, or is the tag name of the bad tag.
|
51
|
+
#
|
52
|
+
# <%= white_list(@article.body) { |node, bad| white_listed_bad_tags.include?(bad) ? nil : node.to_s.gsub(/</, '<') } %>
|
53
|
+
#
|
54
|
+
def white_list(html, options = {}, &block)
|
55
|
+
return html if html.blank? || !html.include?('<')
|
56
|
+
attrs = Set.new(options[:attributes]).merge(white_listed_attributes)
|
57
|
+
tags = Set.new(options[:tags] ).merge(white_listed_tags)
|
58
|
+
block ||= lambda { |node, bad| white_listed_bad_tags.include?(bad) ? nil : node.to_s.gsub(/</, '<') }
|
59
|
+
[].tap do |new_text|
|
60
|
+
tokenizer = HTML::Tokenizer.new(html)
|
61
|
+
bad = nil
|
62
|
+
while token = tokenizer.next
|
63
|
+
node = HTML::Node.parse(nil, 0, 0, token, false)
|
64
|
+
new_text << case node
|
65
|
+
when HTML::Tag
|
66
|
+
node.attributes.keys.each do |attr_name|
|
67
|
+
value = node.attributes[attr_name].to_s
|
68
|
+
if !attrs.include?(attr_name) || (protocol_attributes.include?(attr_name) && contains_bad_protocols?(value))
|
69
|
+
node.attributes.delete(attr_name)
|
70
|
+
else
|
71
|
+
node.attributes[attr_name] = CGI::escapeHTML(value)
|
72
|
+
end
|
73
|
+
end if node.attributes
|
74
|
+
if tags.include?(node.name)
|
75
|
+
bad = nil
|
76
|
+
node
|
77
|
+
else
|
78
|
+
bad = node.name
|
79
|
+
block.call node, bad
|
80
|
+
end
|
81
|
+
else
|
82
|
+
block.call node, bad
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end.join
|
86
|
+
end
|
87
|
+
|
88
|
+
protected
|
89
|
+
def contains_bad_protocols?(value)
|
90
|
+
WhiteListHelper.contains_bad_protocols?(white_listed_protocols, value)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
WhiteListHelper.bad_tags = %w(script)
|
95
|
+
WhiteListHelper.tags = %w(strong em b i p code pre tt output samp kbd var sub sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dt dd abbr acronym a img blockquote del ins fieldset legend)
|
96
|
+
WhiteListHelper.attributes = %w(href src width height alt cite datetime title class)
|
97
|
+
WhiteListHelper.protocols = %w(ed2k ftp http https irc mailto news gopher nntp telnet webcal xmpp callto feed)
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
|
3
|
+
|
4
|
+
class WhiteListTest < Test::Unit::TestCase
|
5
|
+
include WhiteListHelper
|
6
|
+
public :contains_bad_protocols?
|
7
|
+
|
8
|
+
WhiteListHelper.tags.each do |tag_name|
|
9
|
+
define_method "test_should_allow_#{tag_name}_tag" do
|
10
|
+
assert_white_listed "start <#{tag_name} title=\"1\" name=\"foo\">foo <bad>bar</bad> baz</#{tag_name}> end", %(start <#{tag_name} title="1">foo <bad>bar</bad> baz</#{tag_name}> end)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_allow_anchors
|
15
|
+
assert_white_listed %(<a href="foo" onclick="bar"><script>baz</script></a>), %(<a href="foo"></a>)
|
16
|
+
end
|
17
|
+
|
18
|
+
%w(src width height alt).each do |img_attr|
|
19
|
+
define_method "test_should_allow_image_#{img_attr}_attribute" do
|
20
|
+
assert_white_listed %(<img #{img_attr}="foo" onclick="bar" />), %(<img #{img_attr}="foo" />)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_handle_non_html
|
25
|
+
assert_white_listed 'abc'
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_should_handle_blank_text
|
29
|
+
assert_white_listed nil
|
30
|
+
assert_white_listed ''
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_should_allow_custom_tags
|
34
|
+
text = "<u>foo</u>"
|
35
|
+
assert_equal(text, white_list(text, :tags => %w(u)))
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_should_allow_custom_tags_with_attributes
|
39
|
+
text = %(<fieldset foo="bar">foo</fieldset>)
|
40
|
+
assert_equal(text, white_list(text, :attributes => ['foo']))
|
41
|
+
end
|
42
|
+
|
43
|
+
[%w(img src), %w(a href)].each do |(tag, attr)|
|
44
|
+
define_method "test_should_strip_#{attr}_attribute_in_#{tag}_with_bad_protocols" do
|
45
|
+
assert_white_listed %(<#{tag} #{attr}="javascript:bang" title="1">boo</#{tag}>), %(<#{tag} title="1">boo</#{tag}>)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_should_flag_bad_protocols
|
50
|
+
%w(about chrome data disk hcp help javascript livescript lynxcgi lynxexec ms-help ms-its mhtml mocha opera res resource shell vbscript view-source vnd.ms.radio wysiwyg).each do |proto|
|
51
|
+
assert contains_bad_protocols?("#{proto}://bad")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_should_accept_good_protocols
|
56
|
+
WhiteListHelper.protocols.each do |proto|
|
57
|
+
assert !contains_bad_protocols?("#{proto}://good")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_should_reject_hex_codes_in_protocol
|
62
|
+
assert contains_bad_protocols?("%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%22%58%53%53%22%29")
|
63
|
+
assert_white_listed %(<a href="%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%22%58%53%53%22%29">1</a>), "<a>1</a>"
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_should_block_script_tag
|
67
|
+
assert_white_listed %(<SCRIPT\nSRC=http://ha.ckers.org/xss.js></SCRIPT>), ""
|
68
|
+
end
|
69
|
+
|
70
|
+
[%(<IMG SRC="javascript:alert('XSS');">),
|
71
|
+
%(<IMG SRC=javascript:alert('XSS')>),
|
72
|
+
%(<IMG SRC=JaVaScRiPt:alert('XSS')>),
|
73
|
+
%(<IMG """><SCRIPT>alert("XSS")</SCRIPT>">),
|
74
|
+
%(<IMG SRC=javascript:alert("XSS")>),
|
75
|
+
%(<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>),
|
76
|
+
%(<IMG SRC=javascript:alert('XSS')>),
|
77
|
+
%(<IMG SRC=javascript:alert('XSS')>),
|
78
|
+
%(<IMG SRC=javascript:alert('XSS')>),
|
79
|
+
%(<IMG SRC="jav\tascript:alert('XSS');">),
|
80
|
+
%(<IMG SRC="jav	ascript:alert('XSS');">),
|
81
|
+
%(<IMG SRC="jav
ascript:alert('XSS');">),
|
82
|
+
%(<IMG SRC="jav
ascript:alert('XSS');">),
|
83
|
+
%(<IMG SRC="  javascript:alert('XSS');">),
|
84
|
+
%(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i|
|
85
|
+
define_method "test_should_not_fall_for_xss_image_hack_#{i}" do
|
86
|
+
assert_white_listed img_hack, "<img>"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_should_sanitize_tag_broken_up_by_null
|
91
|
+
assert_white_listed %(<SCR\0IPT>alert(\"XSS\")</SCR\0IPT>), "<scr>alert(\"XSS\")</scr>"
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_should_sanitize_invalid_script_tag
|
95
|
+
assert_white_listed %(<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>), ""
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_should_sanitize_script_tag_with_multiple_open_brackets
|
99
|
+
assert_white_listed %(<<SCRIPT>alert("XSS");//<</SCRIPT>), "<"
|
100
|
+
assert_white_listed %(<iframe src=http://ha.ckers.org/scriptlet.html\n<), %(<iframe src="http:" /><)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_should_sanitize_unclosed_script
|
104
|
+
assert_white_listed %(<SCRIPT SRC=http://ha.ckers.org/xss.js?<B>), "<b>"
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_should_sanitize_half_open_scripts
|
108
|
+
assert_white_listed %(<IMG SRC="javascript:alert('XSS')"), "<img>"
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_should_not_fall_for_ridiculous_hack
|
112
|
+
img_hack = %(<IMG\nSRC\n=\n"\nj\na\nv\na\ns\nc\nr\ni\np\nt\n:\na\nl\ne\nr\nt\n(\n'\nX\nS\nS\n'\n)\n"\n>)
|
113
|
+
assert_white_listed img_hack, "<img>"
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_should_allow_custom_block
|
117
|
+
html = %(<SCRIPT type="javascript">foo</SCRIPT><img>blah</img><blink>blah</blink>)
|
118
|
+
safe = white_list html do |node, bad|
|
119
|
+
bad == 'script' ? nil : node
|
120
|
+
end
|
121
|
+
assert_equal "<img>blah</img><blink>blah</blink>", safe
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_should_sanitize_attributes
|
125
|
+
assert_white_listed %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="'><script>alert()</script>">blah</span>)
|
126
|
+
end
|
127
|
+
|
128
|
+
protected
|
129
|
+
def assert_white_listed(text, expected = nil)
|
130
|
+
assert_equal((expected || text), white_list(text))
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
ActiveRecord::Base.class_eval do
|
2
|
+
include ActionView::Helpers::TagHelper, ActionView::Helpers::TextHelper, WhiteListHelper
|
3
|
+
def self.format_attribute(attr_name)
|
4
|
+
class << self; include ActionView::Helpers::TagHelper, ActionView::Helpers::TextHelper, WhiteListHelper; end
|
5
|
+
define_method(:body) { read_attribute attr_name }
|
6
|
+
define_method(:body_html) { read_attribute "#{attr_name}_html" }
|
7
|
+
define_method(:body_html=) { |value| write_attribute "#{attr_name}_html", value }
|
8
|
+
before_save :format_content
|
9
|
+
end
|
10
|
+
|
11
|
+
def dom_id
|
12
|
+
[self.class.name.downcase.pluralize.dasherize, id] * '-'
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
def format_content
|
17
|
+
body.strip! if body.respond_to?(:strip!)
|
18
|
+
self.body_html = body.blank? ? '' : body_html_with_formatting
|
19
|
+
end
|
20
|
+
|
21
|
+
def body_html_with_formatting
|
22
|
+
body_html = auto_link(body) { |text| truncate(text, 50) }
|
23
|
+
textilized = RedCloth.new(body_html, [ :hard_breaks ])
|
24
|
+
textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=")
|
25
|
+
white_list(textilized.to_html)
|
26
|
+
end
|
27
|
+
end
|