Changes to the Controller Class
The controller class, WikiController (see
Listing 3), changes significantly from the original RailsWiki application. Let's review some of methods with the most notable changes.
The create_account method kicks things off by allowing a user to create his or her own account. If all the parameters passed into this method are valid, the user's account (password file) is created using the WikiUser model class, as demonstrated here:
wu = WikiUser.new user
wu.create_account pass
flash[:error] = "Account created; you may login now."
The login method authenticates the user using the WikiUser model class. If the user's credentials are valid, the system establishes a session for the user and forwards him or her to the home view. Otherwise, it sends the user back to the index view with an error message. The following code excerpt demonstrates all of this:
unless wikiuser.valid_password?(pass)
flash[:error] = "Invalid password."
redirect_to :action => :index
else
session[:user] = wikiuser
redirect_to :action => :home, :f => DEFAULT_FILENAME
end
The home method simply gathers a list of wiki pages, encrypted and non-encrypted, which belong to the current user and passes it to the home view, as demonstrated here:
@filelist = []
list1 = WikiDocument.find_wikis(get_basedir, PLAIN_EXTENSION)
list2 = WikiDocument.find_wikis(get_basedir, ENCRYPTED_EXTENSION)
@filelist.concat(list1) unless list1.nil?
@filelist.concat(list2) unless list2.nil?
The create method creates a blank wiki file with the appropriate extension, as shown here:
if (extname.nil? || (extname != ENCRYPTED_EXTENSION && extname != PLAIN_EXTENSION))
if (encrypt)
@filename = @filename + ENCRYPTED_EXTENSION
else
@filename = @filename + PLAIN_EXTENSION
end
end
The save method calls the internal/private method save_document, which in turn determines the appropriate save method to call on the WikiDocument model class based on whether encryption is required or not, as demonstrated here:
def save_document(filename, content, encrypt)
if (encrypt)
WikiDocument.save_encrypted((get_fullpath filename, false), content, (get_session_object).key)
else
WikiDocument.save((get_fullpath filename, false), content)
end
end
Once a wiki file has been created, these files are read using the private method get_content, which determines whether the file needs to be decrypted or not, as shown here:
@filestat = WikiDocument.attributes(get_fullpath(@filename))
extname = File.extname(@filename)
if (extname == ENCRYPTED_EXTENSION)
@content = WikiDocument.find_encrypted(get_fullpath(@filename), (get_session_object).key)
else
@content = WikiDocument.find(get_fullpath(@filename))
end
One last notable method in the controller class is the authenticate method. This method is called before various methods that require a user to be logged in, that is, they require an active session for the user. This method is automatically called prior to such methods by using Rails' filters as shown in this single line of code:
before_filter :authenticate, :only => [:home, :edit, :view, :print]
Configuration File
The other file worth inspecting is the config/environment.rb file, since it contains various default settings for RailsWiki, as shown here:
WIKI_DIR = "/users"
PLAIN_EXTENSION = ".wiki"
ENCRYPTED_EXTENSION = ".swiki"
DEFAULT_FILENAME = "untitled" + PLAIN_EXTENSION
PASSWORD_KEY = "WikiUserKey"
PASSWORD_FILE = ".railswiki_pass"
PATH_SEPARATOR = "/"
The Wrap Up
Part 1 of this article series showed how to build RailsWiki, a very bare bones but functional wiki system. This article added security features to it, namely authentication and encryption. However, many robust wiki systems today tend to contain a lot more features to enable collaboration. Here are some ideas for extending the RailsWiki system even further:
- Add role-based security (that is, authorization)
- Add email alerts for notifying others when changes to a file occur
- Add revisions and ability to roll back to a previous version of a wiki document
- Add search capabilities using something like the Ferret library
If you decide to add any of the above features, be sure to submit your changes to the RailsWiki open source project on RubyForge and/or notify me, as I would love to use some of them myself!