Search site

Add to Google Subscribe in NewsGator Online

Featured Articles
Implementation details for FCKEditor integration with Ruby on Rails back
Previous article: WYSIWYG Editor integration to a Rails application view

Fckeditor

The details of the implementation

embedding FCKEditor into a web page

Let's say you have a welcome page on your site and would like your visitors to leave a fancy message, then the first step is create a controller

$ cd myapp
$ script/generate controller welcome
  exists app/controllers/
  exists app/helpers/
  create app/views/welcome
  exists test/functional/
  create app/controllers/welcome_controller.rb
  create test/functional/welcome_controller_test.rb
  create app/helpers/welcome_helper.rb
$

Next, edit app/controllers/welcome_controller.rb

class WelcomeController < ApplicationController
  def index
  end
  def save_comment
    # save the comment posted back from the form
    ...
    redirect_to :action => 'index'
  end
end

Now create the file app/views/welcome/index.rhtml

<html>
<head><title>Welcome to my site</title>
<%= javascript_include_tag "FCKEditor/fckeditor.js" %>
</head>
<body>
<script>
window.onload = function() {
  var oFCKeditor = new FCKeditor('contents');
  oFCKeditor.BasePath = "/javascripts/FCKeditor/";
  oFCKeditor.Config["CustomConfigurationsPath"] =
    '<%= javascript_path "railsfck.js" %>';

  oFCKeditor.ReplaceTextarea();
}
</script>
<%= start_form_tag { :action => 'save_comment' } %>
<p>Please enter a comment:</p>
<textarea name='contents' id='contents'>Hello World</textarea>
<%= end_form_tag %>
</body>
</html>

Note the override in the code above to invoke our overlay Javascript railsfck.js, which is responsible for redirecting the connector calls in FCKEditor to our Rails controller. Let's call it the AttachmentController, which is created with the command

  script/generate controller attachment

similar to the WelcomeController above. The railsfck.js file contains the following lines:

FCKConfig.LinkBrowserURL = FCKConfig.BasePath +
  'filemanager/browser/default/browser.html?Connector=/attachment/command';
FCKConfig.ImageBrowserURL = FCKConfig.BasePath +
  'filemanager/browser/default/browser.html?Type=Image&Connector=/attachment/command';
FCKConfig.LinkUploadURL = '/attachment/upload';
FCKConfig.ImageUploadURL = '/attachment/upload?Type=Image';
FCKConfig.FlashUploadURL = '/attachment/upload?Type=Flash';

The next step is to create the methods in the AttachmentController to handle requests coming back from the editor's connector, namely the command and upload requests. The command request is the redirector for the four FCKEditor connector commands: GetFolders, GetFoldersAndFiles, CreateFolder and FileUpload. The responses to these requests have to be in XML. You can find the formats for these messages here, but essentially the idea is to either send back the contents of the folders (and files) user clicks on, or to send back a error code which corresponds to the success of the operation in the case of CreateFolder and FileUpload. For the case of FileUpload, the response has to be embedded in a piece of Javascript !

require 'fileutils'
class AttachmentController < ApplicationController
  UPLOADED = "/uploaded"
  UPLOADED_ROOT = RAILS_ROOT + "/public" + UPLOADED
  MIME_TYPES = [
    "image/jpeg",
    "image/gif",
    "image/png",
    "application/x-shockwave-flash"
  ]
  def command
    self.send params[:Command]
  end
  
  def GetFolders
    self.GetFoldersAndFiles(false)
  end
  
  def GetFoldersAndFiles(include_files = true)
    @url = UPLOADED + params[:CurrentFolder]
    @folders = Array.new
    @files = {}
    @current_folder = UPLOADED_ROOT + params[:CurrentFolder]
    Dir.entries(@current_folder).each do |entry|
      next if entry =~ /^\./
      path =
@current_folder + entry
      @folders.push entry if FileTest.directory?(path)
      @files[entry] = (File.size(path) / 1024) if (include_files and FileTest.file?(path))
    end
  
  def CreateFolder
    @url = UPLOADED_ROOT + params[:CurrentFolder]
    path = @url + params[:NewFolderName]
    if !(File.stat(@url).writable?)
      @errorNumber = 103
    elsif params[:CurrentFolder] !~ /[\w\d\s]+/
      @errorNumber = 102
    elsif FileTest.exists?(path)
      @errorNumber = 101
    else
      Dir.mkdir(path,0775)
      @errorNumber = 0
    end
  rescue => e
    @errorNumber = 110 if @errorNumber.nil?
  end
