Rails 5.2 TinyMCE Image Uploads with Amazon S3 - ruby-on-rails

I'm using this tutorial to try to facilitate image uploads using the TinyMCE WYSIWYG editor on my rails 5.2 app.
So far I have implemented all the code in the tutorial and everything works perfectly, but when I try to upload an image I get a "Got a bad response from the server" error message.
In my heroku logs I then get this:
FATAL -- : [527c4468-9ebe-475a-97a9-380bfc327aab] ActionController::RoutingError (uninitialized constant #<Class:0x000055b6d991e020>::EditController
2020-02-22T17:34:07.814727+00:00 app[web.1]: Did you mean? DeviseController):
Here is the route I'm using:
post '/tinymce_assets', to: 'article/edit#image_upload'
With these controller methods:
def image_upload
file = params[:file]
url = upload_file(file)
render json: {
image: {
url: url
}
}, content_type: "text/html"
end
private
def upload_file(file)
s3 = Aws::S3::Resource.new(region:ENV['AWS_REGION'])
obj = s3.bucket(ENV['S3_BUCKET_NAME']).object('articles/images/content/' + filename(file))
obj.upload_file(file.tempfile, {acl: 'public-read'})
obj.public_url.to_s
end
def filename(file)
file.original_filename.gsub(/[^a-zA-Z0-9_\.]/, '_')
end
And this to initialize it:
<%= f.text_area :body, class: "tinymce", rows: 20, cols: 120 %>
<%= tinymce :content_css => asset_path('application.css')%>
...
<script>
$(document).ready(function() {
tinymce.init({
selector: "textarea.tinymce", // change this value according to your HTML
});
});
</script>
Can anyone see where I'm going wrong here?

Rails is trying to find an EditController because of your route: post '/tinymce_assets', to: 'article/edit#image_upload'
This route suggests that the controller it should look in is Article::EditController. Since you are actually looking for the ArticlesController you should change your route to be:
post '/tinymce_assets', to: 'articles#image_upload'
The Rails routing documentation can be helpful, specifically section 2.2 and 2.6. https://guides.rubyonrails.org/routing.html

Related

Attaching AXLSX view to mail Rails Mailer

According to the GitHub Page for the axlsx gem I should use this syntax to render a xlsx view to a file and attach it:
xlsx = render_to_string handlers: [:axlsx], formats: [:xlsx], template: "users/export", locals: {users: users}
attachments["Users.xlsx"] = {mime_type: Mime::XLSX, content: xlsx}
Here is my mail method:
xlsx = render_to_string(handlers: [:axlsx], formats: [:xlsx], template: 'v1/reports/reportxyz', params: {start_date: '2016-09-12', period: 'weekly'})
attachments["report.xlsx"] = {content: xlsx, mime_type: Mime::XLSX}
mail(to: "my#email.address", subject: "Report", format: "text")
However I get this error when I try and call the mailer method:
ActionView::MissingTemplate: Missing template layouts/mailer with {:locale=>[:en], :formats=>[:xlsx], :variants=>[], :handlers=>[:axlsx]}. Searched in:
* "path/to/project/app/views"
Why is the render_to_string method affecting what the mailer view the mailer is trying to render? locgially I don't have a mailer.xlsx.axlsx file in my app/views/layouts folder but rather the mailer.text.erb I am trying to use as with other emails.
EDIT
I changed the render line to xlsx = render_to_string(template: 'v1/reports/azamara_social', params: {start_date: '2016-09-12', period: 'weekly'})
And now it seems to try and render the xlsx view but of course gets nil:NilClass errors when the xlsx view tries to reference instance variables defined in the reports controller.
Have you tried passing layout: false? What versions of axlsx, axlsx_rails, rails, and rubyzip are you using?
In the end it all came down to moving the controller code into a lib file. This way I call it in the controller to get the data if it needs to be rendered via web-requests as well as via the Mailer method where I recreate the #variables the view template is looking for.
Here is the finished salient parts of the report mailer method:
data = ReportUtils.get_data(args)
xlsx = render_to_string(template: 'path/to/report.xlsx', locals: {:#period => period, :#date_ranges => data[:date_ranges], :#data => data[:data]})
attachments["report.xlsx"] = {content: xlsx, mime_type: Mime::XLSX}

html5 video tag not working in firefox for my rails app

For my Rails 4.2 app, my video_tag for HTML5 is working fine for Safari & Chrome, but I get No video with supported format and MIME type found in Firefox.
Here is my view:
<%= video_tag("preroll.webm", "preroll.ogv", "preroll.mp4", controls: true, size: "480x360", poster: "prerollposter.png") %>
Here is my controller show action:
def show
respond_to do |format|
format.any(:html, :m4v, :ogv, :webm) {
}
end
end
Here is my mime_types.rb file:
Mime::Type.register "video/webm", :webm
Mime::Type.register "video/ogg", :ogv
Mime::Type.register "video/mp4", :m4v
In application.html.haml, I have:
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
In my terminal, I've done...
rake assets:precompile
...and I've continually refreshed my firefox browser and cntl-c'ed out of the local server every time.
I'm new at embedding video into a Rails app, so I'm wondering what the Rails equivalent of .htaccess might be (Is it actually mime_types.rb?).
Any help on this would be much appreciated. I think I'd read somewhere previously that the Rails video_tag has some problems, but I'm not sure if that is the cause of Firefox not working here. Thanks so much!

Rails 2.3.14 No Route for .js.erb File

In my layout footer I am including page specific JavaScript files like so:
<%= javascript_include_tag "#{params[:controller]}_#{params[:action]}" if javascript_exists?("#{params[:controller]}_#{params[:action]}") %>
The helper I am using is from another question on this site but modified to work with Rails 2:
application_helper.rb
def javascript_exists?(script)
script = "#{RAILS_ROOT}/public/javascripts/#{script}.js"
extensions = %w(.coffee .erb .coffee.erb) + [""]
extensions.inject(false) do |truth, extension|
truth || File.exists?("#{script}#{extension}")
end
end
Then I also init the included file:
<script>
jQuery(document).ready(function() {
<%= "#{params[:controller].titleize}#{params[:action].titleize}.init();" if javascript_exists?("#{params[:controller]}_#{params[:action]}") %>
});
</script>
This works perfectly fine if my file is named controller_action.js but once renamed to controller_action.js.erb Rails generates an error because it can't find it.
GET http://localhost:3000/javascripts/controller_action.js 404 (Not Found)
Uncaught ReferenceError: ControllerAction is not defined
Update
If I use the .rjs extension then there are no errors generated but this seems to be because Rails doesn't think the file exists. (I updated the javascript_exists? with the .rjs extension.)
After some more debugging, the file is being located:
/path/public/javascripts/circuit_list.js true
but this returns false if .rjs is used.
The routing error when navigating to http://localhost:3000/javascripts/controller_action.js in the browser is:
No route matches "/javascripts/controller_action.js" with {:method=>:get}

uninitialized constant ActionView::CompiledTemplates::FB Ruby on Rails

I am using ruby 1.9.3 Rails 3.2.13 for making an app that can post on facebook wall by using a dialog box (feed dialog)
In my view -
<%
FB.ui(
{
method: 'feed',
name: 'The Facebook SDK for Javascript',
caption: 'Bringing Facebook to the desktop and mobile web',
description: (
'A small JavaScript library that allows you to harness ' +
'the power of Facebook, bringing the user\'s identity, ' +
'social graph and distribution power to your site.'
),
link: 'https://developers.facebook.com/docs/reference/javascript/',
picture: 'http://www.fbrell.com/public/f8.jpg'
},
function(response) {
if (response && response.post_id)
alert('Post was published.')
else
alert('Post was not published.')
end
}
);
%>
IN MY controller
def func
cache_expire = 1.year
response.headers["Pragma"] = "public"
response.headers["Cache-Control"] = "max-age=#{cache_expire.to_i}"
response.headers["Expires"] = (Time.now + cache_expire).strftime("%d %m %Y %H:%I:%S %Z")
render :layout => false, :inline => "<script src='//connect.facebook.net/en_US/all.js'></script>"
redirect_to root_path
end
It is given this error on my view page -
uninitialized constant ActionView::CompiledTemplates::FB
on FB.ui line..
please help I am new with this!
It looks like you're trying to mix Ruby and JavaScript in your view, but you only need JavaScript. Try removing the erb tags <% from your view and wrapping the JS in <script> tags.

Multiple files upload with Rails 3 and paperclip on heroku

I need an interface on my Rails 3 app to upload multiple files to Amazon S3 (because i'm on heroku), possibly with progress bars.
I've easily managed how to set up paperclip and upload single files, but i'm really lost now on how to go ahead.
Please can you give me some advices? It's 2 days i'm searching across all the internet, but i can't find a working solution
** EDIT **
I really can't understand... I'm going mad 'cause I'm losing too many hours on this... please help me.
If I try to open the example app cited by Johnny I only get this (and in my app it is the same):
Where is the UI?
Is there something wrong on my browser?
** EDIT 2 **
Here on GitHub you can find my testapp... please can you explain me why the damn upload UI is not showing up? Thanks!
** EDIT 3 **
Thank you very much Johnny, i wasn't aware of the fact that jquery and prototype can't live together.
Now the plugin is showing up correctly, but as a try to upload something it creates a new "upload" record, but its attachment field is blank, and the files are not on s3.
This is what the console is saying:
Started POST "/uploads" for 127.0.0.1 at 2011-06-27 16:17:22 +0200
Processing by UploadsController#create as JSON
Parameters: {"utf8"=>"✓", "authenticity_token"=>"GesRBTiZR1f2LV/bAeAdxWqF++gxcDJw4pPGStYGsH8=", "upload"=>{"attachment"=>[#<ActionDispatch::Http::UploadedFile:0x000001032834b8 #original_filename="animal-tiger-66550.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"upload[attachment][]\"; filename=\"animal-tiger-66550.jpg\"\r\nContent-Type: image/jpeg\r\n", #tempfile=#<File:/var/folders/Qj/QjEqvUUNGTmuki5SXOaaG++++TI/-Tmp-/RackMultipart20110627-1818-1syiex9>>]}}
AREL (0.5ms) INSERT INTO "uploads" ("attachment", "created_at", "updated_at", "attachment_file_name", "attachment_content_type", "attachment_file_size", "attachment_updated_at") VALUES (NULL, '2011-06-27 14:17:23.049136', '2011-06-27 14:17:23.049136', NULL, NULL, NULL, NULL)
[paperclip] Saving attachments.
Completed 200 OK in 64ms (Views: 4.2ms | ActiveRecord: 0.7ms)
You can look at jQuery-File-Upload. Demo here and rails 3/Paperclip setup here.
Edit: As #apneadiving mentioned, the library has been updated to version 5. The script you have is for verison 4. You should try modifying this to work with PaperClip. Copy-pasting the majority of the example code into my app (with a few modifications) worked for me:
#app/public/javascripts/application.js
$(function () {
// Initialize the jQuery File Upload widget:
$('#fileupload').fileupload();
// Load existing files:
$.getJSON($('#fileupload form').prop('action'), function (files) {
var fu = $('#fileupload').data('fileupload');
fu._adjustMaxNumberOfFiles(-files.length);
fu._renderDownload(files)
.appendTo($('#fileupload .files'))
.fadeIn(function () {
// Fix for IE7 and lower:
$(this).show();
});
});
// Open download dialogs via iframes,
// to prevent aborting current uploads:
$('#fileupload .files a:not([target^=_blank])').live('click', function (e) {
e.preventDefault();
$('<iframe style="display:none;"></iframe>')
.prop('src', this.href)
.appendTo('body');
});
});
#app/controllers/uploads_controller.rb
def create
#upload = Upload.new(params[:upload])
if #upload.save
render :json => [{
:pic_path => #upload.attachment.url.to_s ,
:name => #upload.attachment.instance.attributes["picture_file_name"]
}], :content_type => 'text/html'
else
render [:json => { :result => 'error'}], :content_type => 'text/html'
end
end
#app/views/uploads/new.html.haml
%link#theme{:href => "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/base/jquery-ui.css", :rel => "stylesheet"}
= stylesheet_link_tag 'jquery.fileupload-ui'
#fileupload
= form_for Upload.new, :html => { :multipart => true } do |f|
.fileupload-buttonbar
%label.fileinput-button
%span Add files...
= f.file_field :attachment, :multiple => true
%button.start{:type => "submit"} Start upload
%button.cancel{:type => "reset"} Cancel upload
%button.delete{:type => "button"} Delete files
.fileupload-content
%table.files
.fileupload-progressbar
%script#template-upload{:type => "text/x-jquery-tmpl"}
%tr{:class => "template-upload{{if error}} ui-state-error{{/if}}"}
%td.preview
%td.name ${name}
%td.size ${sizef}
{{if error}}
%td.error{:colspan => "2"}
Error:
{{if error === 'custom_failure'}}Custom Error Message
{{else}}${error}
{{/if}}
{{else}}
%td.progress
%div
%td.start
%button Start
{{/if}}
%td.cancel
%button Cancel
%script#template-download{:type => "text/x-jquery-tmpl"}
%tr{:class => "template-download{{if error}} ui-state-error{{/if}}"}
{{if error}}
%td
%td.name ${name}
%td.size ${sizef}
%td.error{:colspan => "2"}
Error:
{{if error === 1}}File exceeds upload_max_filesize (php.ini directive)
{{else}}${error}
{{/if}}
{{else}}
%td.preview
{{if thumbnail_url}}
%a{:href => "${url}", :target => "_blank"}
%img{:src => "${thumbnail_url}"}/
{{/if}}
%td.name
<a href="${url}"{{if thumbnail_url}} target="_blank"{{/if}}>${name}
%td.size ${sizef}
%td{:colspan => "2"}
{{/if}}
%td.delete
%button{"data-type" => "${delete_type}", "data-url" => "${delete_url}"} Delete
Edit
Had a quick look at your app, the problem is that you are mixing prototype with jquery. The easiest way around this is to switch to jQuery using jquery-rails.
#Gemfile
gem 'jquery-rails'
Next, run bundle install and then rails g jquery:install.
Then change your app/views/layouts/application.erb to this:
<%= stylesheet_link_tag :all %>
<%= csrf_meta_tag %>
<%= javascript_include_tag 'jquery.min' %>
<%= javascript_include_tag 'jquery-ui-1.8.13.custom.min' %>
<%= javascript_include_tag 'jquery.tmpl.min' %>
<%= javascript_include_tag 'jquery.iframe-transport' %>
<%= javascript_include_tag 'jquery.fileupload' %>
<%= javascript_include_tag 'jquery.fileupload-ui' %>
<%= javascript_include_tag 'jquery_ujs' %>
<%= javascript_include_tag 'application' %>
Note that I removed the
<%= javascript_include_tag :defaults %>
So that I can specify the order in which jquery, jquery_ujs, and application are loaded.
I've begun with a very similar task recently, and the swf plugin (at least the more recent one) will indeed let you update paperclip's record. It has callbacks for just about everything you'd need to extend.
:onUploadComplete (upload_options,event)
Here's Nathan Colgate's gist on the matter. He just makes a remote call to the rails server once the upload is finished telling it of the locations for the paperclip attachment.
from his uploadCompleteHandler
var uploadCompleteHandler = function(upload_options,event){
$.ajax({
url: '<%= notify_rails_of_successful_upload_path(:format => :js)%>',
global: false,
type: 'POST',
data: ({
'authenticity_token' : '<%= form_authenticity_token %>',
'upload' : {
'file_file_name' : upload_options.FileName,
'file_file_size' : upload_options.FileSize,
'file_content_type' : upload_options.ContentType
}
}),
dataType: 'script'
}
)
};
I'm not sure if this exact callback gets triggered for each file; it definitely looks like it would. But he passes everything paperclip needs back through an ajax request. filename,size,content-type. This way all that gets sent to heroku is some text about the file, sparing your app a good amount of work by giving it to the client.
edit: flash is the only way I've found to avoid sending a lot of data through heroku to s3. There are a few html5/js-only uploaders that might be able to get the job done, but the ones I have found are still pretty ripe on the dev tree.
As per Heroku support, see this.
Paperclip & multiple files upload, although not S3 specific.
View: (notice the array blog_post[avatars][])
<form accept-charset="UTF-8" action="/blog_posts" enctype="multipart/form-data" id="new_blog_post" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="<%=form_authenticity_token %>" />
</div>
<p><input id="blog_post" name="blog_post[avatars][]" type="file" multiple /></p>
<p><input name="commit" type="submit" value="Upload" /></p>
</form>
Controller:
# POST /blog_posts
# POST /blog_posts.json
def create
#blog_post = BlogPost.new(params[:blog_post])
#blog_post.avatars.each do |avatar|
each_blog_post = BlogPost.new
each_blog_post.avatar = avatar
if each_blog_post.save
end
end
end
Model:
class BlogPost < ActiveRecord::Base
attr_accessible :title, :avatar, :avatars
has_attached_file :avatar
attr_accessor :avatars
end

Resources