Added parent-child relationship to pages to visualize a breadcrump and subpages.
This commit is contained in:
parent
00619ccf55
commit
a8c93c08b7
24 changed files with 513 additions and 51 deletions
|
@ -24,6 +24,7 @@ class PagesController < ApplicationController
|
||||||
def new
|
def new
|
||||||
@page = Page.new
|
@page = Page.new
|
||||||
@page.title = params[:title].gsub("_", " ") if params[:title]
|
@page.title = params[:title].gsub("_", " ") if params[:title]
|
||||||
|
@page.parent = Page.find_by_permalink(params[:parent]) if params[:parent]
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html # new.html.erb
|
format.html # new.html.erb
|
||||||
|
|
|
@ -95,8 +95,13 @@ module ApplicationHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
# to set a title for both the h1-tag and the title in the header
|
# to set a title for both the h1-tag and the title in the header
|
||||||
def title(page_title)
|
def title(page_title, show_title = true)
|
||||||
content_for(:title) { page_title }
|
@content_for_title = page_title.to_s
|
||||||
|
@show_title = show_title
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_title?
|
||||||
|
@show_title
|
||||||
end
|
end
|
||||||
|
|
||||||
def tab_is_active?(tab)
|
def tab_is_active?(tab)
|
||||||
|
|
|
@ -9,10 +9,13 @@ module PagesHelper
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
|
|
||||||
def wikified_body(body)
|
def wikified_body(page)
|
||||||
WikiCloth.new({:data => body, :link_handler => Wikilink.new}).to_html
|
WikiCloth.new({:data => page.body, :link_handler => Wikilink.new, :params => {:referer => page.title}}).to_html
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def link_to_wikipage(page)
|
||||||
|
link_to page.title, "/wiki/#{page.title}"
|
||||||
|
end
|
||||||
# def generate_toc(body)
|
# def generate_toc(body)
|
||||||
# toc = ""
|
# toc = ""
|
||||||
# body.gsub(/^([=]{1,6})\s*(.*?)\s*(\1)/) do
|
# body.gsub(/^([=]{1,6})\s*(.*?)\s*(\1)/) do
|
||||||
|
|
|
@ -19,6 +19,7 @@ class Page < ActiveRecord::Base
|
||||||
|
|
||||||
acts_as_versioned :version_column => :lock_version
|
acts_as_versioned :version_column => :lock_version
|
||||||
self.non_versioned_columns += ['permalink', 'created_at', 'title']
|
self.non_versioned_columns += ['permalink', 'created_at', 'title']
|
||||||
|
acts_as_tree :order => "title"
|
||||||
|
|
||||||
attr_accessor :old_title # Save title to create redirect page when editing title
|
attr_accessor :old_title # Save title to create redirect page when editing title
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
- if flash[:error]
|
- if flash[:error]
|
||||||
%h3.error#flashError= flash[:error]
|
%h3.error#flashError= flash[:error]
|
||||||
#loader{:style => "display:none;"}= image_tag("loader.gif", :border => 0)
|
#loader{:style => "display:none;"}= image_tag("loader.gif", :border => 0)
|
||||||
- if yield(:title)
|
- if show_title?
|
||||||
%h1= yield(:title)
|
%h1= yield(:title)
|
||||||
= yield
|
= yield
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
- content = wikified_body @page.body
|
- content = wikified_body @page
|
||||||
//#toc
|
//#toc
|
||||||
//%h2 Inhaltsverzeichnis
|
//%h2 Inhaltsverzeichnis
|
||||||
//= generate_toc @page.body
|
//= generate_toc @page.body
|
||||||
|
|
|
@ -21,8 +21,9 @@
|
||||||
- form_for @page do |f|
|
- form_for @page do |f|
|
||||||
= f.error_messages
|
= f.error_messages
|
||||||
= f.hidden_field :lock_version
|
= f.hidden_field :lock_version
|
||||||
|
= f.hidden_field :parent_id
|
||||||
%p
|
%p
|
||||||
%b Title
|
%b Titel
|
||||||
%br/
|
%br/
|
||||||
= f.text_field :title
|
= f.text_field :title
|
||||||
%p
|
%p
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
- title @page.title
|
- title @page.title, false
|
||||||
|
|
||||||
#page-versions{:style => "float:right;margin-top:-2%;text-align:right;"}
|
%h1
|
||||||
|
%span#breadcrump
|
||||||
|
- for page in @page.ancestors.reverse
|
||||||
|
= link_to_wikipage(page)
|
||||||
|
>>
|
||||||
|
= @page.title
|
||||||
|
|
||||||
|
#sidebar
|
||||||
|
#page-versions
|
||||||
= link_to "Bearbeiten", edit_page_path(@page)
|
= link_to "Bearbeiten", edit_page_path(@page)
|
||||||
= link_to_function "Versionen (#{@page.versions.count})", "Element.toggle('versions')"
|
= link_to_function "Versionen (#{@page.versions.count})", "Element.toggle('versions')"
|
||||||
#versions{:style => "display:none"}
|
#versions{:style => "display:none"}
|
||||||
|
@ -10,6 +18,13 @@
|
||||||
= link_to I18n.l(version.updated_at, :format => "%d.%m.%y %H:%M"), version_page_path(@page, :version => version.lock_version)
|
= link_to I18n.l(version.updated_at, :format => "%d.%m.%y %H:%M"), version_page_path(@page, :version => version.lock_version)
|
||||||
= "(#{User.find(version.updated_by).nick})"
|
= "(#{User.find(version.updated_by).nick})"
|
||||||
|
|
||||||
|
- unless @page.children.empty?
|
||||||
|
#children
|
||||||
|
%h2 Unterseiten
|
||||||
|
%ul
|
||||||
|
- for page in @page.children
|
||||||
|
%li= link_to_wikipage(page)
|
||||||
|
|
||||||
= render :partial => 'body'
|
= render :partial => 'body'
|
||||||
|
|
||||||
%hr.clear/
|
%hr.clear/
|
||||||
|
|
|
@ -7,6 +7,7 @@ class CreatePages < ActiveRecord::Migration
|
||||||
t.integer :lock_version, :default => 0
|
t.integer :lock_version, :default => 0
|
||||||
t.integer :updated_by
|
t.integer :updated_by
|
||||||
t.integer :redirect
|
t.integer :redirect
|
||||||
|
t.integer :parent_id
|
||||||
|
|
||||||
t.timestamps
|
t.timestamps
|
||||||
end
|
end
|
||||||
|
|
49
db/schema.rb
49
db/schema.rb
|
@ -9,7 +9,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended to check this file into your version control system.
|
# It's strongly recommended to check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(:version => 20090317175355) do
|
ActiveRecord::Schema.define(:version => 20090812110010) do
|
||||||
|
|
||||||
create_table "article_categories", :force => true do |t|
|
create_table "article_categories", :force => true do |t|
|
||||||
t.string "name", :default => "", :null => false
|
t.string "name", :default => "", :null => false
|
||||||
|
@ -37,16 +37,16 @@ ActiveRecord::Schema.define(:version => 20090317175355) do
|
||||||
t.string "manufacturer"
|
t.string "manufacturer"
|
||||||
t.string "origin"
|
t.string "origin"
|
||||||
t.datetime "shared_updated_on"
|
t.datetime "shared_updated_on"
|
||||||
t.decimal "price"
|
t.decimal "price", :precision => 8, :scale => 2
|
||||||
t.float "tax"
|
t.float "tax"
|
||||||
t.decimal "deposit", :default => 0.0
|
t.decimal "deposit", :precision => 8, :scale => 2, :default => 0.0
|
||||||
t.integer "unit_quantity", :default => 1, :null => false
|
t.integer "unit_quantity", :default => 1, :null => false
|
||||||
t.string "order_number"
|
t.string "order_number"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.integer "quantity", :default => 0
|
|
||||||
t.datetime "deleted_at"
|
t.datetime "deleted_at"
|
||||||
t.string "type"
|
t.string "type"
|
||||||
|
t.integer "quantity", :default => 0
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "articles", ["name", "supplier_id"], :name => "index_articles_on_name_and_supplier_id"
|
add_index "articles", ["name", "supplier_id"], :name => "index_articles_on_name_and_supplier_id"
|
||||||
|
@ -75,6 +75,7 @@ ActiveRecord::Schema.define(:version => 20090317175355) do
|
||||||
t.integer "supplier_id"
|
t.integer "supplier_id"
|
||||||
t.date "delivered_on"
|
t.date "delivered_on"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
|
t.text "note"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "financial_transactions", :force => true do |t|
|
create_table "financial_transactions", :force => true do |t|
|
||||||
|
@ -98,7 +99,7 @@ ActiveRecord::Schema.define(:version => 20090317175355) do
|
||||||
t.integer "quantity", :default => 0, :null => false
|
t.integer "quantity", :default => 0, :null => false
|
||||||
t.integer "tolerance", :default => 0, :null => false
|
t.integer "tolerance", :default => 0, :null => false
|
||||||
t.datetime "updated_on", :null => false
|
t.datetime "updated_on", :null => false
|
||||||
t.integer "result"
|
t.decimal "result", :precision => 8, :scale => 3
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "group_order_articles", ["group_order_id", "order_article_id"], :name => "goa_index", :unique => true
|
add_index "group_order_articles", ["group_order_id", "order_article_id"], :name => "goa_index", :unique => true
|
||||||
|
@ -118,7 +119,7 @@ ActiveRecord::Schema.define(:version => 20090317175355) do
|
||||||
t.string "type", :default => "", :null => false
|
t.string "type", :default => "", :null => false
|
||||||
t.string "name", :default => "", :null => false
|
t.string "name", :default => "", :null => false
|
||||||
t.string "description"
|
t.string "description"
|
||||||
t.decimal "account_balance", :default => 0.0, :null => false
|
t.decimal "account_balance", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
||||||
t.datetime "account_updated"
|
t.datetime "account_updated"
|
||||||
t.datetime "created_on", :null => false
|
t.datetime "created_on", :null => false
|
||||||
t.boolean "role_admin", :default => false, :null => false
|
t.boolean "role_admin", :default => false, :null => false
|
||||||
|
@ -135,6 +136,7 @@ ActiveRecord::Schema.define(:version => 20090317175355) do
|
||||||
t.string "contact_person"
|
t.string "contact_person"
|
||||||
t.string "contact_phone"
|
t.string "contact_phone"
|
||||||
t.string "contact_address"
|
t.string "contact_address"
|
||||||
|
t.text "stats"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "groups", ["name"], :name => "index_groups_on_name", :unique => true
|
add_index "groups", ["name"], :name => "index_groups_on_name", :unique => true
|
||||||
|
@ -152,16 +154,16 @@ ActiveRecord::Schema.define(:version => 20090317175355) do
|
||||||
create_table "invoices", :force => true do |t|
|
create_table "invoices", :force => true do |t|
|
||||||
t.integer "supplier_id"
|
t.integer "supplier_id"
|
||||||
t.integer "delivery_id"
|
t.integer "delivery_id"
|
||||||
|
t.integer "order_id"
|
||||||
t.string "number"
|
t.string "number"
|
||||||
t.date "date"
|
t.date "date"
|
||||||
t.date "paid_on"
|
t.date "paid_on"
|
||||||
t.text "note"
|
t.text "note"
|
||||||
t.decimal "amount", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
t.decimal "amount", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
||||||
t.datetime "created_at"
|
|
||||||
t.datetime "updated_at"
|
|
||||||
t.integer "order_id"
|
|
||||||
t.decimal "deposit", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
t.decimal "deposit", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
||||||
t.decimal "deposit_credit", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
t.decimal "deposit_credit", :precision => 8, :scale => 2, :default => 0.0, :null => false
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "memberships", :force => true do |t|
|
create_table "memberships", :force => true do |t|
|
||||||
|
@ -211,6 +213,34 @@ ActiveRecord::Schema.define(:version => 20090317175355) do
|
||||||
t.decimal "foodcoop_result", :precision => 8, :scale => 2
|
t.decimal "foodcoop_result", :precision => 8, :scale => 2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "page_versions", :force => true do |t|
|
||||||
|
t.integer "page_id"
|
||||||
|
t.integer "lock_version"
|
||||||
|
t.text "body"
|
||||||
|
t.integer "updated_by"
|
||||||
|
t.integer "redirect"
|
||||||
|
t.integer "parent_id"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index "page_versions", ["page_id"], :name => "index_page_versions_on_page_id"
|
||||||
|
|
||||||
|
create_table "pages", :force => true do |t|
|
||||||
|
t.string "title"
|
||||||
|
t.text "body"
|
||||||
|
t.string "permalink"
|
||||||
|
t.integer "lock_version", :default => 0
|
||||||
|
t.integer "updated_by"
|
||||||
|
t.integer "redirect"
|
||||||
|
t.integer "parent_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "schema_info", :id => false, :force => true do |t|
|
||||||
|
t.integer "version"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "stock_changes", :force => true do |t|
|
create_table "stock_changes", :force => true do |t|
|
||||||
t.integer "delivery_id"
|
t.integer "delivery_id"
|
||||||
t.integer "order_id"
|
t.integer "order_id"
|
||||||
|
@ -256,6 +286,7 @@ ActiveRecord::Schema.define(:version => 20090317175355) do
|
||||||
t.datetime "created_on", :null => false
|
t.datetime "created_on", :null => false
|
||||||
t.datetime "updated_on", :null => false
|
t.datetime "updated_on", :null => false
|
||||||
t.integer "required_users", :default => 1
|
t.integer "required_users", :default => 1
|
||||||
|
t.boolean "weekly"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "tasks", ["due_date"], :name => "index_tasks_on_due_date"
|
add_index "tasks", ["due_date"], :name => "index_tasks_on_due_date"
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
class Wikilink < WikiCloth::WikiLinkHandler
|
class Wikilink < WikiCloth::WikiLinkHandler
|
||||||
|
|
||||||
def url_for(page)
|
def url_for(page, parent = nil)
|
||||||
|
if parent
|
||||||
|
"/pages/new?title=#{page}&parent=#{parent}"
|
||||||
|
else
|
||||||
"/wiki/#{page}"
|
"/wiki/#{page}"
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def link_attributes_for(page)
|
def link_attributes_for(page)
|
||||||
permalink = Page.permalink(page)
|
permalink = Page.permalink(page)
|
||||||
if Page.exists?(:permalink => permalink)
|
if Page.exists?(:permalink => permalink)
|
||||||
{ :href => url_for(permalink) }
|
{ :href => url_for(permalink) }
|
||||||
else
|
else
|
||||||
{ :href => url_for(page), :class => "new_wiki_link"}
|
{ :href => url_for(page, params[:referer]), :class => "new_wiki_link"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -448,6 +448,18 @@ a.new_wiki_link {
|
||||||
#toc {
|
#toc {
|
||||||
float: right; }
|
float: right; }
|
||||||
|
|
||||||
|
#breadcrump {
|
||||||
|
font-size: 0.5em; }
|
||||||
|
#breadcrump a {
|
||||||
|
color: #ed0606; }
|
||||||
|
|
||||||
|
#sidebar {
|
||||||
|
float: right;
|
||||||
|
margin-top: -2%;
|
||||||
|
width: 20%; }
|
||||||
|
#sidebar #page-versions {
|
||||||
|
text-align: right; }
|
||||||
|
|
||||||
#wiki_content h1, #wiki_content h2, #wiki_content h3, #wiki_content h4, #wiki_content h5 {
|
#wiki_content h1, #wiki_content h2, #wiki_content h3, #wiki_content h4, #wiki_content h5 {
|
||||||
color: black; }
|
color: black; }
|
||||||
#wiki_content span.editsection {
|
#wiki_content span.editsection {
|
||||||
|
|
|
@ -448,6 +448,18 @@ a.new_wiki_link {
|
||||||
#toc {
|
#toc {
|
||||||
float: right; }
|
float: right; }
|
||||||
|
|
||||||
|
#breadcrump {
|
||||||
|
font-size: 0.5em; }
|
||||||
|
#breadcrump a {
|
||||||
|
color: #ed0606; }
|
||||||
|
|
||||||
|
#sidebar {
|
||||||
|
float: right;
|
||||||
|
margin-top: -2%;
|
||||||
|
width: 20%; }
|
||||||
|
#sidebar #page-versions {
|
||||||
|
text-align: right; }
|
||||||
|
|
||||||
#wiki_content h1, #wiki_content h2, #wiki_content h3, #wiki_content h4, #wiki_content h5 {
|
#wiki_content h1, #wiki_content h2, #wiki_content h3, #wiki_content h4, #wiki_content h5 {
|
||||||
color: black; }
|
color: black; }
|
||||||
#wiki_content span.editsection {
|
#wiki_content span.editsection {
|
||||||
|
|
|
@ -493,6 +493,18 @@ a.new_wiki_link
|
||||||
padding: 0 1em
|
padding: 0 1em
|
||||||
#toc
|
#toc
|
||||||
float: right
|
float: right
|
||||||
|
#breadcrump
|
||||||
|
font-size: 0.5em
|
||||||
|
a
|
||||||
|
:color = !main_red
|
||||||
|
#sidebar
|
||||||
|
float: right
|
||||||
|
margin-top: -2%
|
||||||
|
width: 20%
|
||||||
|
#page-versions
|
||||||
|
text-align: right
|
||||||
|
|
||||||
|
|
||||||
#wiki_content
|
#wiki_content
|
||||||
h1, h2, h3, h4, h5
|
h1, h2, h3, h4, h5
|
||||||
color: black
|
color: black
|
||||||
|
|
26
vendor/plugins/acts_as_tree/README
vendored
Normal file
26
vendor/plugins/acts_as_tree/README
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
acts_as_tree
|
||||||
|
============
|
||||||
|
|
||||||
|
Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children
|
||||||
|
association. This requires that you have a foreign key column, which by default is called +parent_id+.
|
||||||
|
|
||||||
|
class Category < ActiveRecord::Base
|
||||||
|
acts_as_tree :order => "name"
|
||||||
|
end
|
||||||
|
|
||||||
|
Example:
|
||||||
|
root
|
||||||
|
\_ child1
|
||||||
|
\_ subchild1
|
||||||
|
\_ subchild2
|
||||||
|
|
||||||
|
root = Category.create("name" => "root")
|
||||||
|
child1 = root.children.create("name" => "child1")
|
||||||
|
subchild1 = child1.children.create("name" => "subchild1")
|
||||||
|
|
||||||
|
root.parent # => nil
|
||||||
|
child1.parent # => root
|
||||||
|
root.children # => [child1]
|
||||||
|
root.children.first.children.first # => subchild1
|
||||||
|
|
||||||
|
Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
|
22
vendor/plugins/acts_as_tree/Rakefile
vendored
Normal file
22
vendor/plugins/acts_as_tree/Rakefile
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
require 'rake'
|
||||||
|
require 'rake/testtask'
|
||||||
|
require 'rake/rdoctask'
|
||||||
|
|
||||||
|
desc 'Default: run unit tests.'
|
||||||
|
task :default => :test
|
||||||
|
|
||||||
|
desc 'Test acts_as_tree plugin.'
|
||||||
|
Rake::TestTask.new(:test) do |t|
|
||||||
|
t.libs << 'lib'
|
||||||
|
t.pattern = 'test/**/*_test.rb'
|
||||||
|
t.verbose = true
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Generate documentation for acts_as_tree plugin.'
|
||||||
|
Rake::RDocTask.new(:rdoc) do |rdoc|
|
||||||
|
rdoc.rdoc_dir = 'rdoc'
|
||||||
|
rdoc.title = 'acts_as_tree'
|
||||||
|
rdoc.options << '--line-numbers' << '--inline-source'
|
||||||
|
rdoc.rdoc_files.include('README')
|
||||||
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||||
|
end
|
1
vendor/plugins/acts_as_tree/init.rb
vendored
Normal file
1
vendor/plugins/acts_as_tree/init.rb
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ActiveRecord::Base.send :include, ActiveRecord::Acts::Tree
|
96
vendor/plugins/acts_as_tree/lib/active_record/acts/tree.rb
vendored
Normal file
96
vendor/plugins/acts_as_tree/lib/active_record/acts/tree.rb
vendored
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
module ActiveRecord
|
||||||
|
module Acts
|
||||||
|
module Tree
|
||||||
|
def self.included(base)
|
||||||
|
base.extend(ClassMethods)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children
|
||||||
|
# association. This requires that you have a foreign key column, which by default is called +parent_id+.
|
||||||
|
#
|
||||||
|
# class Category < ActiveRecord::Base
|
||||||
|
# acts_as_tree :order => "name"
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# root
|
||||||
|
# \_ child1
|
||||||
|
# \_ subchild1
|
||||||
|
# \_ subchild2
|
||||||
|
#
|
||||||
|
# root = Category.create("name" => "root")
|
||||||
|
# child1 = root.children.create("name" => "child1")
|
||||||
|
# subchild1 = child1.children.create("name" => "subchild1")
|
||||||
|
#
|
||||||
|
# root.parent # => nil
|
||||||
|
# child1.parent # => root
|
||||||
|
# root.children # => [child1]
|
||||||
|
# root.children.first.children.first # => subchild1
|
||||||
|
#
|
||||||
|
# In addition to the parent and children associations, the following instance methods are added to the class
|
||||||
|
# after calling <tt>acts_as_tree</tt>:
|
||||||
|
# * <tt>siblings</tt> - Returns all the children of the parent, excluding the current node (<tt>[subchild2]</tt> when called on <tt>subchild1</tt>)
|
||||||
|
# * <tt>self_and_siblings</tt> - Returns all the children of the parent, including the current node (<tt>[subchild1, subchild2]</tt> when called on <tt>subchild1</tt>)
|
||||||
|
# * <tt>ancestors</tt> - Returns all the ancestors of the current node (<tt>[child1, root]</tt> when called on <tt>subchild2</tt>)
|
||||||
|
# * <tt>root</tt> - Returns the root of the current node (<tt>root</tt> when called on <tt>subchild2</tt>)
|
||||||
|
module ClassMethods
|
||||||
|
# Configuration options are:
|
||||||
|
#
|
||||||
|
# * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
|
||||||
|
# * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
|
||||||
|
# * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
|
||||||
|
def acts_as_tree(options = {})
|
||||||
|
configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil }
|
||||||
|
configuration.update(options) if options.is_a?(Hash)
|
||||||
|
|
||||||
|
belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
|
||||||
|
has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => :destroy
|
||||||
|
|
||||||
|
class_eval <<-EOV
|
||||||
|
include ActiveRecord::Acts::Tree::InstanceMethods
|
||||||
|
|
||||||
|
def self.roots
|
||||||
|
find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.root
|
||||||
|
find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
|
||||||
|
end
|
||||||
|
EOV
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
# Returns list of ancestors, starting from parent until root.
|
||||||
|
#
|
||||||
|
# subchild1.ancestors # => [child1, root]
|
||||||
|
def ancestors
|
||||||
|
node, nodes = self, []
|
||||||
|
nodes << node = node.parent while node.parent
|
||||||
|
nodes
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the root node of the tree.
|
||||||
|
def root
|
||||||
|
node = self
|
||||||
|
node = node.parent while node.parent
|
||||||
|
node
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns all siblings of the current node.
|
||||||
|
#
|
||||||
|
# subchild1.siblings # => [subchild2]
|
||||||
|
def siblings
|
||||||
|
self_and_siblings - [self]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns all siblings and a reference to the current node.
|
||||||
|
#
|
||||||
|
# subchild1.self_and_siblings # => [subchild1, subchild2]
|
||||||
|
def self_and_siblings
|
||||||
|
parent ? parent.children : self.class.roots
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
0
vendor/plugins/acts_as_tree/test/abstract_unit.rb
vendored
Normal file
0
vendor/plugins/acts_as_tree/test/abstract_unit.rb
vendored
Normal file
219
vendor/plugins/acts_as_tree/test/acts_as_tree_test.rb
vendored
Normal file
219
vendor/plugins/acts_as_tree/test/acts_as_tree_test.rb
vendored
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
require 'test/unit'
|
||||||
|
|
||||||
|
require 'rubygems'
|
||||||
|
require 'active_record'
|
||||||
|
|
||||||
|
$:.unshift File.dirname(__FILE__) + '/../lib'
|
||||||
|
require File.dirname(__FILE__) + '/../init'
|
||||||
|
|
||||||
|
class Test::Unit::TestCase
|
||||||
|
def assert_queries(num = 1)
|
||||||
|
$query_count = 0
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed."
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_no_queries(&block)
|
||||||
|
assert_queries(0, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
|
||||||
|
|
||||||
|
# AR keeps printing annoying schema statements
|
||||||
|
$stdout = StringIO.new
|
||||||
|
|
||||||
|
def setup_db
|
||||||
|
ActiveRecord::Base.logger
|
||||||
|
ActiveRecord::Schema.define(:version => 1) do
|
||||||
|
create_table :mixins do |t|
|
||||||
|
t.column :type, :string
|
||||||
|
t.column :parent_id, :integer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown_db
|
||||||
|
ActiveRecord::Base.connection.tables.each do |table|
|
||||||
|
ActiveRecord::Base.connection.drop_table(table)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Mixin < ActiveRecord::Base
|
||||||
|
end
|
||||||
|
|
||||||
|
class TreeMixin < Mixin
|
||||||
|
acts_as_tree :foreign_key => "parent_id", :order => "id"
|
||||||
|
end
|
||||||
|
|
||||||
|
class TreeMixinWithoutOrder < Mixin
|
||||||
|
acts_as_tree :foreign_key => "parent_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
class RecursivelyCascadedTreeMixin < Mixin
|
||||||
|
acts_as_tree :foreign_key => "parent_id"
|
||||||
|
has_one :first_child, :class_name => 'RecursivelyCascadedTreeMixin', :foreign_key => :parent_id
|
||||||
|
end
|
||||||
|
|
||||||
|
class TreeTest < Test::Unit::TestCase
|
||||||
|
|
||||||
|
def setup
|
||||||
|
setup_db
|
||||||
|
@root1 = TreeMixin.create!
|
||||||
|
@root_child1 = TreeMixin.create! :parent_id => @root1.id
|
||||||
|
@child1_child = TreeMixin.create! :parent_id => @root_child1.id
|
||||||
|
@root_child2 = TreeMixin.create! :parent_id => @root1.id
|
||||||
|
@root2 = TreeMixin.create!
|
||||||
|
@root3 = TreeMixin.create!
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
teardown_db
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_children
|
||||||
|
assert_equal @root1.children, [@root_child1, @root_child2]
|
||||||
|
assert_equal @root_child1.children, [@child1_child]
|
||||||
|
assert_equal @child1_child.children, []
|
||||||
|
assert_equal @root_child2.children, []
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_parent
|
||||||
|
assert_equal @root_child1.parent, @root1
|
||||||
|
assert_equal @root_child1.parent, @root_child2.parent
|
||||||
|
assert_nil @root1.parent
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_delete
|
||||||
|
assert_equal 6, TreeMixin.count
|
||||||
|
@root1.destroy
|
||||||
|
assert_equal 2, TreeMixin.count
|
||||||
|
@root2.destroy
|
||||||
|
@root3.destroy
|
||||||
|
assert_equal 0, TreeMixin.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_insert
|
||||||
|
@extra = @root1.children.create
|
||||||
|
|
||||||
|
assert @extra
|
||||||
|
|
||||||
|
assert_equal @extra.parent, @root1
|
||||||
|
|
||||||
|
assert_equal 3, @root1.children.size
|
||||||
|
assert @root1.children.include?(@extra)
|
||||||
|
assert @root1.children.include?(@root_child1)
|
||||||
|
assert @root1.children.include?(@root_child2)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_ancestors
|
||||||
|
assert_equal [], @root1.ancestors
|
||||||
|
assert_equal [@root1], @root_child1.ancestors
|
||||||
|
assert_equal [@root_child1, @root1], @child1_child.ancestors
|
||||||
|
assert_equal [@root1], @root_child2.ancestors
|
||||||
|
assert_equal [], @root2.ancestors
|
||||||
|
assert_equal [], @root3.ancestors
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root
|
||||||
|
assert_equal @root1, TreeMixin.root
|
||||||
|
assert_equal @root1, @root1.root
|
||||||
|
assert_equal @root1, @root_child1.root
|
||||||
|
assert_equal @root1, @child1_child.root
|
||||||
|
assert_equal @root1, @root_child2.root
|
||||||
|
assert_equal @root2, @root2.root
|
||||||
|
assert_equal @root3, @root3.root
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_roots
|
||||||
|
assert_equal [@root1, @root2, @root3], TreeMixin.roots
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_siblings
|
||||||
|
assert_equal [@root2, @root3], @root1.siblings
|
||||||
|
assert_equal [@root_child2], @root_child1.siblings
|
||||||
|
assert_equal [], @child1_child.siblings
|
||||||
|
assert_equal [@root_child1], @root_child2.siblings
|
||||||
|
assert_equal [@root1, @root3], @root2.siblings
|
||||||
|
assert_equal [@root1, @root2], @root3.siblings
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_self_and_siblings
|
||||||
|
assert_equal [@root1, @root2, @root3], @root1.self_and_siblings
|
||||||
|
assert_equal [@root_child1, @root_child2], @root_child1.self_and_siblings
|
||||||
|
assert_equal [@child1_child], @child1_child.self_and_siblings
|
||||||
|
assert_equal [@root_child1, @root_child2], @root_child2.self_and_siblings
|
||||||
|
assert_equal [@root1, @root2, @root3], @root2.self_and_siblings
|
||||||
|
assert_equal [@root1, @root2, @root3], @root3.self_and_siblings
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TreeTestWithEagerLoading < Test::Unit::TestCase
|
||||||
|
|
||||||
|
def setup
|
||||||
|
teardown_db
|
||||||
|
setup_db
|
||||||
|
@root1 = TreeMixin.create!
|
||||||
|
@root_child1 = TreeMixin.create! :parent_id => @root1.id
|
||||||
|
@child1_child = TreeMixin.create! :parent_id => @root_child1.id
|
||||||
|
@root_child2 = TreeMixin.create! :parent_id => @root1.id
|
||||||
|
@root2 = TreeMixin.create!
|
||||||
|
@root3 = TreeMixin.create!
|
||||||
|
|
||||||
|
@rc1 = RecursivelyCascadedTreeMixin.create!
|
||||||
|
@rc2 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc1.id
|
||||||
|
@rc3 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc2.id
|
||||||
|
@rc4 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc3.id
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
teardown_db
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_eager_association_loading
|
||||||
|
roots = TreeMixin.find(:all, :include => :children, :conditions => "mixins.parent_id IS NULL", :order => "mixins.id")
|
||||||
|
assert_equal [@root1, @root2, @root3], roots
|
||||||
|
assert_no_queries do
|
||||||
|
assert_equal 2, roots[0].children.size
|
||||||
|
assert_equal 0, roots[1].children.size
|
||||||
|
assert_equal 0, roots[2].children.size
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_eager_association_loading_with_recursive_cascading_three_levels_has_many
|
||||||
|
root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :children => { :children => :children } }, :order => 'mixins.id')
|
||||||
|
assert_equal @rc4, assert_no_queries { root_node.children.first.children.first.children.first }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_eager_association_loading_with_recursive_cascading_three_levels_has_one
|
||||||
|
root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :first_child => { :first_child => :first_child } }, :order => 'mixins.id')
|
||||||
|
assert_equal @rc4, assert_no_queries { root_node.first_child.first_child.first_child }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_eager_association_loading_with_recursive_cascading_three_levels_belongs_to
|
||||||
|
leaf_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :parent => { :parent => :parent } }, :order => 'mixins.id DESC')
|
||||||
|
assert_equal @rc1, assert_no_queries { leaf_node.parent.parent.parent }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TreeTestWithoutOrder < Test::Unit::TestCase
|
||||||
|
|
||||||
|
def setup
|
||||||
|
setup_db
|
||||||
|
@root1 = TreeMixinWithoutOrder.create!
|
||||||
|
@root2 = TreeMixinWithoutOrder.create!
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
teardown_db
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root
|
||||||
|
assert [@root1, @root2].include?(TreeMixinWithoutOrder.root)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_roots
|
||||||
|
assert_equal [], [@root1, @root2] - TreeMixinWithoutOrder.roots
|
||||||
|
end
|
||||||
|
end
|
0
vendor/plugins/acts_as_tree/test/database.yml
vendored
Normal file
0
vendor/plugins/acts_as_tree/test/database.yml
vendored
Normal file
0
vendor/plugins/acts_as_tree/test/fixtures/mixin.rb
vendored
Normal file
0
vendor/plugins/acts_as_tree/test/fixtures/mixin.rb
vendored
Normal file
0
vendor/plugins/acts_as_tree/test/fixtures/mixins.yml
vendored
Normal file
0
vendor/plugins/acts_as_tree/test/fixtures/mixins.yml
vendored
Normal file
0
vendor/plugins/acts_as_tree/test/schema.rb
vendored
Normal file
0
vendor/plugins/acts_as_tree/test/schema.rb
vendored
Normal file
Loading…
Reference in a new issue