we5-browsercms 3.0.1.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -19,7 +19,7 @@ class ContentType < ActiveRecord::Base
19
19
  # Given a 'key' like 'html_blocks' or 'portlet'
20
20
  # Raises exception if nothing was found.
21
21
  def self.find_by_key(key)
22
- class_name = key.classify
22
+ class_name = key.tableize.classify
23
23
  content_type = find_by_name(class_name)
24
24
  if content_type.nil?
25
25
  if class_name.constantize.ancestors.include?(Portlet)
@@ -54,7 +54,7 @@ class ContentType < ActiveRecord::Base
54
54
  end
55
55
 
56
56
  def model_class
57
- name.classify.constantize
57
+ name.tableize.classify.constantize
58
58
  end
59
59
 
60
60
  # Allows models to show additional columns when being shown in a list.
@@ -0,0 +1,193 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5
+ <title></title>
6
+ <link rel="stylesheet" type="text/css" href="files/stylesheets/syntax.css" />
7
+ <script type="text/javascript" src="files/javascripts/code_highlighter.js"></script>
8
+ <script type="text/javascript" src="files/javascripts/highlighters.js"></script>
9
+ <style type="text/css">
10
+ body {
11
+ background: #FFFFFF url(images/bg.png) repeat-x scroll 0 0;
12
+ font-family: "Trebuchet MS", Helvetica, Verdana, Arial, sans-serif;
13
+ margin: 0;
14
+ padding: 0;
15
+ }
16
+
17
+ #page {
18
+ margin: 0 auto;
19
+ text-align: left;
20
+ width: 1000px;
21
+ }
22
+
23
+ #header {
24
+ height: 110px;
25
+ }
26
+
27
+ div.top_cap {
28
+ background: transparent url(images/top_cap.png) no-repeat scroll 0 0;
29
+ height: 10px;
30
+ }
31
+
32
+ #contentwrap {
33
+ background: transparent url(images/dot.png) repeat scroll 0 0;
34
+ float: left;
35
+ width: 1000px;
36
+ }
37
+
38
+ div.bottom_cap {
39
+ background: transparent url(images/bottom_cap.png) no-repeat scroll 0 0;
40
+ height: 9px;
41
+ }
42
+
43
+ div.top_cap_content {
44
+ background: transparent url(images/top_cap_content.png) no-repeat scroll 0 0;
45
+ height: 5px;
46
+ }
47
+
48
+ #content {
49
+ background-color: #FFFFFF;
50
+ margin: 0 5px;
51
+ padding: 0 10px;
52
+ }
53
+
54
+ div.title {
55
+ padding: 20px;
56
+ }
57
+
58
+ div.title h1 {
59
+ border-bottom: 3px solid #505358;
60
+ color: #FFFFFF;
61
+ font-size: 24pt;
62
+ font-weight: normal;
63
+ line-height: 1;
64
+ margin: 0 0 10px;
65
+ padding-bottom: 10px;
66
+ }
67
+
68
+ td.sidebar {
69
+ font-size: 8pt;
70
+ width: 165px;
71
+ padding: 5px;
72
+ }
73
+
74
+ td.sidebar ol {
75
+ margin-left: 20px;
76
+ padding: 0;
77
+ line-height: 1.5;
78
+ }
79
+
80
+ td.sidebar ol li {
81
+ margin: 0;
82
+ padding: 0;
83
+ }
84
+
85
+ td.sidebar ol li ul {
86
+ list-style-type: none;
87
+ padding-left: 10px;
88
+ }
89
+
90
+ td.guides {
91
+ font-size: 10pt;
92
+ width: 800px;
93
+ padding: 10px;
94
+ }
95
+
96
+ .code_container {
97
+ padding: 10px;
98
+ background: #eee;
99
+ border: 1px solid #ccc;
100
+ overflow: auto;
101
+ width: 760px;
102
+ }
103
+
104
+ pre, code {
105
+ overflow: auto;
106
+ white-space:pre;
107
+ }
108
+
109
+ </style>
110
+ </head>
111
+ <body>
112
+ <div id="page">
113
+ <div id="header">
114
+ <a href="index.html"><img style="border:0px" src="images/browsercms_logo.png" alt="BrowserCMS"/></a>
115
+ </div>
116
+ <div id="main">
117
+ <div class="top_cap"></div>
118
+ <div id="contentwrap">
119
+ <div class="title">
120
+ <h1></h1>
121
+ </div>
122
+ <div class="top_cap_content"></div>
123
+ <div id="content">
124
+ <table width="100%" cellpadding="0" cellspacing="0" border="0">
125
+ <tr>
126
+ <td class="sidebar" valign="top">
127
+ <div id="subCol">
128
+ <h3 class="chapter"><img src="images/chapters_icon.gif" alt="" />Chapters</h3>
129
+ <ol class="chapters">
130
+ </ol></div>
131
+ </td>
132
+ <td class="guides">
133
+
134
+ <h2>Using <span class="caps">CMS</span> Authentication</h2>
135
+ <p>When you create public controllers, you may want to take advantage of the <span class="caps">CMS</span> authentication system. Create an action that
136
+ looks like this:</p>
137
+ <div class="code_container"><code class="ruby">class MyNewController &lt; ApplicationController
138
+
139
+ # This adds methods to your controller to work with the authenticated user.
140
+ include Cms::Authentication::Controller
141
+
142
+ def do_something_interesting
143
+ # The current_user method looks up the user based on either a cookie, or session variable.
144
+ user = current_user
145
+
146
+ if user.guest?
147
+ redirect_to &quot;/system/access-denied&quot;
148
+ else
149
+ redirect_to &quot;/my_target/page&quot;
150
+ end
151
+ end
152
+ end</code></div>
153
+ <p>The current_user method is also available in Portlets (maybe), as well as in the view files for both portlets and templates.</p>
154
+ <h3>Understanding Guest users
155
+ Many visitors to a <span class="caps">CMS</span> site will not be logged in. These users are considered to be members of a special group, called &#8216;Guest&#8217;. This
156
+ group allows staff to set permissions for denying entry to specific sections. When you call the following:</h3>
157
+ <div class="code_container"><code class="ruby">user = current_user</code></div>
158
+ <p>if there the user is not logged in, a
159
+ dirty_workaround_for_notextile_2
160
+ object will be returned. This user has all the permissions of the guest group, which are
161
+ usually limited to viewing public sections.</p>
162
+ <h2>Working with the Content <span class="caps">API</span>
163
+ One of the central features that the content <span class="caps">API</span> adds to models is versioning and publishing. Each content block can either be published or in draft. The data for a block is split between two tables, the primary table and it&#8217;s version table. The primary table
164
+ stores the &#8216;live&#8217; version of a block, typically the last &#8216;Published&#8217; version of a block. The versions table stores all other versions, including future edits which are unpublished.</h2>
165
+ <h3>Differences between ActiveRecord and Content <span class="caps">API</span>
166
+ This can cause some confusion when using basic ActiveRecord operations, where you might not get what you expect. For example, suppose we create an Event Block</h3>
167
+ <div class="code_container"><code class="ruby">class Event &lt; ActiveRecord::Base
168
+ acts_as_content_block
169
+ end
170
+
171
+ event = Event.create!(:name=&gt;&quot;Event #1&quot;, :save_and_publish=&gt;true)
172
+ event.name = &quot;Event #2&quot;
173
+ event.save!
174
+
175
+ assert_equals &quot;Event #2&quot;, Event.find(event.id) # This is false, and will fail.</code></div>
176
+ <p>In this case, &#8220;Event #2&#8221; is a draft, stored in the &#8216;events_versions&#8217; table. To create and publish the event, you can do this:</p>
177
+ <div class="code_container"><code class="ruby">event = Event.create!(:name=&gt;&quot;Event #1&quot;, :save_and_publish=&gt;true)
178
+ event.name = &quot;Event #2&quot;
179
+ event.publish! # This will both publish and save the record.
180
+
181
+ assert_equals &quot;Event #2&quot;, Event.find(event.id) # This is now true.</code></div>
182
+ </td>
183
+ </tr>
184
+ </table>
185
+ </div>
186
+ </div>
187
+ <br clear="all"/>
188
+ <div class="bottom_cap"></div>
189
+ </div>
190
+ </div>
191
+ </body>
192
+ </html>
193
+
@@ -138,7 +138,17 @@
138
138
  <li>How to use helpers to add dynamic content to templates and partials</li>
139
139
  <li>How to use the <span class="caps">CMS</span>-specific form builder extensions</li>
140
140
  </ul>
141
-
141
+ <h2>Creating a template
142
+ Each page in BrowserCMS uses a single template, which is designed to provide overall layout structure of the page. Here&#8217;s the general process
143
+ that a design team might follow to create a <span class="caps">CMS</span> template.</h2>
144
+ <p>1. Start with a <span class="caps">PSD</span> or <span class="caps">JPG</span> of the design, which represents the end result of what the webpage should look like.
145
+ 2. Create a static html file which implements that design.
146
+ 3. When creating menus, use the same structural <span class="caps">HTML</span> markup as will be generated by the Menu <span class="caps">API</span>. (See Menu&#8217;s below)
147
+ 4. Change the file extension from .htm to .html.erb and add it as a template to the <span class="caps">CMS</span>.</p>
148
+ <h2>Menus
149
+ BrowserCMS provides an <span class="caps">API</span> to allow menus to be dynamically generated based on the sitemap. The purpose of this is to make
150
+ it easy to add new pages, without having to modify templates.</h2>
151
+ <div class="code_container"><code class="ruby">render_menu</code></div>
142
152
  </td>
143
153
  </tr>
144
154
  </table>
@@ -127,7 +127,7 @@
127
127
  <div id="subCol">
128
128
  <h3 class="chapter"><img src="images/chapters_icon.gif" alt="" />Chapters</h3>
129
129
  <ol class="chapters">
130
- <li><a href="#content-blocks">Content Blocks</a><ul></ul></li><li><a href="#creating-a-custom-content-block">Creating A Custom Content Block</a><ul></ul></li><li><a href="#creating-a-custom-portlet">Creating A Custom Portlet</a><ul><li><a href="#using-file-system-templates">Using File system templates</a></li><li><a href="#pre-selecting-a-handler">Pre-selecting a handler</a></li></ul></li><li><a href="#page-routes">Page Routes</a><ul></ul></li></ol></div>
130
+ <li><a href="#content-blocks">Content Blocks</a><ul></ul></li><li><a href="#creating-a-custom-content-block">Creating A Custom Content Block</a><ul><li><a href="#attribute-types">Attribute Types</a></li></ul></li><li><a href="#creating-a-custom-portlet">Creating A Custom Portlet</a><ul><li><a href="#using-file-system-templates">Using File system templates</a></li><li><a href="#pre-selecting-a-handler">Pre-selecting a handler</a></li></ul></li><li><a href="#page-routes">Page Routes</a><ul></ul></li></ol></div>
131
131
  </td>
132
132
  <td class="guides">
133
133
  <h2>BrowserCMS Developer Guide</h2>
@@ -170,6 +170,48 @@ end</code></div>
170
170
  <p>The form helper methods that are prefixed with <tt>cms_</tt> will wrap that form helper with the <span class="caps">CMS</span> styling and extra functionality. The <tt>cms_text_editor</tt> will show the user a <span class="caps">WYSIWYG</span> editor for editing <span class="caps">HTML</span>. Additional <span class="caps">CMS</span> form builder extensions are covered in the <a href="designer_guide.html">BrowserCMS Designer Guide</a>.</p>
171
171
  <p>The render template at <tt>app/views/cms/products/render.html.erb</tt> is the template that will be used to render the <span class="caps">HTML</span> when this product is placed directly on a page. It is also what is shown when you view a product within the content library of the <span class="caps">CMS</span>.</p>
172
172
  <p>As you will see in the next section, custom content blocks are often not placed directly on a page, instead the data of a product is displayed through a portlet. For this reason, a more informational display, similar to what is automatically generated by the generator, is what the render template often contains. Depending on what your content block is, you may want to place the content block directly on a page, in which case you would most likely customize the render template.</p>
173
+ <h4 id="attribute-types">2.1 Attribute Types
174
+ This section covers some of the different attribute types that Content Blocks can have. Each attribute represents a
175
+ persistent column in the database, will appear as an editable control on the <em>form.html.erb, and may also need to need to be configured
176
+ on the content</em>block itself.</h4>
177
+ <p>List of Content Types</p>
178
+ <ul>
179
+ <li>Text Fields</li>
180
+ <li>Text Areas</li>
181
+ <li>Drop Down (Select)</li>
182
+ <li>Text Editor (<span class="caps">WYWIWYG</span>)</li>
183
+ <li>Attachment (File Upload)</li>
184
+ <li>Tag List (Allow</li>
185
+ <li>Date Picker</li>
186
+ </ul>
187
+ <h5 id="drop-down--selects">2.1.1 Drop Down / Selects
188
+ This is similar to the traditional &#8216;select&#8217; helper, it renders a stylized select control which allows users to choose one item from a list.</h5>
189
+ <h6 id="cms-drop-down">2.1.1.1 cms_drop_down
190
+ In _form.html.erb:</h6>
191
+ <div class="code_container"><code class="html">&lt;%= f.cms_drop_down :category_id, Category.all(:order =&gt; &quot;name&quot;).map{|c| [c.name, c.id]},
192
+ :prompt =&gt; &quot;Select a Category&quot;, :label =&gt; &quot;Category&quot;,
193
+ :instructions=&gt;&quot;Determines which category is used on the homepage.&quot; %&gt;</code></div>
194
+ <p>In product.rb:</p>
195
+ <div class="code_container"><code class="ruby">class Product &lt; ActiveRecord::Base
196
+ belongs_to :category
197
+ end</code></div>
198
+ <h5 id="attachments">2.1.2 Attachments
199
+ Each content block can have a single file attachment, which will allow users to upload files into the content repository. After uploading, the file will be
200
+ stored in a section within the <span class="caps">CMS</span>. Since sections determine permissions, this will allow you to control which users can access the file itself. Attached files
201
+ will have their own versioning history, which will keep track of changes.</h5>
202
+ <h6 id="cms-file-field">2.1.2.1 cms_file_field
203
+ This helper will create a stylized file upload file. An uploaded file will be associated with the content_block to which it is attached.</h6>
204
+ <p>In _form.html.erb (View)</p>
205
+ <div class="code_container"><code class="html">&lt;%= f.cms_file_field :attachment_file, :label =&gt; &quot;File&quot; %&gt;</code></div>
206
+ <p>In product.rb (Model)</p>
207
+ <div class="code_container"><code class="ruby">class Product &lt; ActiveRecord::Base
208
+ acts_as_content_block :belongs_to_attachment =&gt; true
209
+ end</code></div>
210
+ <p>In create_products.rb (Migration)</p>
211
+ <div class="code_container"><code class="ruby">create_content_table :products do |t|
212
+ t.belongs_to :attachment
213
+ t.integer :attachment_version
214
+ end</code></div>
173
215
  <h3 id="creating-a-custom-portlet">3 Creating A Custom Portlet</h3>
174
216
  <p>Once you have created the product content block and created a few products in the content library, you need a way to display them on a page. To do that, you will want to create a portlet.</p>
175
217
  <p>A portlet is used to display dynamic data on a page. A portlet is a content block. A portlet will typically perform some kind of database query in the render method and then render it&#8217;s view. One difference between a portlet and typical content block is that each instance of a portlet can have a unique template because that template is stored as data along with the portlet. Let&#8217;s generate a portlet to display the most recently created products:</p>
@@ -155,7 +155,7 @@ $ script/server</code></div>
155
155
  <div class="code_container"><code class="html">$ rails my_new_project_name -d mysql -m http://browsercms.org/templates/demo.rb
156
156
  $ cd my_new_project_name
157
157
  $ script/server</code></div>
158
- <p>Here we specify the -m mysql flag to rails, which will create our project using MySQL. You need to have the mysql gem installed for this to work.</p>
158
+ <p>Here we specify the -d mysql flag to rails, which will create our project using MySQL. You need to have the mysql gem installed for this to work.</p>
159
159
  <h4 id="using-your-site">2.3 Using your Site</h4>
160
160
  <p>Open your browser to <a href="http://localhost:3000/cms">http://localhost:3000/cms</a> to log into the admin for the <span class="caps">CMS</span>. Enter the default username/password (in development mode) is username=cmsadmin, password=cmsadmin. You should be now be logged in, viewing the home page of the site. You can now edit or add new content via the admin interface.</p>
161
161
  <p>To learn more about the types of things you can do with BrowserCMS, see the <a href="user_guide.html">User&#8217;s Guide</a>.</p>
@@ -53,7 +53,11 @@ module ActiveRecord
53
53
  end
54
54
 
55
55
  end
56
-
56
+
57
+ #
58
+ # @deprecated - create_versioned_table should be considered deprecated and may be removed in a future version.
59
+ # Use create_content_table instead in your migrations
60
+ #
57
61
  alias :create_versioned_table :create_content_table
58
62
 
59
63
  def create_table_from_definition(table_name, options, table_definition)
@@ -72,7 +76,13 @@ module ActiveRecord
72
76
  drop_table "#{table_name.singularize}_versions".to_sym
73
77
  drop_table table_name
74
78
  end
75
-
79
+
80
+ # Adds a column to both the primary and versioned table. Save needing two calls.
81
+ # This is only needed if your content block is versioned, otherwise add_column will work just fine.
82
+ def add_content_column(table_name, column_name, type, options={})
83
+ add_column table_name, column_name, type, options
84
+ add_column "#{table_name.to_s.singularize}_versions".to_sym, column_name, type, options
85
+ end
76
86
  end
77
87
  end
78
88
  end
data/lib/cms/routes.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  module Cms::Routes
2
-
2
+
3
+ #
4
+ # content_block_name - Should be a plural symbol matching the name of the content_block, like :dogs or donation_statuses
5
+ #
3
6
  def content_blocks(content_block_name, options={}, &block)
4
7
  content_block = content_block_name.to_s.classify.constantize
5
8
  resources(*[content_block_name, default_routes_for_content_block(content_block).deep_merge(options)], &block)
data/lib/tasks/db.rake CHANGED
@@ -18,7 +18,7 @@ namespace :db do
18
18
  puts "Models: " + models.join(', ')
19
19
 
20
20
  models.each do |m|
21
- model = m.classify.constantize
21
+ model = m.tableize.classify.constantize
22
22
  create_fixture(model)
23
23
  create_fixture(model.version_class) if model.versioned?
24
24
  end
@@ -0,0 +1,57 @@
1
+ require File.join(File.dirname(__FILE__), '/../../test_helper')
2
+
3
+ class RouteBuilder
4
+ include Cms::Routes
5
+ end
6
+
7
+ class Bear < ActiveRecord::Base
8
+ acts_as_content_block
9
+ end
10
+
11
+ class Kindness < ActiveRecord::Base
12
+ acts_as_content_block
13
+ end
14
+
15
+ class RoutesTest < ActiveSupport::TestCase
16
+
17
+ test "Verify behavior of classify, and how it works with already pluralized symbols" do
18
+ assert_equal "Kindness", :kindnesses.to_s.classify, "routes will pass 'plural' symbols to 'content_block', rather than single"
19
+ end
20
+
21
+
22
+ test "behavior of 'content_blocks' route generator" do
23
+ rb = RouteBuilder.new
24
+
25
+ # Expect
26
+ rb.expects(:resources).with(:bears, {:member => {:publish => :put, :usages => :get, :versions => :get}})
27
+ rb.expects(:version_cms_bears).with("/cms/bears/:id/version/:version", :controller => "cms/bears", :action => "version", :conditions => {:method => :get})
28
+ rb.expects(:revert_to_cms_bears).with(
29
+ "/cms/bears/:id/revert_to/:version",
30
+ :controller => "cms/bears",
31
+ :action => "revert_to",
32
+ :conditions => {:method => :put})
33
+
34
+ rb.content_blocks :bears
35
+
36
+ # Verifies the exact messages being passed to the route generator
37
+ end
38
+
39
+ test "model names with s at the end behave identically (since content_blocks expects plural symbols)" do
40
+ rb = RouteBuilder.new
41
+
42
+ # Expect
43
+ rb.expects(:resources).with(:kindnesses, {:member => {:publish => :put, :usages => :get, :versions => :get}})
44
+ rb.expects(:version_cms_kindnesses).with("/cms/kindnesses/:id/version/:version", :controller => "cms/kindnesses", :action => "version", :conditions => {:method => :get})
45
+ rb.expects(:revert_to_cms_kindnesses).with(
46
+ "/cms/kindnesses/:id/revert_to/:version",
47
+ :controller => "cms/kindnesses",
48
+ :action => "revert_to",
49
+ :conditions => {:method => :put})
50
+
51
+ rb.content_blocks :kindnesses
52
+
53
+ # Verifies the exact messages being passed to the route generator
54
+ end
55
+
56
+
57
+ end
@@ -1,5 +1,10 @@
1
1
  require File.join(File.dirname(__FILE__), '/../../test_helper')
2
2
 
3
+ # Sample Model for testing naming/model classes
4
+ class Kindness < ActiveRecord::Base
5
+ acts_as_content_block
6
+ end
7
+
3
8
  class ContentTypeTest < ActiveSupport::TestCase
4
9
  def setup
5
10
  @c = ContentType.new(:name => "HtmlBlock")
@@ -20,4 +25,20 @@ class ContentTypeTest < ActiveSupport::TestCase
20
25
  def test_content_block_type
21
26
  assert_equal "html_blocks", @c.content_block_type
22
27
  end
23
- end
28
+
29
+ test "find_by_key handles names that end with s correctly" do
30
+ ContentType.create!(:name => "Kindness", :group_name => "Anything")
31
+
32
+ ct = ContentType.find_by_key("kindness")
33
+ assert_not_nil ct
34
+ assert_equal "Kindness", ct.display_name
35
+ end
36
+
37
+ test "calculate the model_class name with s" do
38
+ ct = ContentType.new(:name=>"Kindness")
39
+ assert_equal Kindness, ct.model_class
40
+ end
41
+
42
+
43
+ end
44
+
@@ -0,0 +1,41 @@
1
+ require File.join(File.dirname(__FILE__), '/../test_helper')
2
+
3
+ class SchemaStatementsTest < ActiveSupport::TestCase
4
+
5
+ def teardown
6
+ %w(fake_contents fake_content_versions).each do |table|
7
+ ActiveRecord::Base.connection.drop_table(table) rescue nil
8
+ end
9
+ end
10
+
11
+ test "create_content_table should make two tables" do
12
+ conn = ActiveRecord::Base.connection
13
+ conn.create_content_table :fake_contents do |t|
14
+ t.string :name
15
+ end
16
+
17
+ expected_columns = %w(archived created_at created_by_id deleted id lock_version name published updated_at updated_by_id version)
18
+ expected_columns_v = %w(archived created_at created_by_id deleted fake_content_id id name published updated_at updated_by_id version version_comment)
19
+ assert_equal expected_columns, conn.columns(:fake_contents).map { |c| c.name }.sort
20
+ assert_equal expected_columns_v, conn.columns(:fake_content_versions).map { |c| c.name }.sort
21
+ end
22
+
23
+ test "add_content_column should add columns to both primary and versions table" do
24
+ connection.create_content_table :fake_contents do |t| end
25
+
26
+ connection.add_content_column :fake_contents, :foo, :string
27
+
28
+ found_c = connection.columns(:fake_contents).map { |c| c.name }
29
+ assert found_c.include?("foo")
30
+
31
+ found_c = connection.columns(:fake_content_versions).map { |c| c.name }
32
+ assert found_c.include?("foo")
33
+ end
34
+
35
+
36
+ def connection
37
+ ActiveRecord::Base.connection
38
+ end
39
+ end
40
+
41
+