&  end
end

Now for the upload piece, which can be done as either part of the File Browser, or by the upload tab itself. The next section of code is part of the same AttachmentController above.

  def FileUpload
  begin
    ftype = params[:NewFile].content_type.strip
    if ! MIME_TYPES.include?(ftype)
      @errorNumber = 202
      raise "#{ftype} is invalid MIME type"
    else
      dir = UPLOADED_ROOT + (params[:CurrentFolder] ? params[:CurrentFolder] : "/")
      path = dir + params[:NewFile].original_filename
      File.open(path,"wb",0664) do |fp|
        FileUtils.copy_stream(params[:NewFile], fp)
      end
      @errorNumber = 0
    end
  rescue => e
    @errorNumber = 110 if @errorNumber.nil?
  end
    render :text => <<-EOL
    <script type="text/javascript">
    window.parent.frames['frmUpload'].OnUploadCompleted(#{@errorNumber});
    </script>
    EOL
  end
  
  def upload
    self.FileUpload
  end
  

The final step is to create the XML template file for the response, which is almost trivial for a Rails application. The file is app/views/attachment/command.rxml, which caters for the responses to all the commands, depending on which variable (@folders, @files or @errorNumber) is set

xml.instruct!
  #=> <?xml version="1.0" encoding="utf-8" ?>
xml.Connector("command" => params[:Command], "resourceType" => 'File') do
  xml.CurrentFolder("url" => @url, "path" => params[:CurrentFolder])
  xml.Folders do
    @folders.each do |folder|
      xml.Folder("name" => folder)
    end
  end if !@folders.nil?
  xml.Files do
    @files.keys.sort.each do |f|
      xml.File("name" => f, "size" => @files[f])
    end
  end if !@files.nil?
  xml.Error("number" => @errorNumber) if !@errorNumber.nil?
end

So, in order to integrate FCKEditor into Rails, with full server side support for upload and browsing, we only needed to write three files (one Javascript, one Controller, and one Viewer file). Note that I have not included

  • error handling code (to handle permissions problems on the server)
  • access control (you might not want everyone to be able to upload to your server)
  • thumbnail generation (to support summary on the front page)
etc. in order not to cloud the issue, but all these steps are very straight forward to do too. If you click on the discuss link here or at the end of this article, you will be taken to the comments page, with an embedded FCKEditor, as a demonstration of the code I have shown so far. I make use of this feature heavily throughout the site, so typically practise what I preach

 

back
Previous article: WYSIWYG Editor integration to a Rails application view

discuss (15 comments)
 by by David at 20 May 2006 22:09:28
David-
Looks interesting. You may want to have a look at the integration I did with FCKeditor and Rails a while, maybe you already did, who knows. It basically allows you to use a tag to place an FCKeditor into any page using a standard rails syntax.
http://www.underpantsgnome.com/projects/fckeditor-on-rails/
Enjoy,
Michael
by Michael at 06 May 2006 05:43:42
Oops, sorry to Michael, Joshua etc. that I did not make it too clear that I did read all your articles, and only cover here what I thought your articles did not cover. I did mention this in the previous article of this thread.

So, this document should really be read together with http://www.joshuamcharles.com/rails/fckeditor.html and http://www.underpantsgnome.com/projects/fckeditor-on-rails/, and the code here should be wrapped into nice Rails helpers if you intend to embed them in multiple places. I just thought I list out the steps here to demonstrate the elegance of the Rails framework.
by David at 06 May 2006 11:58:51
I am attempting to implement this, and everything seems to be working like a charm except for linking images.  When I click into image and select browse, I see all the files I would expect to see.  Then when I select one I get the following in the url path:
./script/../config/../public/uploaded/someimage.jpg

The image tag also has that as its path.  So I did some checking, and my RAILS_ROOT is indeed set to:
./script/../config/..

Being a relative Rails novice, I'm not entirely sure what that should be, but it doesn't seem right.  Any ideas?
by Joe C at 20 May 2006 19:35:08
Hi Joe

This is correct. The path you are showing is the location where the file will be deposited on the web server.  Your document root is the public directory, so in order to access the uploaded image in your rhtml, there are two posibilities:
  1. if your uploaded directory is not under the /public/images directory, you have to access it using normal html i.e. <img src='/uploaded/someimage.jpg' />
  2. if you change your uploaded directory to RAILS_ROOT + "public/images/uploaded", you can use the Rails image tag i.e. <%= image_tag "uploaded/someimage.jpg" %>
by David at 20 May 2006 20:24:23
Hi, and thanks for the quick reply!   I don't think I was clear, with describing my problem, let me give it another go.

I click Insert/edit Image button on the toolbar and that brings up the "Image Properties" window.  I then select "Browse Server" which opens another windor listing the files in that directory.  I'm not uploading anything, these are already there.  So far so good.  Now I click on of those files and it returns me to the the original "image Properties" window with the URL field now filled out.  What is there is literally:
./script/../config/../public/uploaded/someimage.jpg

But this fails because that's not the path to the image.  If I edit this value to read as below It works as expected:
/upload/myimage.jpg

So someplace things are going wrong for me, but I can't determine where.  Things upload correctly, and displaying the contents of the server directory works, but it breaks down when I actually select a file from the upload directory.
by Guest User at 20 May 2006 21:26:05
You are right, my fat finger made a typo with the cut and paste. The first line of code in the method GetFoldersAndFiles should be changed from
     @url = UPLOADED_ROOT + params[:CurrentFolder]
to
    @url = UPLOADED + params[:CurrentFolder]

I have made this correction in the article. Send me an email if you have any problem.
by David at 20 May 2006 22:13:28
David, you are the man!  I thought it was something like that, but I couldn't find the right line. 

This is a really brilliant solution, thanks for sharing it!

Joe
by Joe C at 20 May 2006 23:53:08
Great work. Well explained. Thanks for sharing.
by railsnewbie(somewhereidon'twanttoadmitto) at 04 Jun 2006 05:08:58
Hi David,

Nice work on the editor. I have wrapped this and the some other bits of code I found on using FCK into a plugin for Rails, and I thought you might be interested:

http://blog.caronsoftware.com/articles/2006/08/07/fckeditor-plugin-for-rails

It expands on your code a b it to provide helpers that work in AJAX and straight HTML.

Cheers
Scott.
by Scott Rutherford at 08 Aug 2006 09:48:07
This is fantastic. I knew that it would probably be an easy task to do this, but I never actually sat down to try until now. Thanks for pulling the info and compiling it all David, kudos.
by Rob at 04 Nov 2006 17:03:36
I f***g love you, I just started learning Ruby and Rails, and being a PHP developer, I was just about to start using rails to develop a new app, and I was just about to go back to PHP since I couldn't get FCKeditor to work with rails with upload/browse on the server, Thanks, you've made people happy with this post! Thanks, thanks and thanks again.
by Gabriel Medina at 27 Nov 2006 20:41:41
I'm getting a XML request error: Internal Server Error (500)...
Looked on the web for explanations for people who doing rails apps and can't find
a viable solution....
Did anyone encounter this and have any tips...
I followed the directions provided on this page to a t....so I don't get why
this would be occurring...

Thanks.
by Tony at 24 Jan 2007 22:25:47
First off, thanks for the awesome work!

The file browser will not work for me, but uploading files does. I am getting the following error message:

The server didn't send back a proper XML response. Please contact your system administrator.

XML request error: OK (200)


Requested URL:
/attachment/command?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=%2F

Response text:
<?xml version="1.0" encoding"UTF-8"?>
<Connector command="GetFoldersAndFiles" resourceType="File">
  <CurrentFOlder url="/uploads/" path="/" />
  <Folders>
    <Folder name="images" />
  </Folders>
  <Files>
    <File name="untitled.html" size="0" />
  </Files>
</Connector>

I have done a little modification to the code. The "& end" at the end of CreateFolder and the missing "end" for GetFoldersAndFiles was throwing an error for me. After fixing those, I got this far.
by John at 17 Aug 2007 15:31:46
This may help others. To get it to work for me, I changed attachment_controller.rb (FCKeditor version 2.5 may be the reason):
@myPath = UPLOADED + (params[:CurrentFolder] ? params[:CurrentFolder] : "/") + params[:NewFile].original_filename
...
<script type="text/javascript">
window.parent.OnUploadCompleted(#{@errorNumber}, "#{@myPath}");
</script>
by Kevin at 26 Oct 2007 21:42:04
thx Dave ! you have saved my life ... this is still working perfectly
by RedDragon010 at 10 Dec 2008 09:15:44
Copyrights © Transcraft Trading Limited 2006.All rights reserved. Bots Rss-rss