Tiếp theo trong loạt bài viết về Ruby On Rails, hôm nay chúng ta sẽ tìm hiểu cách tích hợp bộ soạn thảo TinyMCE phiên bản 4.x cùng với trình quản lý tệp tin elFinder phiên bản 2.x vào Rails 5.
Bộ soạn thảo TinyMCE
Trong một dự án, nếu bạn muốn quản lý nội dung và mô tả của một sản phẩm hoặc bài viết một cách hiệu quả, bạn cần một bộ soạn thảo để tạo nội dung dễ đọc và trực quan cho người đọc. TinyMCE là một ví dụ về một bộ soạn thảo nội dung WYSIWYG (What You See Is What You Get) mạnh mẽ và đáng tin cậy để giúp bạn thực hiện công việc này.
Trình quản lý file elFinder
elFinder là một ứng dụng quản lý tệp và thư mục cực kỳ mạnh mẽ, với nhiều tính năng ấn tượng như tải lên tệp, cắt tệp, và giải nén tệp. Một trong những điểm đặc biệt của elFinder là khả năng tích hợp nó vào bộ soạn thảo TinyMCE. Điều này đặc biệt hữu ích vì việc sử dụng trình quản lý tệp đi kèm với TinyMCE thường đòi hỏi phải trả phí. Vì vậy, sử dụng elFinder là một giải pháp hoàn toàn miễn phí để tích hợp một trình quản lý tệp mạnh mẽ vào ứng dụng của bạn.
Tích hợp TinyMCE và elFinder trong Rails 5
1. Cài đặt TinyMCE Editor và elFilder
– Sửa file Gemfile trong project của Rails 5, thêm dòng sau:
gem 'tinymce-rails' gem 'el_finder', '1.1.12'
Chạy command bundle để Rails cài đặt 2 gem này. Kết quả sau khi cài đặt:
– Download elFinder ở đây: https://studio-42.github.io/elFinder/
Sau đó giải nén, và copy vào thư mục public/ của project
2. Tích hợp TinyMCE vào Rails 5
– Tạo một controller mới có tên là Media, chạy command sau:
rails g controller Media index
– Sửa file config/routes.rb
# Media route get '/admin/media' => 'media#index', as: :media_management match 'elfinder' => 'media#elfinder', via: [:get, :post]
– Update nội dung cho file app/controllers/media_controller.rb
class MediaController < ApplicationController skip_before_action :verify_authenticity_token, :only => ['elfinder'] def index render :layout => false end def elfinder rootpath = File.join(Rails.public_path, 'uploads') rooturl = '/uploads' h, r = ElFinder::Connector.new( :root => rootpath, :url => rooturl, :perms => { /^(Welcome|README)$/ => {:read => true, :write => false, :rm => false}, '.' => {:read => true, :write => true, :rm => true}, # '.' is the proper way to specify the home/root directory. }, :extractors => { 'application/zip' => ['unzip', '-qq', '-o'], # Each argument will be shellescaped (also true for archivers) 'application/x-gzip' => ['tar', '-xzf'], }, :archivers => { 'application/zip' => ['.zip', 'zip', '-qr9'], # Note first argument is archive extension 'application/x-gzip' => ['.tgz', 'tar', '-czf'], }, :thumbs => true ).run(params) headers.merge!(h) if r.empty? (render :nothing => true) and return end render :json => r, :layout => false end end
Ởfunction elfinder của controller Class MediaController, để trả về dữ liệu cho elFinder.
- Thư mục quản lý file sẽ đặt ở thư mục public/uploads của project
- Gem ‘el_finder’ để xứ lý backend cho phần quản lý file. (https://github.com/phallstrom/el_finder)
– Sửa file app/views/media/index.html.rb
<!DOCTYPE html> <html> <head> <title>File Manager</title> <link rel="stylesheet" type="text/css" media="screen" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/smoothness/jquery-ui.css"> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script> <script type="text/javascript" src="/elfinder/js/elfinder.min.js"></script> <script src="/elfinder/js/proxy/elFinderSupportVer1.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript" src="/elfinder/js/i18n/elfinder.de.js"></script><!-- optional --> <link rel="stylesheet" type="text/css" media="screen" href="/elfinder/css/elfinder.min.css"> <link rel="stylesheet" type="text/css" media="screen" href="/elfinder/css/theme.css"> </head> <body> <div id="elfinder"></div> <script type="text/javascript"> var FileBrowserDialogue = { init: function() { // Here goes your code for setting your custom things onLoad. }, mySubmit: function (URL) { // pass selected file path to TinyMCE parent.tinymce.activeEditor.windowManager.getParams().setUrl(URL); // close popup window parent.tinymce.activeEditor.windowManager.close(); } } $().ready(function() { var elf = $('#elfinder').elfinder({ // set your elFinder options here url: '/elfinder', // connector URL transport : new elFinderSupportVer1(), getFileCallback: function(file) { // editor callback // file.url - commandsOptions.getfile.onlyURL = false (default) // file - commandsOptions.getfile.onlyURL = true FileBrowserDialogue.mySubmit(file); // pass selected file path to TinyMCE } }).elfinder('instance'); }); </script> </body> </html>
– Sửa file app/assets/application.js với nội dung như sau:
//= require jquery-3.3.1.slim.min //= require rails-ujs //= require tinymce //= require activestorage //= require turbolinks //= require_tree . $(document).ready(function(){ tinymce.init({ selector: "textarea.tinymce", plugins: [ "advlist autolink lists link image charmap print preview anchor", "searchreplace visualblocks code fullscreen", "insertdatetime media table contextmenu paste" ], toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image", file_browser_callback : elFinderBrowser }); function elFinderBrowser (field_name, url, type, win) { tinymce.activeEditor.windowManager.open({ file: '/admin/media', // use an absolute path! title: 'elFinder 2.0', width: 900, height: 450, resizable: 'yes' }, { setUrl: function (obj) { win.document.getElementById(field_name).value = obj.url; } }); return false; } })
– Cuối cùng là đặt TinyMCE ở vị trí thích hợp trong project
<%= f.text_area :post_content, id: 'form-post_content' , class: 'form-control tinymce', rows: 5 %>
Kết quả sau khi tích hợp thành công: