From 6cfe947f7e5c124a4bb575e56d6d32c401ab227f Mon Sep 17 00:00:00 2001 From: Igor Galeta Date: Fri, 8 Jul 2011 17:10:48 +0300 Subject: [PATCH] Controller helpers --- .gitignore | 2 + Gemfile | 1 + Gemfile.lock | 6 +++ README.rdoc | 26 ++++++++++++ .../ckeditor/attachment_files_controller.rb | 2 +- app/controllers/ckeditor/base_controller.rb | 4 +- .../ckeditor/pictures_controller.rb | 2 +- lib/ckeditor.rb | 1 + lib/ckeditor/engine.rb | 6 ++- lib/ckeditor/helpers/controllers.rb | 30 ++++++++++++++ .../models/active_record/attachment_file.rb | 1 + .../templates/models/active_record/picture.rb | 1 + test/controllers/pictures_controller_test.rb | 38 ++++++++++++++++++ test/dummy/app/models/ckeditor/asset.rb | 7 ++++ .../app/models/ckeditor/attachment_file.rb | 15 +++++++ test/dummy/app/models/ckeditor/picture.rb | 13 ++++++ test/dummy/config/application.rb | 3 +- test/dummy/config/initializers/ckeditor.rb | 18 +++++++++ .../20110705195648_create_ckeditor_assets.rb | 26 ++++++++++++ test/dummy/db/schema.rb | 16 +++++++- test/dummy/test/fixtures/files/rails.png | Bin 0 -> 6646 bytes 21 files changed, 212 insertions(+), 6 deletions(-) create mode 100644 lib/ckeditor/helpers/controllers.rb create mode 100644 test/controllers/pictures_controller_test.rb create mode 100644 test/dummy/app/models/ckeditor/asset.rb create mode 100644 test/dummy/app/models/ckeditor/attachment_file.rb create mode 100644 test/dummy/app/models/ckeditor/picture.rb create mode 100644 test/dummy/config/initializers/ckeditor.rb create mode 100644 test/dummy/db/migrate/20110705195648_create_ckeditor_assets.rb create mode 100644 test/dummy/test/fixtures/files/rails.png diff --git a/.gitignore b/.gitignore index 6c81ff6dd..7ad054897 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ log/*.log pkg/ test/dummy/db/*.sqlite3 +test/dummy/db/schema.rb test/dummy/log/*.log +test/dummy/public/ckeditor_assets/ test/dummy/tmp/ test/tmp diff --git a/Gemfile b/Gemfile index 65928fcd4..751fb004e 100644 --- a/Gemfile +++ b/Gemfile @@ -10,6 +10,7 @@ platforms :ruby do group :development, :test do gem "capybara", ">= 0.4.0" gem "redgreen", "~> 1.2.2" + gem "paperclip", "~> 2.3.12" # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+) # gem 'ruby-debug' diff --git a/Gemfile.lock b/Gemfile.lock index 0a783187d..4d69d67ca 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -47,6 +47,7 @@ GEM cgi_multipart_eof_fix (2.5.0) childprocess (0.1.9) ffi (~> 1.0.6) + cocaine (0.1.0) daemons (1.1.4) erubis (2.6.6) abstract (>= 1.0.0) @@ -69,6 +70,10 @@ GEM mysql2 (0.2.11) nokogiri (1.4.6) orm_adapter (0.0.5) + paperclip (2.3.12) + activerecord (>= 2.3.0) + activesupport (>= 2.3.2) + cocaine (>= 0.0.2) polyglot (0.3.1) rack (1.2.3) rack-mount (0.6.14) @@ -113,5 +118,6 @@ DEPENDENCIES ckeditor! mongrel mysql2 (= 0.2.11) + paperclip (~> 2.3.12) rails (= 3.0.9) redgreen (~> 1.2.2) diff --git a/README.rdoc b/README.rdoc index 33e3848af..d9891d3e6 100644 --- a/README.rdoc +++ b/README.rdoc @@ -88,6 +88,32 @@ Jquery sample: <%= form.ckeditor :content, :label => false, :input_html => { :toolbar => 'Full' } %> +=== Default scope + +For example, you need split assets collection for each user. + + class ApplicationController < ActionController::Base + + protected + + def ckeditor_filebrowser_scope(options = {}) + super { :assetable_id => current_user.id, :assetable_type => 'User' }.merge(options) + end + end + +=== Before create asset callback + + class ApplicationController < ActionController::Base + + protected + + def ckeditor_before_create_asset(asset) + asset.assetable = current_user if respond_to?(:current_user) + return can?(:create, asset) + end + end + + == I18n en: diff --git a/app/controllers/ckeditor/attachment_files_controller.rb b/app/controllers/ckeditor/attachment_files_controller.rb index 9f2ff0703..e91160471 100644 --- a/app/controllers/ckeditor/attachment_files_controller.rb +++ b/app/controllers/ckeditor/attachment_files_controller.rb @@ -1,7 +1,7 @@ class Ckeditor::AttachmentFilesController < Ckeditor::BaseController def index - @attachments = Ckeditor.attachment_file_model.find_all(:order => [:id, :desc]) + @attachments = Ckeditor.attachment_file_model.find_all(ckeditor_attachment_files_scope) respond_with(@attachments) end diff --git a/app/controllers/ckeditor/base_controller.rb b/app/controllers/ckeditor/base_controller.rb index c35948ad7..dcce168eb 100644 --- a/app/controllers/ckeditor/base_controller.rb +++ b/app/controllers/ckeditor/base_controller.rb @@ -17,7 +17,9 @@ def respond_with_asset(asset) file = params[:CKEditor].blank? ? params[:qqfile] : params[:upload] asset.data = Ckeditor::Http.normalize_param(file, request) - if asset.save + callback = ckeditor_before_create_asset(asset) + + if callback && asset.save body = params[:CKEditor].blank? ? asset.to_json(:only=>[:id, :type]) : %Q"" diff --git a/app/controllers/ckeditor/pictures_controller.rb b/app/controllers/ckeditor/pictures_controller.rb index 079bfb274..1e6e45d23 100644 --- a/app/controllers/ckeditor/pictures_controller.rb +++ b/app/controllers/ckeditor/pictures_controller.rb @@ -1,7 +1,7 @@ class Ckeditor::PicturesController < Ckeditor::BaseController def index - @pictures = Ckeditor.picture_model.find_all(:order => [:id, :desc]) + @pictures = Ckeditor.picture_model.find_all(ckeditor_pictures_scope) respond_with(@pictures) end diff --git a/lib/ckeditor.rb b/lib/ckeditor.rb index f7b22c237..6575541f0 100644 --- a/lib/ckeditor.rb +++ b/lib/ckeditor.rb @@ -10,6 +10,7 @@ module Helpers autoload :ViewHelper, 'ckeditor/helpers/view_helper' autoload :FormHelper, 'ckeditor/helpers/form_helper' autoload :FormBuilder, 'ckeditor/helpers/form_builder' + autoload :Controllers, 'ckeditor/helpers/controllers' end module Hooks diff --git a/lib/ckeditor/engine.rb b/lib/ckeditor/engine.rb index 61b08ab69..0890206cd 100644 --- a/lib/ckeditor/engine.rb +++ b/lib/ckeditor/engine.rb @@ -4,7 +4,11 @@ module Ckeditor class Engine < ::Rails::Engine config.action_view.javascript_expansions[:ckeditor] = "ckeditor/ckeditor" - initializer "ckeditor.view_helpers" do + initializer "ckeditor.helpers" do + ActiveSupport.on_load(:action_controller) do + ActionController::Base.send :include, Ckeditor::Helpers::Controllers + end + ActiveSupport.on_load :action_view do ActionView::Base.send :include, Ckeditor::Helpers::ViewHelper ActionView::Base.send :include, Ckeditor::Helpers::FormHelper diff --git a/lib/ckeditor/helpers/controllers.rb b/lib/ckeditor/helpers/controllers.rb new file mode 100644 index 000000000..23f2400d1 --- /dev/null +++ b/lib/ckeditor/helpers/controllers.rb @@ -0,0 +1,30 @@ +module Ckeditor + module Helpers + module Controllers + extend ActiveSupport::Concern + + protected + + def ckeditor_before_create_asset(asset) + asset.assetable = current_user if respond_to?(:current_user) + return true + end + + def ckeditor_authenticate(asset) + # TODO: + end + + def ckeditor_pictures_scope(options = {}) + ckeditor_filebrowser_scope(options) + end + + def ckeditor_attachment_files_scope(options = {}) + ckeditor_filebrowser_scope(options) + end + + def ckeditor_filebrowser_scope(options = {}) + { :order => [:id, :desc] }.merge(options) + end + end + end +end diff --git a/lib/generators/ckeditor/templates/models/active_record/attachment_file.rb b/lib/generators/ckeditor/templates/models/active_record/attachment_file.rb index ef3e2f5ae..d76dbcd95 100644 --- a/lib/generators/ckeditor/templates/models/active_record/attachment_file.rb +++ b/lib/generators/ckeditor/templates/models/active_record/attachment_file.rb @@ -4,6 +4,7 @@ class Ckeditor::AttachmentFile < Ckeditor::Asset :path => ":rails_root/public/ckeditor_assets/attachments/:id/:filename" validates_attachment_size :data, :less_than => 100.megabytes + validates_attachment_presence :data def url_thumb @url_thumb ||= begin diff --git a/lib/generators/ckeditor/templates/models/active_record/picture.rb b/lib/generators/ckeditor/templates/models/active_record/picture.rb index db365adab..4192217ce 100644 --- a/lib/generators/ckeditor/templates/models/active_record/picture.rb +++ b/lib/generators/ckeditor/templates/models/active_record/picture.rb @@ -5,6 +5,7 @@ class Ckeditor::Picture < Ckeditor::Asset :styles => { :content => '800>', :thumb => '118x100#' } validates_attachment_size :data, :less_than => 2.megabytes + validates_attachment_presence :data def url_content url(:content) diff --git a/test/controllers/pictures_controller_test.rb b/test/controllers/pictures_controller_test.rb new file mode 100644 index 000000000..8bbc2b0b1 --- /dev/null +++ b/test/controllers/pictures_controller_test.rb @@ -0,0 +1,38 @@ +require 'test_helper' + +class PicturesControllerTest < ActionController::TestCase + tests Ckeditor::PicturesController + + def setup + @image = fixture_file_upload('files/rails.png', 'image/png') + end + + test "index action" do + get :index + + assert_equal 200, @response.status + assert_template "ckeditor/pictures/index" + end + + test "create action via filebrowser" do + assert_difference 'Ckeditor::Picture.count' do + post :create, :qqfile => @image + end + + assert_equal 200, @response.status + end + + test "create action via CKEditor upload form" do + assert_difference 'Ckeditor::Picture.count' do + post :create, :upload => @image, :CKEditor => 'ckeditor_field' + end + + assert_equal 200, @response.status + end + + test "invalid params for create action" do + assert_no_difference 'Ckeditor::Picture.count' do + post :create, :qqfile => nil + end + end +end diff --git a/test/dummy/app/models/ckeditor/asset.rb b/test/dummy/app/models/ckeditor/asset.rb new file mode 100644 index 000000000..9c33c05a0 --- /dev/null +++ b/test/dummy/app/models/ckeditor/asset.rb @@ -0,0 +1,7 @@ +require 'mime/types' + +class Ckeditor::Asset < ActiveRecord::Base + include Ckeditor::Orm::ActiveRecord::AssetBase + + attr_accessible :data, :assetable_type, :assetable_id, :assetable +end diff --git a/test/dummy/app/models/ckeditor/attachment_file.rb b/test/dummy/app/models/ckeditor/attachment_file.rb new file mode 100644 index 000000000..d76dbcd95 --- /dev/null +++ b/test/dummy/app/models/ckeditor/attachment_file.rb @@ -0,0 +1,15 @@ +class Ckeditor::AttachmentFile < Ckeditor::Asset + has_attached_file :data, + :url => "/ckeditor_assets/attachments/:id/:filename", + :path => ":rails_root/public/ckeditor_assets/attachments/:id/:filename" + + validates_attachment_size :data, :less_than => 100.megabytes + validates_attachment_presence :data + + def url_thumb + @url_thumb ||= begin + extname = File.extname(filename).gsub(/^\./, '') + "/javascripts/ckeditor/filebrowser/images/thumbs/#{extname}.gif" + end + end +end diff --git a/test/dummy/app/models/ckeditor/picture.rb b/test/dummy/app/models/ckeditor/picture.rb new file mode 100644 index 000000000..4192217ce --- /dev/null +++ b/test/dummy/app/models/ckeditor/picture.rb @@ -0,0 +1,13 @@ +class Ckeditor::Picture < Ckeditor::Asset + has_attached_file :data, + :url => "/ckeditor_assets/pictures/:id/:style_:basename.:extension", + :path => ":rails_root/public/ckeditor_assets/pictures/:id/:style_:basename.:extension", + :styles => { :content => '800>', :thumb => '118x100#' } + + validates_attachment_size :data, :less_than => 2.megabytes + validates_attachment_presence :data + + def url_content + url(:content) + end +end diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index e8a687b27..7100761ac 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -8,6 +8,7 @@ Bundler.require require "ckeditor" +require "paperclip" module Dummy class Application < Rails::Application @@ -16,7 +17,7 @@ class Application < Rails::Application # -- all .rb files in that directory are automatically loaded. # Custom directories with classes and modules you want to be autoloadable. - # config.autoload_paths += %W(#{config.root}/extras) + config.autoload_paths += %W(#{config.root}/app/models/ckeditor) # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. diff --git a/test/dummy/config/initializers/ckeditor.rb b/test/dummy/config/initializers/ckeditor.rb new file mode 100644 index 000000000..808f412c5 --- /dev/null +++ b/test/dummy/config/initializers/ckeditor.rb @@ -0,0 +1,18 @@ +# Use this hook to configure ckeditor +if Object.const_defined?("Ckeditor") + Ckeditor.setup do |config| + # ==> ORM configuration + # Load and configure the ORM. Supports :active_record (default), :mongo_mapper and + # :mongoid (bson_ext recommended) by default. Other ORMs may be + # available as additional gems. + require 'ckeditor/orm/active_record' + + # Allowed image file types for upload. + # Set to nil or [] (empty array) for all file types + # config.image_file_types = ["jpg", "jpeg", "png", "gif", "tiff"] + + # Allowed attachment file types for upload. + # Set to nil or [] (empty array) for all file types + # config.attachment_file_types = ["doc", "docx", "rar", "zip", "xls", "swf"] + end +end diff --git a/test/dummy/db/migrate/20110705195648_create_ckeditor_assets.rb b/test/dummy/db/migrate/20110705195648_create_ckeditor_assets.rb new file mode 100644 index 000000000..9ad4c15a2 --- /dev/null +++ b/test/dummy/db/migrate/20110705195648_create_ckeditor_assets.rb @@ -0,0 +1,26 @@ +class CreateCkeditorAssets < ActiveRecord::Migration + def self.up + create_table :ckeditor_assets do |t| + t.string :data_file_name, :null => false + t.string :data_content_type + t.integer :data_file_size + + t.integer :assetable_id + t.string :assetable_type, :limit => 30 + t.string :type, :limit => 30 + + # Uncomment it to save images dimensions, if your need it +# t.integer :width +# t.integer :height + + t.timestamps + end + + add_index "ckeditor_assets", ["assetable_type", "type", "assetable_id"], :name => "idx_ckeditor_assetable_type" + add_index "ckeditor_assets", ["assetable_type", "assetable_id"], :name => "idx_ckeditor_assetable" + end + + def self.down + drop_table :ckeditor_assets + end +end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 4b098eb53..4a1b88c53 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -10,7 +10,21 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20110623120047) do +ActiveRecord::Schema.define(:version => 20110705195648) do + + create_table "ckeditor_assets", :force => true do |t| + t.string "data_file_name", :null => false + t.string "data_content_type" + t.integer "data_file_size" + t.integer "assetable_id" + t.string "assetable_type", :limit => 30 + t.string "type", :limit => 30 + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "ckeditor_assets", ["assetable_type", "assetable_id"], :name => "idx_ckeditor_assetable" + add_index "ckeditor_assets", ["assetable_type", "type", "assetable_id"], :name => "idx_ckeditor_assetable_type" create_table "posts", :force => true do |t| t.string "title" diff --git a/test/dummy/test/fixtures/files/rails.png b/test/dummy/test/fixtures/files/rails.png new file mode 100644 index 0000000000000000000000000000000000000000..d5edc04e65f555e3ba4dcdaad39dc352e75b575e GIT binary patch literal 6646 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 AQ~&?~ literal 0 HcmV?d00001