summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/helpers/content_helper.rb28
-rw-r--r--app/models/flag.rb3
-rw-r--r--app/models/page.rb51
-rw-r--r--app/views/content/_article.html.erb6
-rw-r--r--app/views/content/render_page.html.erb2
-rw-r--r--db/migrate/20090201211159_create_flags.rb13
-rw-r--r--db/migrate/20090201211523_add_join_table_for_flags_pages.rb15
-rw-r--r--doc/README_FOR_APP70
-rw-r--r--test/fixtures/flags.yml7
-rw-r--r--test/unit/flag_test.rb8
10 files changed, 193 insertions, 10 deletions
diff --git a/app/helpers/content_helper.rb b/app/helpers/content_helper.rb
index 0e1df66..3cf3488 100644
--- a/app/helpers/content_helper.rb
+++ b/app/helpers/content_helper.rb
@@ -1,8 +1,34 @@
1module ContentHelper 1module ContentHelper
2 2
3 #
4 def date_for_page page 3 def date_for_page page
5 page.published_at.to_s(:db) rescue page.created_at.to_s(:db) 4 page.published_at.to_s(:db) rescue page.created_at.to_s(:db)
6 end 5 end
7 6
7 def aggregate? content
8 options = {}
9
10 begin
11 if content =~ /<aggregate([^<>]*)>/
12 tag = $~.to_s
13 matched_data = $1.scan(/\w+\=\"[a-zA-Z\s\/_\d]*\"/)
14
15 matched_data.each do |data|
16 splitted_data = data.split("=")
17 options[splitted_data[0].to_sym] = splitted_data[1].gsub(/\"/, "")
18 end
19
20 content.sub(tag, render_collection(options))
21 end
22
23 rescue
24 content
25 end
26 end
27
28 def render_collection options
29 render(
30 :partial => 'content/article',
31 :collection => Page.aggregate(options)
32 )
33 end
8end 34end
diff --git a/app/models/flag.rb b/app/models/flag.rb
new file mode 100644
index 0000000..6d67377
--- /dev/null
+++ b/app/models/flag.rb
@@ -0,0 +1,3 @@
1class Flag < ActiveRecord::Base
2 has_and_belongs_to_many :pages
3end
diff --git a/app/models/page.rb b/app/models/page.rb
index 0fcb4a8..fee20a8 100644
--- a/app/models/page.rb
+++ b/app/models/page.rb
@@ -1,7 +1,56 @@
1class Page < ActiveRecord::Base 1class Page < ActiveRecord::Base
2 2
3 belongs_to :node 3 belongs_to :node
4 has_and_belongs_to_many :flags
4 5
5 acts_as_list :column => :revision, :scope => :node_id 6 acts_as_list :column => :revision, :scope => :node_id
6 7
7end 8 # Alternativ Queries with one or two inner joins. Loading the Flags themselves
9 # would be another query. Could be faster on larger data sets.
10 #
11 # Single Join:
12 #
13 # Page.find(
14 # :all,
15 # :joins => 'JOIN flags_pages on pages.id = flags_pages.page_id',
16 # :include => :flags,
17 # :conditions => ['flags_pages.flag_id IN (?)', [1,2]]
18 # )
19 # Two inner joins:
20 #
21 # Page.find(
22 # :all,
23 # :joins => :flags_pages,
24 # :conditions => ['flags_pages.flag_id IN (?)', [1,2]]
25 # )
26 named_scope :with_flags, lambda {|flag_names|
27 if (flags = Flag.find_all_by_name(flag_names)).empty?
28 {}
29 else
30 {:include => :flags, :conditions => ['flags_pages.flag_id IN (?)', flags.map(&:id)] }
31 end
32 }
33
34 # <aggregate
35 # flags="updates pressemitteilungen"
36 # limit="20"
37 # order_by="published_at"
38 # order_direction="DESC"
39 # />
40 def self.aggregate options
41
42 defaults = {
43 :flags => "",
44 :limit => 20,
45 :order_by => "id",
46 :order_direction => "ASC"
47 }
48
49 options = defaults.merge options
50
51 pages = Page.with_flags(options[:flags].split(/\s/)).all(
52 :limit => options[:limit],
53 :order => "#{options[:order_by]} #{options[:order_direction]}"
54 )
55 end
56end \ No newline at end of file
diff --git a/app/views/content/_article.html.erb b/app/views/content/_article.html.erb
new file mode 100644
index 0000000..1e06787
--- /dev/null
+++ b/app/views/content/_article.html.erb
@@ -0,0 +1,6 @@
1<div class="teaserruler">
2 <hr/>
3</div>
4<h2><%= article.title %></h2>
5<h3><%= date_for_page article %>, gregoa</h3>
6<p><%= article.abstract %></p> \ No newline at end of file
diff --git a/app/views/content/render_page.html.erb b/app/views/content/render_page.html.erb
index 311d61d..b70f90e 100644
--- a/app/views/content/render_page.html.erb
+++ b/app/views/content/render_page.html.erb
@@ -13,5 +13,5 @@
13 <h3><%= date_for_page @page %>, gregoa</h3> 13 <h3><%= date_for_page @page %>, gregoa</h3>
14 <hr class="subtitle" /> 14 <hr class="subtitle" />
15 <p><em><%= @page.abstract %></em></p> 15 <p><em><%= @page.abstract %></em></p>
16 <%= @page.body %> 16 <%= aggregate?(@page.body) %>
17</div> \ No newline at end of file 17</div> \ No newline at end of file
diff --git a/db/migrate/20090201211159_create_flags.rb b/db/migrate/20090201211159_create_flags.rb
new file mode 100644
index 0000000..3b9da43
--- /dev/null
+++ b/db/migrate/20090201211159_create_flags.rb
@@ -0,0 +1,13 @@
1class CreateFlags < ActiveRecord::Migration
2 def self.up
3 create_table :flags do |t|
4 t.string :name
5
6 t.timestamps
7 end
8 end
9
10 def self.down
11 drop_table :flags
12 end
13end
diff --git a/db/migrate/20090201211523_add_join_table_for_flags_pages.rb b/db/migrate/20090201211523_add_join_table_for_flags_pages.rb
new file mode 100644
index 0000000..99eb9c9
--- /dev/null
+++ b/db/migrate/20090201211523_add_join_table_for_flags_pages.rb
@@ -0,0 +1,15 @@
1class AddJoinTableForFlagsPages < ActiveRecord::Migration
2 def self.up
3 create_table :flags_pages, :id => false do |t|
4 t.integer :flag_id
5 t.integer :page_id
6 end
7 add_index :flags_pages, [:flag_id]
8 add_index :flags_pages, [:page_id]
9 end
10
11 def self.down
12 remove_table :flags_pages
13 end
14
15end
diff --git a/doc/README_FOR_APP b/doc/README_FOR_APP
index 9b76357..c1bc254 100644
--- a/doc/README_FOR_APP
+++ b/doc/README_FOR_APP
@@ -1,15 +1,71 @@
1CCCMS 1CCCMS
2 2
3==General
3 4
4The basic structure of the cccms is built from Nodes. Nodes live within a 5===Nodes
5nested set. When a arbitrary url is entered it is dispatched to the
6ContentController action render_page. Based on the url parameters the
7render_page action retrieves the corresponding Node from the database. Rather
8than walking through the tree of the nested set to find the node, the Node is
9retrieved directly by its unique_name which matches the url parameters.
10 6
11So much for now yeah 7The structure of the cccms is built from Node objects which live within a nested
8set. Therefor a given node has parents, children, descendants etc.
12 9
10The position of a node within the nested set corresponds directly to the URL
11under which that node is accessible:
12
13root
14 \__updates
15 \__2009
16 \___ultra_important_news
17
18=> http://domain/de/updates/2009/ultra_important_news
19
20Note that the first parameter after the domain is the locale. Everything after
21the locale identifier is the unique path of a given node. The unique path itself
22is generated from the slugs of the ancestors of a node. The last part of the
23unique path is taken from the slug of the node.
24
25Once a node is added to the nested set or moved within, the unique path of that
26node is generated from all its ancestors up to the root node. The computed path
27is then saved on the node object itself, allowing the system to retrieve a
28node simply by looking for the right url in the unique_path column. This is a
29lot faster then walking down the tree.
30
31===Pages
32
33As the nodes only built the structure, another object is necessary to actually
34hold all the contents. This object is called a page and is associated to a node
35via a one-to-many association. A node can have multiple pages associated to it.
36The node is actually a proxy for the pages behind it, and the pages act as a
37versioned page. By default, if you retrieve a node from the database by its
38unique path and ask this node for a page, the node would return the most recent
39one. It is also possible to get a page from a node, supplying a revision number.
40The node object would then retrieve the associated page with the corresponding
41revision number. For convenience purposes, the most recent page revision, in
42the scope of a node, is flagged as the head of this collection. This is
43primarily for making certain queries a lot easier where you only want to select
44upon the current pages in the db rather than on all.
45
46It is important to know that all the associations of a page, such as tags,
47authors etc, must be copied one a new revision of a page is created. The Page
48class is providing a deep_copy method to make sure everything important is
49copied.
50
51===Keywords
52
53Pages of course come with meta data attatched to them. Keywords are one kind of
54meta data. They can be understood and used as tags, categories or any similar
55concept.
56
57===Aggregation
58
59Keywords and other meta data can be used to aggregate any ammount of pages
60into the body of another page.
61
62<aggregate
63 flags="updates pressemitteilungen"
64 limit="20"
65 order_by="published_at"
66 order_direction="DESC"
67/>
68
13 69
14git clone ssh://git@svn.medienhaus.udk-berlin.de/usr/local/git/cccms 70git clone ssh://git@svn.medienhaus.udk-berlin.de/usr/local/git/cccms
15 71
diff --git a/test/fixtures/flags.yml b/test/fixtures/flags.yml
new file mode 100644
index 0000000..157d747
--- /dev/null
+++ b/test/fixtures/flags.yml
@@ -0,0 +1,7 @@
1# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
3one:
4 name: MyString
5
6two:
7 name: MyString
diff --git a/test/unit/flag_test.rb b/test/unit/flag_test.rb
new file mode 100644
index 0000000..49b0d96
--- /dev/null
+++ b/test/unit/flag_test.rb
@@ -0,0 +1,8 @@
1require 'test_helper'
2
3class FlagTest < ActiveSupport::TestCase
4 # Replace this with your real tests.
5 test "the truth" do
6 assert true
7 end
8end