Rails 3 Uploadify + Paperclip File Data Is Never Sent - ruby-on-rails-3

I'm using Rails 3.1 with Paperclip and trying to implement Uploadify for multiple file uploads on a single page. I tried following various samples, including: Rails3-Paperclip-Uploadify
Currently I have a Upload model which has a one to many relationship with my UploadImage model - This is what I had setup so far for my view:
UploadImages/new.html.erb
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js" %>
<%= javascript_include_tag "swfobject.js", "jquery.uploadify.v2.1.0.js" %>
<script type="text/javascript" charset="utf-8">
<%- session_key = Rails.application.config.session_options[:key] -%>
$(document).ready(function()
{
// Create an empty object to store our custom script data
var uploadify_script_data = {};
// Fetch the CSRF meta tag data
var csrf_token = $('meta[name=csrf-token]').attr('content');
var csrf_param = $('meta[name=csrf-param]').attr('content');
// Now associate the data in the config, encoding the data safely
uploadify_script_data[csrf_token] = encodeURI(encodeURI(csrf_param));
$('.uploadify').uploadify
({
uploader : '/uploadify/uploadify.swf',
cancelImg : '/uploadify/cancel.png',
multi : true,
auto : false,
onComplete : function(event, queueID, fileObj, response, data)
{
var dat = eval('(' + response + ')');
$.getScript(dat.upload);
},
scriptData : {
'_http_accept': 'application/javascript',
'format' : 'json',
'_method': 'post',
'<%= session_key %>' : encodeURIComponent('<%= u cookies[session_key] %>'),
'authenticity_token': encodeURIComponent('<%= u form_authenticity_token %>'),
'upload_id' : '<%= #upload.id %>'
}
});
});
</script>
<%= form_for #upload.upload_images.build, :html => { :class => "upload", :multipart => true } do |f| %>
<%= f.file_field :image, :class => "uploadify" %>
<%= submit_tag "Submit Upload", :disable_with => "Uploading", :class => "submit"%>
<% end %>
I see the uploadify flash button, I select a few files and submit but this is all I see in my params:
{"utf8"=>"✓",
"authenticity_token"=>"K1bSH/FO0Hjdum0aiNU45mHJXezXTiCgh9XVmk1jrZM=",
"commit"=>"Submit Upload", "action"=>"create",
"controller"=>"upload_images"}
As you can see there is no file data being sent and even the scriptData that I specify doesn't get sent, I noticed that other people's code uses the script parameter for the uploadify function. In PHP frameworks they point it to the .php file which handles the saving. I'm using Paperclip so I wasn't sure how to implement this... perhaps this is my problem? Let me know if you need any additional details.

I found the answer by looking at this question: uploadify rails 3 nothing happens after the file is chosen
I had to attach some events to my submit button and add the script parameter to the uploadify function as I surmised.
So for starters in my config/routes.rb I needed to add:
post "upload_images/create"
And in my view I added:
$('#submit').click(function(event){
event.preventDefault();
});
$('#submit').click(function(event){
event.preventDefault();
$('.uploadify').uploadifyUpload();
});
and finally I added the script param to my initial uploadify function call:
script : '/upload_images/create'
After many hours of beating my head against it's finally working and making sense! Hope this helps somebody else.

Related

How config url in Kaminari pagination? '.json' appended automatically

