= Multi Bit Shift Helper The Multi Bit Shift Helper is designed to make it easy to include either the Multi Bit Shift or Multi Bit Shift Advanced flash file upload assets in rails projects. Both Multi Bit Shift and Multi Bit Shift Advanced can be used as form field plugins, and can replace individual or series of file_fields. The replacement is not a direct replacement, as a multi_bit_shift_field is designed to allow any number of files to be uploaded. Both can also operate as separate applets, and can be integrated without forms. == Installation === Multi Bit Shift The Multi Bit Shift plugin should be installed from the SVN Release repository. To install, use the script/plugin method: ruby script/plugin install http://multibitshift.com/svn/multi_bit_shift_helper/branches/multi_bit_shift/current/multi_bit_shift_helper/ === Multi Bit Shift Advanced The Multi Bit Shift Advanced plugin installs both Multi Bit Shift and Multi Bit Shift Advanced. To install, use the script/plugin method: ruby script/plugin install http://multibitshift.com/svn/multi_bit_shift_helper/branches/multi_bit_shift_advanced/current/multi_bit_shift_helper/ == Usage It is recommended that the installation screencasts at http://multibitshift.com/screencasts be viewed as they provide an extensive overview of these installation procedures. === Basic Requirements Multi Bit Shift and Multi Bit Shift Advanced don't require our helper plugins to work, but they do make the applets more manageable. Both plugins are capable of acting independently and only require that the following methods be implemented in order to function: ==== 'uploadURL' URL that files should be uploaded to. The parameters Filename and Filedata are sent to the url. The applicationToken and the requested Token are also sent to the url in the parameters token and application_token. It is expected that the URL responds with either a 200 status if the upload was a success or another invalid status if the upload failed. The content of the reply does not matter. We suggest that errors are indicated with the 409 status code. THIS METHOD DOES NOT PERSIST THE SESSION, see the Session Management section for information about session validation with file uploads. Defaults to action 'upload_file'. def upload_file file_path = "public/uploaded_files" file_data = params[:Filedata] file_name = params[:Filename] if File.exists?(file_path + "/" + file_name) render(:text => 'error', :status => 409) # In practice, you probably wouldn't want to throw this error, but it is # included for demonstration purposes. Do to flash limitations, an actual # error message can't be returned, so a standard error message is used. # The text can be customized with the uploadRejectedErrorMessageText, and # the uploadRejectedErrorTitleText parameters. else file_path = "public/uploaded_files" File.open(file_path + "/" + file_name, "wb") { |new_file| new_file. write(file_data.read) } render(:xml => "") end end ==== 'removeFileURL' URL that files should be removed with. This URL is sent a 0 referenced array file[], that contains the file names of the files to be removed. Multi Bit Shift Advanced also sends a 0 referenced array id[] that contains the IDs sent in by the fileList XML. The applicationToken is also sent to the url in the parameter application_token. When the upload was successful, Multi Bit Shift Advanced expects the updated fileList XML to be returned. Multi Bit Shift will accept any input that is not an error message, although we recommend taht the xml "" is returned. On error, both versions expect that an xml error message formatted as "ContentTitle" be returned. Both applets will then display a popup error displaying the indicated error message to the client. The applets expect that the file upload process is transactional, in the sense that if a single error occurs on any file removal, it is assumed that all file removals failed. Multi Bit Shift Advanced is capable of silent failure, only removing a subset of files, then returning correct xml that lists only the files that presently exist on the server. Silent failure is discouraged. Defaults to action 'remove_files'. def remove_files @file_path = "public/uploaded_files" if !params['file'].nil? params['file'].each_value{|value| value File.delete(@file_path + "/" + value) } end render :action => "files_on_server" # No error messages are included in this function. The following code can, # however, display messages. # render(:xml => "Bad File RemovalError!") end ==== 'fileListURL' This method is only used by Multi Bit Shift Advanced. See the Query String Parameters below for information about how files are passed into Multi Bit Shift. URL that lists files. This URL is sent the applicationToken in the parameter application_token. The applet expects an xml file of the following format to be returned: File Name human readable file size integer file size in bytes URL of Image image or file any value URL for icon if file_type is image The name field is the name of the file. The size is the human readable file size that is displayed to the user. The bytes field is the size in bytes of the file. The URL is the URL that the image is loaded from, or that the user is sent to when they double click the item in the applet. The file_type should be either the string "image" or "file". If the file_type is "file", an image representation can be loaded with the icon field, which contains the URL of a icon file to use. The id parameter can be any value that the user wants, and is often used to identify the file by its database ID as it is sent to the rename and remove file URLs. Defaults to action 'files_on_server'. xml.instruct! :xml, :version=>"1.0" xml.instruct! :rss, :version=>"2.0" xml.channel { for file in (Dir.entries(@file_path) - [".",".."]) xml.file do xml.name(file) xml.size(number_to_human_size(File.size("#{@file_path}/#{file}"))) xml.bytes(File.size("#{@file_path}/#{file}")) xml.url("http://#{request.host_with_port}/uploaded_files/#{file}") xml.file_type(file_type(File.extname(file)) xml.id(file) if File.extname(file)==".doc" or File.extname(file)==".pdf" xml.icon("http://#{request.host_with_port}#{file_icon(File.extname(file))}") end end end } ==== 'renameFileURL' This method is only used by Multi Bit Shift Advanced. URL that files should be renamed with. The parameters old_file_name and id represent the file to be renamed. The parameter new_file_name contains the name that the file should be renamed to. The applicationToken is also sent to the url in the parameter application_token. When the rename was successful, Multi Bit Shift Advanced expects the updated fileList XML to be returned. On error, an xml error message formatted as "ContentTitle" is expected to be returned. A popup error displaying the indicated error message to the client. Defaults to action 'rename_file'. def rename_file @file_path = "public/uploaded_files" if File.exists?(@file_path + '/' + params['new_file_name']) render(:xml => "Error!Cannot move the file, " + "a file by that name currently exists.") else File.move(@file_path + '/' + params['old_file_name'], @file_path + '/' + params['new_file_name']) render :action => "files_on_server" end end ==== 'rotateCWURL' This method is only used by Multi Bit Shift Advanced. URL that files should be rotated clockwise with. The parameters name and id represent the file to be rotated. The applicationToken is also sent to the url in the parameter application_token. When the rotate was successful, Multi Bit Shift Advanced expects the updated fileList XML to be returned. In addition to setting the rotateCWURL, the rotateCWImageURL should also be set. This defaults to "/flash/cw.gif". On error, an xml error message formatted as "ContentTitle" is expected to be returned. A popup error displaying the indicated error message to the client. Be default, this action is disabled. def rotate_cw rotate(90) end private def rotate(degrees) require 'RMagick' # rmagick must be installed for this to work @file_path = "public/uploaded_files" if !File.exists?(@file_path + '/' + params['name']) render(:xml => "Error!That file doesn't exist.") else image = Magick::Image.read(@file_path + '/' + params['name'])[0] image = image.rotate(degrees) image.write(@file_path + '/' + params['name']){self.quality = 100} render :action => "files_on_server" end end ==== 'rotateCCWURL' This method is only used by Multi Bit Shift Advanced. URL that files should be rotated counter-clockwise with. The parameters name and id represent the file to be rotated. The applicationToken is also sent to the url in the parameter application_token. When the rotate was successful, Multi Bit Shift Advanced expects the updated fileList XML to be returned. In addition to setting the rotateCCWURL, the rotateCWImageURL should also be set. This defaults to "/flash/ccw.gif". On error, an xml error message formatted as "ContentTitle" is expected to be returned. A popup error displaying the indicated error message to the client. Be default, this action is disabled. def rotate_ccw rotate(-90) end private def rotate(degrees) require 'RMagick' # rmagick must be installed for this to work @file_path = "public/uploaded_files" if !File.exists?(@file_path + '/' + params['name']) render(:xml => "Error!That file doesn't exist.") else image = Magick::Image.read(@file_path + '/' + params['name'])[0] image = image.rotate(degrees) image.write(@file_path + '/' + params['name']){self.quality = 100} render :action => "files_on_server" end end === Session Management Multi Bit Shift and Multi Bit Shift Advanced both make use of the same session management functionality. For all requests other than file upload, the current browser session is sent to the server. The uploadURL, however, is not sent the session. As such, we have a method that can request a token from the server. The token is then sent with requests to the uploadURL so that the client can be authenticated. In other words, the tokenRequestURL can authenticate the user with their session, then genate a token. When a file is uploaded, the server can watch for the token that was generated. * 'tokenRequestURL' - URL that the token is requested from. The URL expects a string representing the token to be returned. If this attribute is left blank, no token request is made. === Query String Parameters The applicationToken is a special token that is passed to the applet. It can be used to further identify the user. For instance, using our helpers, the applicationToken is used to identify the model that the files are associated with. Files must be passed into the Multi Bit Shift applet from the query string. The parameters of interest are uploadedFileName#{number} and uploadedFileSize#{number}. The number should start at 1, and go up indefinitely. The uploadedFileName is the file name, and teh uploadedFileSize is the size of the uploaded file in bytes. === Flash Applet Inclusion When including the Multi Bit Shift or Multi Bit Shift Advanced flash applets on pages, we recommend using our multi_bit_shift_flash helper. This helper will automatically insert your query string parameters, and use javascript to write the flash applet to the page. Parameters can be specified as hashes inside the options parameter of the helper. An example call to include the Multi Bit Shift applet follows: multi_bit_shift_flash('uploadedFileName1'=>'smallImage.gif', 'uploadedFileSize1'=>'175','applicationToken'=>'214675-12231-182199') An example call to include the Multi Bit Shift Advanced applet follows: multi_bit_shift_flash({'mbs_version'=>'Advanced', 'flashCSS'=>'/flash/css/siu.swf', 'doneURL'=>url_for(:action=>'index'), 'fileListURL'=>url_for(:action=>'xml_file_listing'), 'fileLabel'=>'All Files', 'fileExtensions' => '*.*', "maximumUploads" => "10", "maximumFileBytes" => "102400", 'mainPanelTitleText' => 'Multi Bit Shift Advanced Demo', 'maximumFileSizeAlert' => ' is larger than 1MB.'}) As you can see in the examples above, any of the query string parameters expected by the applets can be passed to the applet by including it in the options hash, where it is formatted and correctly presented. === Advanced Usage - Usage in Forms ==== Dependencies To use the applets in forms, we have included some helper methods that will make it easier to use. The UUID gem is required to use the plugin. We provide a rake task to ease the installation of the gem. It can be installed by running rake install_uuid from the root of the plugin directory. While it is not required, we highly recommend using the high-quality open source plugin file_column to handle the uploaded files. We provide a rake task for this installation as well, which can be activated with the command rake install_filecolumn from the root of the plugin directory. ==== Model/Migration Generation The plugin requires a secondary table and model to store the actual files that are associated with your primary model. The model and migration can be generated by our script, with the command ruby script/generate multi_bit_shift ClassName [command]. We recommend naming the class MbsFile. Valid commands are [generate_model], [generate_migration], [generate_validation_object], and [all]. We recommend generating all, with the command ruby script/generate multi_bit_shift MbsFile all. In addition to the model and the migration, this also generates the ValidateMbsFile model, which is used to consolidate the number of places that validation settings are entered. The model and migration that are generated are designed to be used with the file_column plugin, and contain a file_name field that will represent the uploaded file, and an associated_with column that will represent the main model that the file is associated with. The associated_with column must be named associated_with. ==== Model Configuration The main model has to be prepared to have files associated with it. This is done by creating a string column that can be named whatever you choose. We generally suggest "files". This column will store a globally unique identifier that will be used to locate files associated with the model. This behaviour is automatic. The file model, suggested to be MbsFile, also needs to be setup to accept file uploads. If file_column is used, all that needs to be done is inserting the line file_column :file_name into the MbsFile model, where 'file_name' is the name of the column that will represent the file. ==== Automatic Validation Validations can be configured in the ValidateMbsFile class. At the top of the file, you will find a series of constant hashes which contain the validation settings. By default, an example hash index called files exists. You can modify the values associated with this index, or create additional index value pairs. The automatic_mbs_validation method should be called from both your main model and the model which represents your files. The call to the method is the same in both classes, and will result in a series of validations being performed before files and the main model are saved. An example call follows: automatic_mbs_validation ValidateMbsFile.new("files") The ValidateMbsFile class can also be used to pass validation information to the applets themselves through the multi_bit_shift_field helper. This will ensure that the validations are performed both server and client side. The validation object can be passed into the helper in the 'validation_object' index of the options hash, as follows: multi_bit_shift_field 'object_name', 'method', {"validation_object" => ValidateMbsFile.new("files")} ==== Multi Bit Shift Field Helper The multi_bit_shift_field helper is desinged to be used in the same manner as any other rails form field helper. The helper will insert a hidden field containing the GUID corresponding to the main object, as well as the appropriate flash applet. It is highly recommended that a validation object be included in the options as it will assist in loading files and setting up client side validation. Example usage for Multi Bit Shift is as follows: multi_bit_shift_field 'object_name', 'method', {"validation_object" => ValidateMbsFile.new("files")} Example usage for Multi Bit Shift Advanced is as follows: multi_bit_shift_field 'object_name', 'method', {"validation_object" => ValidateMbsFile.new("files"), 'mbs_version' == 'Advanced'} ==== Server Side Methods Required When Multi Bit Shift or Multi Bit Shift Advanced are used in forms, they must still implement the methods from the Basic Requirements section above. == Documentation Generation To generate this documentation, use rake from the root of your app: rake doc:plugins Release documentation can be generated by changing to the plugin directory and using the command rake release_docs. This command relies upon the allison gem, which can be installed with the command gem install allison.