convert SVG code to format to attach to user in Rails - ruby-on-rails

Essentially, in my app users can create a custom svg element using js (stimulus).
My user.rb model has:
has_one_attached :picture
in my attach_image_controller.js I can access the svg code:
<svg>
<-- blah blah >
</svg>
What is the best way to transform this code into a format that can be attached in my user_controller.rb?
I have tried turning the code into a blob and creating an object url, but I haven't been able to then attach it to a user (see below attempt)
attach_image_controller.js
var testsvg = `<svg>
<-- blah blah >
</svg>`;
var blob = new Blob([testsvg], {type: "image/svg+xml"});
var url = URL.createObjectURL(blob);
console.log(url); // returns: blob:http://localhost:3000/15107c0d-b794-4be6-a1e0-2cf9e8f49174 and results in routing error
// As there is a routing error, this url can't be used as per below
and then when passed to the user_controller.rb:
user_controller.rb
#url = params[:url]
#user = current_user
file = URI.open(#url[5..-1])
#user.picture.attach(
io: file,
filename: #url[5..-1],
content_type: 'image/svg+xml')
Edit:
To make things more complicated, in some cases, users have the ability to upload and attach an image, or generate a svg code that renders in the DOM, but I want to be able to attach both the SVG code and the uploaded image.

The typical use case for attachments is when we wish to associate an uploaded file (often an image, e.g. jpg) with a model.
However the svg is an html snippet, it's a string comprised of a single html element (<svg>... </svg>). So you might consider simply including it as a string column in your User model. Remember, though, that you need to declare it html_safe before it will render correctly. So if you are using erb, you'll have <%= user.svg_image.html_safe %>.

Related

How to add html file into active admin page and make it a part of page?

Now I have information in XML format, I need to convert it with stylesheet.xslt to receive HTML table. I try to put this HTML table into my admin page(I use active admin), but get text of my html file. However I would like to see a table after converting
I tried to put it into different tags(div/pre), don't help
pre id: 'response_xml_into_html', class: 'collapse' do
document = Nokogiri::XML(request)
template = Nokogiri::XSLT(File.read('stylesheet.xslt'))
template.transform(document)
Am not sure, but try this:
document = Nokogiri::XML(request)
template = Nokogiri::XSLT(File.read('stylesheet.xslt'))
htmltable_out = template.transform(document)
div(id: 'response_xml_into_html', class: 'collapse') do
htmltable_out.html_safe
end
Also make sure to start a rails console en see whether the transformation indeed works. Good luck!

Can I build a model with Paperclip attachment?

I have a model Style which has a paperclip attachment file. I am using a multi-page form for creating the Styles. In my first step I upload the file and in the next page I update the other attributes of the Style record. I don't know how to build the style with the attachment so that it can be used in the later step.
Below is my action for my second step. The attachment file is not yet saved, so how do I build it that the file is available in the view. Any help is appreciated.
def build_form
styles = params_array.delete(:styles)
#styles = []
styles.each do |style_file|
name = style_file.original_filename.split(".")[0..-2].join(".")
#styles << Style.new(name: name, file: style_file)
end
render :new
end
HTTP is stateless so if your multipage form is using HTTP requests I think you should be able to save it to database or store in the session.
If you are saving it to the database you should remove record at the end if any step is not valid.
But I think multipage form should use js, so file content and file info is saved to the form.
So my suggestion is to use ajax for multipage form, in this case, you will have all content on the page, but some content would be hidden

How to display an image using a different filename than the physical filename?

