Biketire Biketire - 4 months ago 31
Ruby Question

Can't add parameters to the picture model with the use of Ckeditor, Paperclip and Ruby on Rails

I have a CKeditor picture model like this:

class Ckeditor::Picture < Ckeditor::Asset
before_save :set_vars
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 => '600>',:medium => '300x300', :quintet => '150x150', :thumb => '118x100#' }

validates_attachment_size :data, :less_than => 2.megabytes
validates_attachment_presence :data

def url_content
url(:content)
end

protected
def set_vars
#self.assetable_id = id
#self.assetable_type = controller_name
end
end


What I want is that the 'assetable_id' and 'assetable_type' are being filled during the creation of a new picture (because there are columns for those in the database table). And I want to pass them variables. Like the id from the post/event/user that the picture is linked to. And ofcourse the type of 'model' the picture is assigned to - again post/event/user.

I don't know if this is the right solution but I don't know how else to fix it. Documentation online about the CKeditor gem, the config settings and Rails is horrible - I'm searching for hours and hours and I can't find a single thing that closely resembles what I want - so please help.

I know how to adjust the parameters for the upload but none of them seem to do something that I want:

Started POST "/ckeditor/pictures?CKEditor=post%5B14%5D&CKEditorFuncNum=1&
langCode=en&%3Aassetable-id=0&assetable_type=post&
authenticity_token=fsKA68sxkzQpiSMmtcP782i4oI%2FA6KSIsSZuwO5zDWA%3D" for 127.0.0.1 at
2013-04-15 10:05:06 +0200

Processing by Ckeditor::PicturesController#create as HTML

Parameters: {"upload"=>#<ActionDispatch::Http::UploadedFile:0x007f94f80beef8
@original_filename="kb_new.png", @content_type="image/png", @headers="Content-
Disposition: form-data; name=\"upload\"; filename=\"kb_new.png\"\r\nContent-Type:
image/png\r\n", @tempfile=#<File:/tmp/RackMultipart20130415-3130-1ls814r>>,
"CKEditor"=>"post[14]", "CKEditorFuncNum"=>"1", "langCode"=>"en", ":assetable-id"=>"0",
"assetable_type"=>"post",
"authenticity_token"=>"fsKA68sxkzQpiSMmtcP782i4oI/A6KSIsSZuwO5zDWA="}
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
[ALL THE FORMATING STUFF]


SQL (0.6ms) INSERT INTO `ckeditor_assets` (`assetable_id`, `assetable_type`, `created_at`, `data_content_type`, `data_file_name`, `data_file_size`, `height`, `type`, `updated_at`, `width`) VALUES (NULL, '0', '2013-04-15 08:05:07', 'image/png', 'kb_new.png', 291770, 419, 'Ckeditor::Picture', '2013-04-15 08:05:07', 450)

[paperclip] Saving attachments.

(62.5ms) COMMIT

Rendered text template (0.0ms)

Completed 200 OK in 929ms (Views: 0.5ms | ActiveRecord: 63.6ms)


Also check out this question:

How to set the size of an image within CKeditor in Ruby On Rails according to the picture model?

Answer

I actually figured this out and have a solution that works. I too tried googling everything and found literally ZERO information about how to add custom params to a Ckeditor upload within Rails.

Here's what I did:

  1. Let's start with the form itself. With Ckeditor, everything is driven by the URL. So when you click the image icon, and the pop-up window appears, and then you click the BROWSE SERVER button, you'll notice it opens a new pop-up which has a URL. This is the 1st URL you need to modify. Then, when you actually upload an image, it will send a post request to another URL. That's the 2nd URL you need to modify.

By default, these URL's are set to the "index" and "create" actions on the Ckeditor::PicturesController. Here's a link to this controller file in the gem's repo, you will need this later - https://github.com/galetahub/ckeditor/blob/2dd963fae117726976e5bf1dc264e27d3741fea8/app/controllers/ckeditor/pictures_controller.rb

So logically, what we need to do is modify these URL's so that we can add our own custom code to control what happens. So here's what I did to do that (notice the "ckeditor" hash):

<%= cktext_area_tag 'column1_body', @section, 
    :ckeditor => { 
      filebrowserImageUploadUrl: "/ckeditor/pictures?website_id=#{@website.id}",
      filebrowserImageBrowseUrl: "/picture_overrides" 
} %>

cool.

2.So first I modified the filebrowserImageBrowseUrl with '/picture_overrides'. This means that when someone clicks the BROWSE SERVER button, it will call the 'index' action on my PictureOverridesController. So I added the route, created the controller file, and views.

For the views, I copied the view file exactly from the gem, which is here - https://github.com/galetahub/ckeditor/blob/master/app/views/ckeditor/pictures/index.html.erb . Note: there is a partial in there, so you'll need to grab that too.

Now on my new 'PictureOverridesController' file, I edited the 'index' action as follows:

def index
  # I need to find the website
  @website = Website.find_by_subdomain(request.subdomain)
  # I can scope @pictures to only contain the images the user should see.
  @pictures = Ckeditor::Picture.where(website_id: @website.id)
end

Then, some other private methods are called during this process, so you need to add the following code to this controller file as well (just cut & paste). You'll notice I grabbed this code from the same controller on the gem file.

  protected

  def find_asset
    @picture = Ckeditor.picture_adapter.get!(params[:id])
  end

  def authorize_resource
    model = (@picture || Ckeditor.picture_model)
    @authorization_adapter.try(:authorize, params[:action], model)
  end

With this, now my users will only see the images that have the correct website_id.

Now, I need to make sure the website_id is set when a user uploads an image through Ckeditor.

3.While you could certainly modify the create action on this controller file, and set the URL to this, I chose a different way. I simply added the website_id to the URL, as you could see above. Unfortunately, the Ckeditor::Picture instance wont save this automatically. So I decided to accomplish this with an after_filter in the ApplicationController, like so:

    after_filter :ckeditor_add_website_id

    def ckeditor_add_website_id
      if params[:controller] == 'ckeditor/pictures' && params[:action] == 'create'
        @website = find_website_by_domain_subdomain(request)
        @picture.update_attributes(website_id: @website.id)
      end
    end

It just works.

Lastly -- DONT FORGET to add the custom URL's to any form where you are utilizing Ckeditor.