Refactoring the Web Model (From James Herdman)

A bit of refactoring, via 

  http://github.com/jherdman/instiki/tree/master
This commit is contained in:
Jacques Distler 2009-09-05 23:02:52 -05:00
parent 37a8f30ded
commit f029aae60e
2 changed files with 124 additions and 87 deletions

View file

@ -1,7 +1,27 @@
class Web < ActiveRecord::Base class Web < ActiveRecord::Base
has_many :pages, :dependent => :destroy ## Associations
has_many :pages, :dependent => :destroy
has_many :wiki_files, :dependent => :destroy has_many :wiki_files, :dependent => :destroy
has_many :revisions, :through => :pages
## Hooks
before_save :sanitize_markup
after_save :create_files_directory
before_validation :validate_address
## Validations
validates_uniqueness_of :address
validates_length_of :color, :in => 3..6
## Methods
# @return [Wiki] a new Wiki instance
def wiki def wiki
Wiki.new Wiki.new
end end
@ -13,34 +33,40 @@ class Web < ActiveRecord::Base
end end
def add_page(name, content, time, author, renderer) def add_page(name, content, time, author, renderer)
page = page(name) || Page.new(:web => self, :name => name) page = page(name) || pages.build(:name => name)
page.revise(content, name, time, author, renderer) page.revise(content, name, time, author, renderer)
end end
# @return [Array<String>] a collection of all the names of the authors that
# have ever contributed to the pages for this Web
def authors def authors
connection.select_all( revisions.all(
'SELECT DISTINCT r.author AS author ' + :select => "DISTINCT revisions.author",
'FROM revisions r ' + :order => "1"
'JOIN pages p ON p.id = r.page_id ' + ).collect(&:author)
'WHERE p.web_id = ' + self.id.to_s +
' ORDER by 1 '
).collect { |row| row['author'] }
end end
def categories def categories
select.map { |page| page.categories }.flatten.uniq.sort select.map { |page| page.categories }.flatten.uniq.sort
end end
# @param [String] name the name of some associated Page record to find
# @return [Page, nil] the associated Page record, or +nil+ if no record is
# found with the provided name
def page(name) def page(name)
pages.first(:conditions => ['name = ?', name]) pages.find_by_name(name)
end end
# @return [Page] the last associated Page record
def last_page def last_page
return Page.first(:order => 'id desc', :conditions => ['web_id = ?', self.id]) pages.last
end end
# @param [String] name the name of some potential Page record
# @return [Boolean] whether or not a given Page record exists with a given
# name
def has_page?(name) def has_page?(name)
Page.count(:conditions => ['web_id = ? AND name = ?', id, name]) > 0 pages.exists?(:name => name)
end end
def has_redirect_for?(name) def has_redirect_for?(name)
@ -52,11 +78,11 @@ class Web < ActiveRecord::Base
end end
def has_file?(file_name) def has_file?(file_name)
WikiFile.find_by_file_name(file_name) != nil wiki_files.exists?(:file_name => file_name)
end end
def file_list(sort_order = 'file_name') def file_list(sort_order="file_name")
WikiFile.all(:order => sort_order, :conditions => ['web_id = ?', id]) wiki_files.all(:order => sort_order)
end end
def pages_that_link_to(page_name) def pages_that_link_to(page_name)
@ -67,30 +93,34 @@ class Web < ActiveRecord::Base
WikiReference.pages_that_link_to_file(self, file_name) WikiReference.pages_that_link_to_file(self, file_name)
end end
# @param [String] file_name the name of some WikiFile of interest
# @return [String, nil] the description of some WikiFile of interest, nil if
# the WikiFile could not be found
def description(file_name) def description(file_name)
file = WikiFile.find_by_file_name(file_name) wiki_files.find_by_file_name(file_name).try(:description)
file.description if file
end end
# @return [Symbol] the type of markup used by this Web
def markup def markup
read_attribute('markup').to_sym self[:markup].to_sym
end end
# @return [Hash] a Hash wherein the key is some author's name, and the
# values are an array of page names for that author.
def page_names_by_author def page_names_by_author
connection.select_all( data = revisions.all(
'SELECT DISTINCT r.author AS author, p.name AS page_name ' + :select => "DISTINCT revisions.author AS author, pages.name AS page_name",
'FROM revisions r ' + :order => "pages.name"
'JOIN pages p ON r.page_id = p.id ' + )
"WHERE p.web_id = #{self.id} " +
'ORDER by p.name' data.inject({}) do |result, revision|
).inject({}) { |result, row| result[revision.author] ||= []
author, page_name = row['author'], row['page_name'] result[revision.author] << revision.page_name
result[author] = [] unless result.has_key?(author) result
result[author] << page_name end
result
}
end end
# OPTIMIZE Use the +delete_all+ with conditions for extra efficiency
def remove_pages(pages_to_be_removed) def remove_pages(pages_to_be_removed)
pages_to_be_removed.each { |p| p.destroy } pages_to_be_removed.each { |p| p.destroy }
end end
@ -107,28 +137,39 @@ class Web < ActiveRecord::Base
PageSet.new(self, pages, nil) PageSet.new(self, pages, nil)
end end
# @return [String] uses the +address+ attribute for this record's parameter name
def to_param def to_param
address address
end end
# Called by an +after_save+ hook. Creates the directory that houses this
# Web's associated files.
#
# TODO Move this into the WikiFile model
def create_files_directory def create_files_directory
return unless allow_uploads == 1 return unless allow_uploads == 1
dummy_file = self.wiki_files.build(:file_name => '0', :description => '0', :content => '0')
dummy_file = wiki_files.build(
:file_name => "0",
:description => "0",
:content => "0"
)
File.umask(0002) File.umask(0002)
dir = File.dirname(dummy_file.content_path)
begin begin
require 'fileutils' dummy_file.content_path.parent.mkpath
FileUtils.mkdir_p dir
dummy_file.save dummy_file.save
dummy_file.destroy dummy_file.destroy
rescue => e rescue => e
logger.error("Failed create files directory for #{self.address}: #{e}") logger.error "Failed create files directory for #{address}: #{e}"
raise "Instiki could not create directory to store uploaded files. " + raise "Instiki could not create directory to store uploaded files. " +
"Please make sure that Instiki is allowed to create directory " + "Please make sure that Instiki is allowed to create directory " +
"#{File.expand_path(dir)} and add files to it." "#{dummy_file.content_path.expand_path} and add files to it."
end end
end end
# @return [Pathname] the path to the files for this record
def files_path def files_path
path = Rails.root.join("webs") path = Rails.root.join("webs")
if default_web? if default_web?
@ -138,6 +179,7 @@ class Web < ActiveRecord::Base
end end
end end
# @return [Pathname] the path to PNGs for this record
def blahtex_pngs_path def blahtex_pngs_path
files_path.join("pngs") files_path.join("pngs")
end end
@ -155,11 +197,6 @@ class Web < ActiveRecord::Base
end end
protected protected
before_save :sanitize_markup
after_save :create_files_directory
before_validation :validate_address
validates_uniqueness_of :address
validates_length_of :color, :in => 3..6
def sanitize_markup def sanitize_markup
self.markup = markup.to_s self.markup = markup.to_s
@ -172,7 +209,8 @@ class Web < ActiveRecord::Base
end end
end end
# @return [Boolean] whether or not this record is considered the default Web
def default_web? def default_web?
defined? DEFAULT_WEB and self.address == DEFAULT_WEB defined?(DEFAULT_WEB) && address == DEFAULT_WEB
end end
end end

View file

@ -1,5 +1,4 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
#require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
class WebTest < ActiveSupport::TestCase class WebTest < ActiveSupport::TestCase
fixtures :system, :webs, :pages, :revisions, :wiki_references fixtures :system, :webs, :pages, :revisions, :wiki_references