In my image hosting webapp I created a hackish way for image de-duplication to save on storage space by having an image.rb model with paperclip to store physical images and a second model imagelink.rb to store image names which link to the physical image. So in my imagelink model I use "belongs_to: image" and add an index on the imagelink to image_id of the image. The naming of the image and imagelink is simply an encoded version of the ActiveRecord ID.
When uploading the image I simply check it's md5sum to see if the image already exists if it does exist then I create a new imagelink ID and use the image ID of the original image. Otherwise I save the image and create a new image ID. This allows me to have a physical image like "vb56.jpg" and an encoded imagelink like "vb56.jpg" as well as a second imagelink like "4gb7.jpg" which also uses the physical image "vb56.jpg"
So naturally now I want to display the original physical image "vb56.jpg" but using the name "4gb7.jpg" when being accessed from the "4gb7.jpg" imagelink. I can achieve this by making another request for each imagelink which would look something like this:
images_controller.rb
before_action :set_image, only: [:show, :show_direct]
def show_direct
path = #image.image.image.url
url = Rails.root.join('uploads' + path)
send_file url, type: #image.image.image_content_type, disposition: 'inline'
end
def set_image
#image = ImageLink.decode(params[:id])
raise 'image not found' if #image.nil?
end
image_view.html.erb
<%
id = #image.encoded_id
ext = #image.image.extension
%>
<img src="<%= MYAPP::DOMAIN %><%= id %>.<%= ext %>" class="image-display" />
So two problems doing it this way is 1) This is probably going to create slowness as well as tons of requests to the rails server for each image displayed on a page. 2) This is messing up the way I store session[:previous_url] for logging in with devise which is "session[:previous_url] = request.fullpath" since each image is a request it's storing the last requested image as the previous_url instead of the actual page the user is on.
Is there a way I can display the image without making tons of requests like currently doing? Doing the proper way with <%= image_tag(#image.image.image.url) %> to display the physical image will show the image as the original filename but I'd like it to show the filename as the imagelink name so that to the user the physical image name will always match the imagelink name.
Also am I doing session[:previous_url] wrong? Is there a better way to do it to capture the page URL rather than the URL of other requests coming from within the page?

How do I convert a page of HTML to a page on my Rails site?

I added an upload form so people can upload HTML files to my site. How do I parse a file of HTML to create a page of content on the site? Currently, I just need to get the title and body of a file, so I thought a full-blown parser like Nokogiri would be overkill.
#this takes in a <ActionDispatch::Http::UploadedFile>
def import(file)
#code to get title and body?
end
One of many ways to do this..
You can open and read the file from your controller assuming you saved it to an object somewhere.
#content = File.read(#your_saved_object.attachment.file_name)
And then in your view ( in Haml ) :
#content-container= #content

How do I update the contents of a placeholder with a generated image in Rails?

I have a div tag in the view that I'd like to update with a graph that I generate via Gruff.
I have the following controller action which does this at the end
send_data g.to_blob, :disposition=>'inline', :type=>'image/png', :filename=>'top_n.pdf'
Now if I directly invoke this action, I can see the graph. (More details here if reqd.)
If I add a link_to_remote_tag that calls the above action via AJAX passing in specific input, generates this graph and tries to update a placeholder div tag... I see gibberish.
I think I can write the graph to a png file with g.write(filename.png) how do I embed the graph within the div tag in the view at run-time?
In your link_to_remote tag just set :complete to something like this:
:complete => "updateImg(id_of_div, request.responseText)"
And write a JS function:
function updateImg(id, img)
{
$(id).innerHTML = '<img src="' + img + '" />';
}
Where id_of_div is the id of the div when you want to show de image.
The request.responseText var come from the request of the AJAX call, I mean, when your code writes the png file with the graph, finish the method returning the path to this new png (render :text => path_to_new_image ); then, use this request variable in the :complete.
You could use a regular img tag to call a controller action wich returns a generated png. If you set up the controller to use respond_to something like this:
def graph
# get the relevant data for 'g' here
respond_to do |format|
format.html #uses the default view if relevant (good for debugging)
format.png do
send_data g.to_blob,
:disposition=>'inline',
:type=>'image/png',
:filename=>'top_n.pdf'
end
end
end
You'll even have a normal looking url for the generator like this:
<img src="controller/graph.png" alt="Something"/>
If there's a chance the image generation can fail: you could store a fallback image on the server and read that file and return that.
If the generation is quite heavy and not very likely to change all the time you cold allso cache the resulting file and get that instead if you determine that the data has not changed. You could use the method ARemesal suggested to delay adding the image link until the image is generated and then link directly to the cached file. (It depends on your specific case what's best)

Resources