子在川上曰

  逝者如斯夫不舍昼夜
随笔 - 71, 文章 - 0, 评论 - 915, 引用 - 0
数据加载中……

让Rails版的FCKEditor支持动态设置上传目录

一个多用户的系统,上传图像文件等,希望不同用户的图像上传到它专有的目录里。我最初查到在PHP版的FCKEditor是通过设置$Config('UserFilesPath')来实现,但Rails版的FCKEditor没有此项设置(搜索UserFilesPath关键字后做出此判断)。接着,我查看了FCKEditor关键的fckeditor_controller.rb的源代码,似乎它并不支持此项设置。再看javaeye是怎么用FCKEditor的,发现它放弃了FCKEditor的上传功能。google了半天,除了那些转来转去的相同内容的帖子之外(搞不懂有了google之后,怎么还会有人费劲去转帖别人的文章),一点营养也没有。在JavaEye发了个求助帖,没人理 :-( 。 传说中高手云集的JavaEye,其Rails版块真是冷清,给人阴飕飕的感觉。没办法,自己改源代码吧。
文/陈刚 www.chengang.com.cn 转载请保留出处
1.修改fckeditor_controller.rb,把它那几个private方法修改如下:
  
  
private
  def current_directory_path
    base_dir 
= "#{RAILS_ROOT}/public"

    #TODO 在创建用户时,就建立好目录。这时可以去掉这部份代码,提高运行效率。
    (
"#{params[:uploaded]||UPLOADED}/#{params[:Type]}").split('/').each do |s|
    next 
if s==''
        base_dir 
+= '/' + s
        Dir.mkdir(base_dir,
0775) unless File.exists?(base_dir)
    end
    
    check_path(
"#{base_dir}#{params[:CurrentFolder]}")
  end
  
  def upload_directory_path
    uploaded 
= @request.relative_url_root.to_s+"#{params[:uploaded]||UPLOADED}/#{params[:Type]}"
    
"#{uploaded}#{params[:CurrentFolder]}"
  end
  
  def check_file(file)
    # check that the file is a tempfile object
    unless 
"#{file.class}" == "Tempfile" || "#{file.class}" == "StringIO"
      @errorNumber 
= 403
      
throw Exception.new
    end
    file
  end
  
  def check_path(path)
    exp_path 
= File.expand_path path
    
if exp_path !~ %r[^#{File.expand_path(RAILS_ROOT)}/public#{params[:uploaded]||UPLOADED}]
      @errorNumber 
= 403
      
throw Exception.new
    end
    path
  end

另外,它前面的常量UPLOADED_ROOT也没用了,可以删掉。


2. 在上面的代码中params[:uploaded]是关键,它就是我们动态定义的上传目录。该值来自于FCKEditor的一些html页面,它是通过get参数传入的。修改browser.html文件(如下粗体部份),在它的url请求中把我们定义目录加入到get参数列中,这样它就可以传到fckeditor_controller.rb里了


var sServerPath 
= GetUrlParam( 'ServerPath' ) ;
if ( sServerPath.length > 0 )
    oConnector.ConnectorUrl 
+= 'ServerPath=' + escape( sServerPath ) + '&' ;

var sUploaded 
= GetUrlParam( 'uploaded' ) ;
if ( sUploaded.length > 0 )
    oConnector.ConnectorUrl 
+= 'uploaded=' + escape( sUploaded ) + '&'
 ;

oConnector.ResourceType        
= GetUrlParam( 'Type' ) ;
oConnector.ShowAllTypes        
= ( oConnector.ResourceType.length == 0 ) ;


3.  上面
的GetUrlParam( 'uploaded' ) 的值来自于fckcustom.js。修改fckcustom.js(如下粗体部份),把uploaded加入到get参数列中。

// CHANGE FOR APPS HOSTED IN SUBDIRECTORY
FCKRelativePath 
= '';

// DON'T CHANGE THESE
FCKConfig.LinkBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Connector='+FCKRelativePath+'/fckeditor/command';
FCKConfig.ImageBrowserURL 
= FCKConfig.BasePath + 'filemanager/browser/default/browser.html?uploaded='+FCKConfig.uploaded+'&Type=Image&Connector='+FCKRelativePath+'/fckeditor/command';
FCKConfig.FlashBrowserURL 
= FCKConfig.BasePath + 'filemanager/browser/default/browser.html?uploaded='+FCKConfig.uploaded+'&Type=Flash&Connector='+FCKRelativePath+'/fckeditor/command';

FCKConfig.LinkUploadURL 
= FCKRelativePath+'/fckeditor/upload';
FCKConfig.ImageUploadURL 
= FCKRelativePath+'/fckeditor/upload?Type=Image&uploaded='+FCKConfig.uploaded;
FCKConfig.FlashUploadURL 
= FCKRelativePath+'/fckeditor/upload?Type=Flash&uploaded='+FCKConfig.uploaded;
FCKConfig.AllowQueryStringDebug 
= false;
FCKConfig.SpellChecker 
= 'SpellerPages';

// ONLY CHANGE BELOW HERE
FCKConfig.SkinPath 
= FCKConfig.BasePath + 'skins/silver/';
FCKConfig.AutoDetectLanguage 
= false ;
FCKConfig.DefaultLanguage 
= 'zh-cn' ;
FCKConfig.FontNames 
= '微软雅黑;宋体;黑体;隶书;楷体_GB2312;Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;

FCKConfig.ToolbarSets[
"Simple"= [
    [
'Source','-','FitWindow','Preview','-','Templates'],
    [
'PasteText','PasteWord'],
    [
'Undo','Redo','Find','Replace'],
    
'/',
    [
'RemoveFormat','Bold','Italic','Underline','StrikeThrough'],
    [
'OrderedList','UnorderedList','Outdent','Indent'],
    [
'JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
        [
'TextColor','BGColor'],
    [
'Link','Unlink','Anchor'],
    [
'Image','Flash','Table','Rule','Smiley'],
    
'/',
    [
'Style','FontFormat','FontName','FontSize']
] ;

4. 上面FCKConfig.uploaded的值来自于fckeditor.rb。在fckeditor.rb中加入一句(如下粗体所示)。
      javascript_tag( "var oFCKeditor = new FCKeditor('#{id}', '#{width}', '#{height}', '#{toolbarSet}');\n"+
                      
"oFCKeditor.BasePath = \"#{base_path}\"\n"+
                      "oFCKeditor.Config['CustomConfigurationsPath'] = '../../fckcustom.js';\n"+
                      
"oFCKeditor.Config['uploaded'] = '#{options[:path]}';\n"+
                      
"oFCKeditor.ReplaceTextarea();\n")                         

5.不过上面oFCKeditor.Config['uploaded']的值要传到fckcustom.js的FCKConfig.uploaded里,还需要修改fckeditorcode_gecko.js和fckeditorcode_ie.js(这两个文件对javascript进行了压缩处理,修改起来较难操作)。我是参考了oFCKeditor.Config['CustomConfigurationsPath'] 这个参数的载入实现,才找到这种鸟不生蛋的地方。搜索这两个文件的关键字CustomConfigurationsPath,找到如下一行,然后加入一个else if判断(如下粗体所示)。
if (D=='CustomConfigurationsPath') FCKConfig[D]=E;else if (D=='uploaded') FCKConfig[D]=E;else if (E.toLowerCase()=="true"this.PageConfig[D]=true;


6.最后在fckeditor.rb里的#{options[:path]}来自于我们前台的view了。如下粗体所示,把标准的fckeditor_textarea新增加了一个参数,其中params[:user_id]是把用户的ID值做为目录名。这样就实现了动态改变FCKEditor的上传目录。

<%=fckeditor_textarea(:topic, :content, :ajax => true, :toolbarSet => 'Simple', :height => '400px',  :path => "/uploads/#{params[:user_id]}"%>


修改完后需要重启WEB服务,最后别忘记把public/javascripts/fckeditor和vendor/plugins/fckeditor/public/javascripts同步一下,原因见http://www.blogjava.net/chengang/archive/2007/09/24/147867.html

posted on 2007-09-26 10:13 陈刚 阅读(4268) 评论(5)  编辑  收藏 所属分类: Rails&Ruby

评论

# re: 让Rails版的FCKEditor支持动态设置上传目录  回复  更多评论   

不可夺得得好文章.很不错,试验一下....
2007-09-26 14:32 | weskycn

# re: 让Rails版的FCKEditor支持动态设置上传目录  回复  更多评论   

用户是不是可以无限制的上传文件?
2007-09-27 09:07 | 路人甲

# re: 让Rails版的FCKEditor支持动态设置上传目录  回复  更多评论   

@路人甲
好象没发现FCKEditor有文件大小限制
2007-09-28 08:26 | 陈刚

# re: 让Rails版的FCKEditor支持动态设置上传目录  回复  更多评论   

不知道现在还行不行了。按照这个方法不行了。
2008-05-23 00:57 | chiuras

# re: 让Rails版的FCKEditor支持动态设置上传目录  回复  更多评论   

是我失误了,可以用,非常感谢。
2008-05-23 01:06 | chiuras

只有注册用户登录后才能发表评论。


网站导航: