Save canvas to image on server upon form submit with Rails - ruby-on-rails

i'm using Caman JS to manipulate an image in my edit view for the model Item.
$('#vintage').click(function() {
Caman("#preview_image", function () {
this.reset();
this.crossProcess(100)
this.render(function () {
this.addClass('selected');
});
});
});
Caman JS provides me with an option to get the base64 value of the Canvas object
var dataURL = this.toBase64();
However i'm now kind of stuck what to do with this information. Ideally i'd like to overwrite the original image upon submitting my rails form.
Any suggestions would be great.

Ok, I found A solution. Here it is...
create a hidden field with the base64 data as the value
<input id="base64" type="hidden" value="" name="base64"/>
var dataURL = this.toBase64();
$('#base64').val(dataURL)
I then processed this in my controller.
unless params[:base64].empty?
data = params[:base64]
image_data = Base64.decode64(data['data:image/png;base64,'.length .. -1])
File.open("#{Rails.root}/public#{#item.image.url.to_s}", 'wb') do |f|
f.write image_data
end
// Carierwave method to regenerate thumbnails
#item.image.recreate_versions!
end
Might help someone, I'm still definitely open to suggestions for better or more efficient ways to do this.

Related

Render partial from jQuery ruby on rails

I wanted to render a partial that contains a form inside of view from application js, I am reading the event of attached button without submitting because I need to process the headers of a file CSV before doing submit.
This is the function:
$(document).ready(function () {
$("#attached_attached_csv").change(function (e) {
if (e.target.files != undefined) {
var reader = new FileReader();
reader.onload = function (e) {
// this line isn't working - I try of many ways, but none are working
$("#text").html("<%= j render partial: 'layouts/form') %>".html_safe);
};
reader.readAsText(e.target.files.item(0));
}
return false;
});
});
I see also how any people using ajax, but I don't know how to use this for the trigger event of an attached button without submitting, I prob sending without html_safe but I obtain the string:
<%= j render partial: 'layouts/form') %>
My partial is "layouts/form", which is a file with extension html.erb. here share where I found the code for handle the event http://jsfiddle.net/FSc8y/2/, but it's not important the most important for me its render the embedded ruby form. Thanks in advance.
You can use rails syntax in your javascript files by adding .js.erb extension to the file name like my_file.js.erb.

How to load initial data from rails to redux

I tried to load json from rails, and pass it to redux createStore.
let initialStore = window.INITIAL;
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(rootReducer, initialStore);
But i always get undefined, or just window.INITIAL return value after store.
At first, store loads with empty object, then fetch action is dispatched, and i get updated store with json, but i already got error, when i'm trying to call something like { product.title } on empty object. No matter what I do, i can't load json before redux stuff begins, even with global data, like this.
(function() {
$.getJSON('http://localhost:3000/products.json', function(data) {
return window.INITIAL = data;
});
});
Api and controller is simple.
def index
products = Product.all
render json: products
end
How do you handle this? I want to do it without any gems like react-rails etc, i can't pass all initial state to Root component in one place.
In the question above you have the following:
let initialStore = window.INITIAL;
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(rootReducer, initialStore);
The problem with the above code is that it will only populate your store with window.INITIAL as it exists when the page first loads. Any further changes to window.INITIAL will be ignored.
What you need to do is populate window.INITIAL with your initial data in your server rendered code. That is, simply place the script block before your redux code:
<script>
var INITIAL = { /* this object should match the shape of your reducer state */ };
</script>
That's it. Now get rid of the AJAX call. You don't need it. This will be a lot more performant too. Instead of forcing the user to wait on an additional request after the page has already rendered, the user instead gets all the data at the same time as the rest of the page.

Rendering dynamic scss-files with ajax, rails

As the title suggests, my main objective is to render a dynamic scss(.erb) file after an ajax call.
assets/javascripts/header.js
// onChange of a checkbox, a database boolean field should be toggled via AJAX
$( document ).ready(function() {
$('input[class=collection_cb]').change(function() {
// get the id of the item
var collection_id = $(this).parent().attr("data-collection-id");
// show a loading animation
$("#coll-loading").removeClass("vhidden");
// AJAX call
$.ajax({
type : 'PUT',
url : "/collections/" + collection_id + "/toggle",
success : function() {
// removal of loading animation, a bit delayed, as it would be too fast otherwise
setTimeout(function() {
$("#coll_loading").addClass("vhidden");
}, 300);
},
});
});
});
controller/collections_controller.rb
def toggle
# safety measure to check if the user changes his collection
if current_user.id == Collection.find(params[:id]).user_id
collection = Collection.find(params[:id])
# toggle the collection
collection.toggle! :auto_add_item
else
# redirect the user to error page, alert page
end
render :nothing => true
end
All worked very smooth when I solely toggled the database object.
Now I wanted to add some extra spices and change the CSS of my 50+ li's accordingly to the currently selected collections of the user.
My desired CSS looks like this, it checks li elements if they belong to the collections and give them a border color if so.
ul#list > li[data-collections~='8'][data-collections~='2']
{
border-color: #ff2900;
}
I added this to my controller to generate the []-conditions:
def toggle
# .
# .
# toggle function
# return the currently selected collection ids in the [data-collections]-format
#active_collections = ""
c_ids = current_user.collections.where(:auto_add_item => true).pluck('collections.id')
if c_ids.size != 0
c_ids.each { |id| #active_collections += "[data-collections~='#{id}']" }
end
# this is what gets retrieved
# #active_collections => [data-collections~='8'][data-collections~='2']
end
now I need a way to put those brackets in a scss file that gets generated dynamically.
I tried adding:
respond_to do |format|
format.css
end
to my controller, having the file views/collections/toggle.css.erb
ul#list<%= raw active_collections %> > li<%= raw active_collections %> {
border-color: #ff2900;
}
It didn't work, another way was rendering the css file from my controller, and then passing it to a view as described by Manuel Meurer
Did I mess up with the file names? Like using css instead of scss? Do you have any ideas how I should proceed?
Thanks for your help!
Why dynamic CSS? - reasoning
I know that this should normally happen by adding classes via JavaScript. My reasoning to why I need a dynamic css is that when the user decides to change the selected collections, he does this very concentrated. Something like 4 calls in 3 seconds, then a 5 minutes pause, then 5 calls in 4 seconds. The JavaScript would simply take too long to loop through the 50+ li's after every call.
UPDATE
As it turns out, JavaScript was very fast at handling my "long" list... Thanks y'all for pointing out the errors in my thinking!
In my opinion, the problem you've got isn't to do with CSS; it's to do with how your system works
CSS is loaded static (from the http request), which means when the page is rendered, it will not update if you change the CSS files on the server
JS is client side and is designed to interact with rendered HTML elements (through the DOM). This means that JS by its nature is dynamic, and is why we can use it with technologies like Ajax to change parts of the page
Here's where I think your problem comes in...
Your JS call is not reloading the page, which means the CSS stays static. There is currently no way to reload the CSS and have them render without refreshing (sending an HTTP request). This means that any updating you do with JS will have to include per-loaded CSS
As per the comments to your OP, you should really look at updating the classes of your list elements. If you use something like this it should work instantaneously:
$('li').addClass('new');
Hope this helps?
If I understood your feature correctly, actually all you need can be realized by JavaScript simply, no need for any hack.
Let me organize your feature at first
Given an user visiting the page
When he checks a checkbox
He will see a loading sign which implies this is an interaction with server
When the loading sign stopped
He will see the row(or 'li") he checked has a border which implies his action has been accepted by server
Then comes the solution. For readability I will simplify your loading sign code into named functions instead of real code.
$(document).ready(function() {
$('input[class=collection_cb]').change(function() {
// Use a variable to store parent of current scope for using later
var $parent = $(this).parent();
// get the id of the item
var collection_id = $parent.attr("data-collection-id");
show_loading_sign();
// AJAX call
$.ajax({
type : 'PUT',
url : "/collections/" + collection_id + "/toggle",
success : function() {
// This is the effect you need.
$parent.addClass('green_color_border');
},
error: function() {
$parent.addClass('red_color_border');
},
complete: function() {
close_loading_sign(); /*Close the sign no matter success or error*/
}
});
});
});
Let me know if my understanding of feature is correct and if this could solve the problem.
What if, when the user toggles a collection selection, you use jquery change one class on the ul and then define static styles based on that?
For example, your original markup might be:
ul#list.no_selection
li.collection8.collection2
li.collection1
And your css would have, statically:
ul.collection1 li.collection1,
ul.collection2 li.collection2,
...
ul.collection8 li.collection8 {
border-color: #ff2900;
}
So by default, there wouldn't be a border. But if the user selects collection 8, your jquery would do:
$('ul#list').addClass('collection8')
and voila, border around the li that's in collection8-- without looping over all the lis in javascript and without loading a stylesheet dynamically.
What do you think, would this work in your case?

Rails 3: best way to preview image before upload

I need to preview an image prior to submitting a form.
I work with Rails 3 and needs something that is browser compatible.
Any ideas how I can achieve that?
So! :) The main idea is to use the FileReader Javascript Class, which is really handy for what you need to do.
You just have to listen to the "change" event on your file input and then call a method that will use the "readAsDataURL()" method of the FileReader class. Then you just have to fill the source of a "preview img tag" with the returned result of the method...
I've wrote you a simple jsFiddle that achieves what you want. You can see my code below:
<!-- HTML Code -->
<div class="upload-preview">
<img />
</div>
<input class="file" name="logo" type="file">
//JS File
$(document).ready(function(){
var preview = $(".upload-preview img");
$(".file").change(function(event){
var input = $(event.currentTarget);
var file = input[0].files[0];
var reader = new FileReader();
reader.onload = function(e){
image_base64 = e.target.result;
preview.attr("src", image_base64);
};
reader.readAsDataURL(file);
});
});
And in the Mozilla Documentation, you have another example (surely more robust). This solution should work with Safari (version 6.0+).
This is the only way I know to preview an image prior to submitting a form, but I think it is quite a common way. Of course it has nothing to do with Ruby On Rails as we only use Javascript here... It would be impossible to do it using Rails only as you would have to upload the image before rendering it. (As Rails is server side, I think you perfectly understand why. :) )
HTML:
<input type="file">
<div id="image_preview"></div>
JS (require jquery):
$(document).ready(function(){
$('input[type="file"]').change(function(){
var image = window.URL.createObjectURL(this.files[0]);
$("#image_preview").css("background-image", "url(" + image + ")");
});
});

How to show images after uploading with Plupload without page refreshing?

Plupload/paperclip/rails 3.1.4/ruby 1.9.3
i successfully upload multiple images with Plupload, and as usual i've put in 'images/create.js.erb' code, which appends images to page.
nothing happens. even primitive alert has no visual response, but i hear how my hard disk grunts (actually i made endless cycle of alerts to hear that something happens inside :)
images_controller
def create
#image=Image.create(:photo => params[:file])
respond_to :js
end
views/images/create.js.erb
$('body').append('<%= escape_javascript(image_tag(#image.photo.url(:medium))) %>');
after each image creating, it must appear on page.
i found the answer.
views/images/create.js.erb
<%=#image.id %>:<%= #image.photo.url(:medium) %>
views/items/_form.js.erb
<script>
...
uploader.bind('FileUploaded', function (up, file, info) {
var response = info['response'].split(':');
var image_id= response[0];
var image_url= response[1];
...
use it as you want, my lord!..
...
});
...
</script>

Resources