Load table with Kaminari pagination using AJAX.
The pagination itself is using AJAX as well.
In my controller:
def update_user_list
modal = render_to_string('tables/_user_table', :layout => false, :formats=>[:html]).html_safe
data = {
:table => modal
}
respond_to do |format|
format.json { render :json => data }
end
end
In tables/_user_table
# Table part and content notrelated
<%= paginate #users, :params => {:controller => 'product', :action => 'more_users'}, :remote => true, :theme => 'twitter-bootstrap-3' %>
The response JSON of update_user_list looks like:
{
table=" // the table part
// the pagination part shows as follows
<li class="page">3</li>
<li class="page">4
"
}
What I want is to remove ".json" in the url.
If I just render tables/_user_table without AJAX, not in a JSON object, it doesn't have ".json" in the url.
version:
rails: 3.2.17
kaminari: 0.13.0
bootstrap-kaminari-views: 0.0.3
Find the problem. It's actually not included in the question.
$.ajax({
url: '<%= user_product_index_url %>.json',
success: function(data) {
// not important......
});
remove ".json" here solve the problem...

ajax .keyup search function

I have a search function that uses the .keyup method on a rails application. I know that the call is working because the first letter I type is searching and showing results. If I continue to type it doesn't continue to search the method. Here is my jquery below and the part of my rails view it is calling.
JQuery
$("input#search").keyup(function (){
$.get($("#verified_search").attr("action"), $("#verified_search").serialize(), null, "script");
return false;
});
index.js.erb
$(".results").html("<%= escape_javascript(render("search")) %>");
index.html.erb view
<%= form_tag admin_view_index_path, :method => 'get', :id => 'verified_search' do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => :nil %>
<% end %>
<%= render 'search' %>
Use .live()
$("input#search").live('keyup', function (){
$.get($("#verified_search").attr("action"), $("#verified_search").serialize(), null, "script");
return false;
});
When you replace the content of $('.results') in index.js.erb, any listeners associated with those elements are gone.
http://api.jquery.com/live/
Edit: As it says in the link, the .live() method is deprecated as of jQuery 1.7. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live().
Try this
$(document).on("keyup", "#verified_search", function(){
$.get($("#verified_search").attr("action"), $("#verified_search").serialize(), null, "script");
return false;
});

Trying to implement an Ajax function rails 3 .load()

This is my first time trying to implement an Ajax call in rails 3, though I am using the .load function ( I still hope this is Ajax otherwise im understanding this incorrectly)
So i have a search form that returns results via a get request which renders on a different page, i would like the results to appear on the same page as the search form
<%= form_tag({:controller => 'search', :action => 'search'}, {:method => 'get'}) do |select| %>
<%= label_tag :search, "Enter Keywords Here" %>
<%= text_field_tag :search, params[:search] %>
(I have shortened the form)
<%= submit_tag "Search", :class => "searchbutton" %>
<% end %>
Jquery/Ajax call
$(document).ready(function() {
$('.searchbutton').click(function() {
$('#searchres').load('shared/searchresults');
});
});
View
<h3>Search Recipes here</h3>
<%= render 'shared/searchrecipes' %>
<div id ="searchres">
</div>
What am i doing wrong?
Due to this being an AJAX call, you need to add remote: true besides method: :get, getting an html parameter hash like this:
{:method => 'get', :remote => true}
When Rails finda remote call, it prevents the default automagically. Otherwise, you would need to modify you javascript like this:
$(document).ready(function() {
$('.searchbutton').click(function(evt) {
$('#searchres').load('shared/searchresults');
evt.preventDefault();
});
});

Allowing User to Download File from S3 Storage

Right now I am using Amazon S3 and Paperclip which is allowing my users to upload an image that is associated with the event they are creating. My ultimate goal is since others can view this event, to be able to click on the image and have it prompt a SAVE TO their computer. As of now, clicking the link will open the image in a browser window. I rather have it ask for them to download instead. All images only saved on S3, not local. Need to hide exposed s3 url as well if possible or camouflage it
Here is my current setup
Index.html
<%= link_to 'Download Creative', event.creative.url, class: "btn btn-info" %>
Event.rb
has_attached_file :creative,
:styles => { :thumb => "150x150", :custcreative => "250x75" },
:path => ":attachment/:id/:style.:extension",
:s3_domain_url => "******.s3.amazonaws.com",
:storage => :s3,
:s3_credentials => Rails.root.join("config/s3.yml"),
:bucket => '*****',
:s3_permissions => :public_read,
:s3_protocol => "http",
:convert_options => { :all => "-auto-orient" },
:encode => 'utf8'
Hoping someone can help me out.
To avoid extra load to your app (saving dyno's time in Heroku), I would rather do something like this: add this method to your model with the attachment:
def download_url(style_name=:original)
creative.s3_bucket.objects[creative.s3_object(style_name).key].url_for(:read,
:secure => true,
     :expires => 24*3600,  # 24 hours
     :response_content_disposition => "attachment; filename='#{creative_file_name}'").to_s
end
And then use it in your views/controllers like this:
<%= link_to 'Download Creative', event.download_url, class: "btn btn-info" %>
To make this work, I've just added a new action in the controller, so in your case it could be:
#routes
resources :events do
member { get :download }
end
#index
<%= link_to 'Download Creative', download_event_path(event), class: "btn btn-info" %>
#events_controller
def download
data = open(event.creative_url)
send_data data.read, :type => data.content_type, :x_sendfile => true
end
EDIT:
the correct solution for download controller action can be found here (I've updated the code above): Force a link to download an MP3 rather than play it?
Now in aws-sdk v2, there is a method :presigned_url defined in Aws::S3::Object, you can use this method to construct the direct download url for a s3 object:
s3 = Aws::S3::Resource.new
# YOUR-OBJECT-KEY should be the relative path of the object like 'uploads/user/logo/123/pic.png'
obj = s3.bucket('YOUR-BUCKET-NAME').object('YOUR-OBJECT-KEY')
url = obj.presigned_url(:get, expires_in: 3600, response_content_disposition: "attachment; filename='FILENAME'")
then in your views, just use:
= link_to 'download', url
event = Event.find(params[:id])
data = open(event.creative.url)
send_data data.read, :type => data.content_type, :x_sendfile => true, :url_based_filename => true
end
You need to set the "Content-Disposition" to "attachment" in your HTTP response header. I'm not a Rails developer - so just Google it and you'll see plenty of examples - but it probably looks something like this:
:content_disposition => "attachment"
or
...
:disposition => "attachment"

Ajax Callbacks in Rails 3 with Prototype, not jQuery

I'm upgrading an app from Rails 2 to 3 and am reworking all of the remote functions to use Unobtrusive Javascript. Where I'm struggling is handling ajax callbacks in UJS.
There are a lot of resources I've found that show how to implement these callbacks with jQuery, but not much for prototype. Perhaps you can help me figure this out.
In Rails 2, I had this:
<% remote_form_for #foo, {:loading => "loading_function()", :complete => "complete_function()" } do |f| %>
...
<% end %>
In Rails 3, I have this:
<%= form_for #foo, :remote => true do |f| %>
....
<% end %>
From what I've figured out so far (which may be wrong), I need to attach my old loading/complete functions to the form so that they'll be fired by the handleRemote function in Rails.js. I'm just not sure how to go about that.
Again, I'm doing this in Prototype. So answers specific to that framework are appreciated.
The answer is the following:
<%= form_for #foo, :remote => true do |f| %>
...
<% end %>
...
<script type='text/javascript'>
$('edit_foo').observe('ajax:before', loading_function());
$('edit_foo').observe('ajax:complete complete_function());
</script>
Try this link. Yes, it is JQuery, but JQuery and Prototype do not differ the way how things work together. Here is a code fragment that adds a new task directly in the index page - and it uses Prototype:
views/tasks/_newform.html.erb:
<%= form_for(#task, :remote => true) do |f| %>
<div>
<%= f.label 'Add a new task: ' %>
<%= f.text_field :name %>
</div>
<div>
<%= f.submit %>
</div>
<% end %>
views/tasks/index.html.erb:
<div id='newform'>
<%= render :partial => "newform", :locals => { :#task => Task.new } %>
</div>
views/tasks/create.js.rjs:
page.insert_html :after, 'tablehead', :partial => #task
page.replace_html 'newform',:partial => "newform", :locals => { :#task => Task.new }
Edit: you need to add "format.js" to our create method of the task controller
For people with a similar issue, it may also help to look at the source code for the remote helpers in the Rails 2.3.x source code.
In my case, I wanted to figure out what to do with the ':update' parameter, as in:
remote_form_for(#obj, :update => "new_obj", :before => "some js code") do |f|
I had to find the update functionality in the remote_function code.
For my specific issue, it looks like it's impossible to get the equivalent of :update with Rails 3 UJS helpers. The rails.js in Rails 3 wraps :remote => true requests with the Ajax.Request(...), whereas the :update function in Rails 2 wraps Ajax requests with Ajax.Updater(...). For people looking to replace the :update feature from Rails 2, I see 2 options:
Switch to jquery-rails, so that you can access the response from the Ajax request, with code like this:
$("#elem").bind("ajax:complete", function(et, e){
$("#results").html(e.responseText);
});
Write your own Prototype based code to grab the form and submit it via ajax, using Ajax.Updater(...) instead of Ajax.Request. Do NOT use :remote => true, since this will attempt to use Ajax.Request.
Side note: I played around with the callback object provided in the ajax:complete event
$('new_obj').observe('ajax:complete', function(request){
console.info(request);
});
The request object doesn't appear to contain the response anywhere in it. It is pretty massive, though, so I could be wrong. Hopefully this will help someone else trying to upgrade from Rails 2 to 3, though.
There's a way to get the response from the Ajax.Request invocation, if you were using remote_form_for with :update option. So, you probably don't need to change it to use Ajax.Updater as a workaround. Basically, you use respone.memo.responseText, in your example it would be something like this:
$('new_obj').observe('ajax:complete', function(response){
console.info(response.memo.responseText);
// Probably you would use it like this:
$('new_obj').update(response.memo.responseText);
});