Dragonfly and Short URLs - ruby-on-rails

I'm using Dragonfly in a project that returns a large stream of photos and was looking to optimize the URLs. I'm currently getting image URLs like:
http://localhost:3000/media/BAhbCFsHOgZmSSJgZmRlL2ZkZTAxYzQ0LTM4Y2UtNGU0ZS1iOWRlLWUwZmUxNWUwN2JmMC83Mzk1NmZlMC05ZTA5LTQzNWUtODUyMC00MzFlYzQxMzQ1OTQvb3JpZ2luYWwuanBlZwY6BkVUWwg6BnA6CnRodW1iSSIMMjQweDI0MAY7BkZbCTsHOgxjb252ZXJ0SSIQLXF1YWxpdHkgODAGOwZGMA/240x240.jpg
Which is over 256 bytes. I'd like something like:
http://localhost:3000/media/1024/240x240_medium.jpg
That is conforming to:
/media/:id/:format
How would I go about adding this when using Dragonfly and Rails such that :format maps to a chain of operations and :id is used to find the model or image? Thanks!
Edit:
I've added custom Mime::Typefor each of the formats I need and have the following working:
# config/routes.rb
match "/photos/:id/:style", to: "photos#show", as: :media
# app/controllers/photos_controller.rb
def show
#photo = Photo.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.jpg { cache('public', 86400); redirect_to #photo.url(params[:style], 'jpg') }
format.png { cache('public', 86400); redirect_to #photo.url(params[:style], 'png') }
format.gif { cache('public', 86400); redirect_to #photo.url(params[:style], 'gif') }
end
end
# app/views/photos/show.html.erb
<%= image_tag media_path(id: #photo.id, style: 'small', format: 'png') %>
However this results in a 302 for each image (but otherwise works fine). Is it possible to handle this as a render or somehow do an internal redirect (i.e. not require the client to make duplicate requests)?

you shouldn't need to use a controller action - you can use a dragonfly endpoint - see http://markevans.github.com/dragonfly/file.URLs.html#Routed_Endpoints
e.g.
match '/photos/:id/:style.:format' => Dragonfly[:images].endpoint { |params, app|
Photo.find(params[:id]).image.thumb(params[:style]).encode(params[:format])
}
or something like that
(haven't tried the above code but it'll be something along those lines)

I've ran into a similar situation where the client needed a short url for downloadable pdfs.
Building on Mark's answer and looking at the dragonfly docs I came up with this:
#file.rb
class File < ActiveRecord::Base
dragonfly_accessor :pdf
end
def pdf_link
return "/pdf/#{self.filename}.pdf"
end
#routes.rb
get '/pdf/:filename' => Dragonfly.app.endpoint { |params, app|
File.where(filename: params[:filename]).first.pdf
}
It's not a direct answer to the question, but maybe it can still help someone looking for a way to shorten urls in dragonfly

Related

Sending an image path in json response with paperclip in rails

I am using paperclip for images in rails api.My problem is to send all ads which have also avatars along with other attributes.
I cant understand how I send all ads along with their images.
My response is like that
def ads_list
#ads = Ad.all.limit(10)
render json: {:success=>true, :message=>"List of all Ads",:ads=>#ads}, :status=>200
end
Through this all data send except avatars_urls.How I send avatar along with this?
My search till now.I found a solution for only one single object like this
Add in your model
def avatar_url
avatar.url(:medium)
end
and response is like that
render :json => #model.to_json(:only => [:id,:name,:homephone,:cellphone], :methods => [:avatar_url])
How I customize it for all objects or any other solutions?
I solve it
render json: {:success=>true, :message=>"List of all Ads",:ads=>#ads.map {|u| u.attributes.merge(:thumbnail_url => u.thumbnail.url)}}, :status=>200

How do can I show image files from outside the public directory?

It's pretty trivial to use the image_tag method to serve an image in the public directory, but what about images that I don't want to be publicly accessible, images for admins only, maybe.
How should my controller and view look so that an image_tag method serves an image from root/private/images rather than root/public. Also, that would be completely secure, right? If I had private images, and wanted to serve them only to admins, a simple if statement to check if the user is an admin and then using an image_tag to serve them the private image from outside the public folder would be secure?
I'd be interested in how to do this without paperclip. (paperclip not even mentioned so it's not a duplicate)
Assuming the image is related to a model such as one with paperclip attached, you could do this. (And I'd really recommend this).
def show
#image = Image.find(params[:id])
published_image = #image.published_image
respond_to do |format|
format.all {
if published_image
send_file published_image.attached_image.path, :type=> published_image.attached_image_content_type
else
raise ActionController::RoutingError.new('Not Found')
end
}
end
end
Assuming you have another way to tell this, you could have all routes beginning with /admin/image route to a controller action, and then there call render file on the rest of the path. Example:
routes.rb
get 'admin/photo/*other', to: 'admin#photos'
admin.controller.rb
def photos
if current_user.admin?
render file: Rails.root.join("private","admin","images",request.path.gsub("/admin/photo/","")
else
render :file => "public/401.html", :status => :unauthorized
end
end
view
image_tag "/admin/photos/id.jpg"
This would in theory work, but it might be more complicated than i'm thinking
Images here would be hosted in public/admin/images, but linked to as /admin/photos/id
I'm not sure how you are handling authentication for admins but assuming you have a separate login.
Store your images as BLOB in MySQL.
Return the requested image files using send_data in rails controller with authentication
This link have an example

Deleting a public folder or file from a Rails3 view?

I have a user model where users can upload their profile image, using the Paperclip gem. This all works fine and stores the file in the /public/images/#{user.id}/medium or original or small directory.
However I need to create an method to be able to delete these files, could someone help me with this?
Here is the code I have so far:
app/views/users/index.html.erb:
<%= link_to "Delete", method: :file_cleanup, action: :destroy %>
app/controllers/users_controllers.rb:
def file_cleanup
File.delete(Rails.root + 'public/#{current_user.image.url}')
redirect_to :action => :edit
end
I have not added any routes as the page seems to load without any errors.
It should be as simple as:
def delete_image
#user.image.destroy
end
I'd use that as a hook like before_destroy :delete_image.
See: Rails Paperclip how to delete attachment?

Ransack Search Results - to_xls?

I have a ransack search form which is working wonderfully, I would like to add an export for the user to send the contents of the result set to an XLS file.
I have implemented the to_xls sucessfully as well, however it is giving me back the fullest possible scope of the object I am searching, and not the filtered results that are shown in the view.
def index
#search = Expense.search(params[:q])
#expense_list = #search.result.sort_by(&:expense_date)
respond_to do |format|
format.html
format.xml { render :xml => #expense_list }
format.xls { send_data #expense_list.to_xls, :filename => '123.xls'}
end
end
Does it have something to do with how ransack uses the GET method? Any help would be great.
Thanks!
I know this is such a hack, after spending many hours of not getting it, I used it anyway.
make xls
so basically it takes the searchpath after the ?, then adds it to your model.xls output path and then it works. I hate it myself, there must be a better way, but deadlines.
There was a good link here.
Ronin gave a simple solution to this related question, but with CSV instead of XLS . In my case, using Ronin's answer, I just rewrote the link to work with XLS as shown below
<%= link_to "Download Excel", reports_path(params.merge(format: "xls")) %>
%= link_to "Download Excel", yours_controller_path(params.merge(format: "xls")) %>

Sending an image through JSON data

noobie here hope you guys don't mind! Im trying to query my user/id/pictures.json but all it returns are attributes cus i did a generic format.json {render :json => #photo.to_json()}. My question is how can i create and encapsulate the actual data from the images, so my client can turn that data in to an image? And also what do i need to create(attribute wise) besides the path of image(say you only had useless attributes eg: height content_type, description, thumbnail file_name)?
this is what im trying in my index.json.erb so far
}
<% #photos.each do |photo|%>
data: <%= StringIO.new(Base64.encode64(photo.public_filename(:large))) %>
<%end%>
}
i am getting back
{
data: #<StringIO:0x1058a6cd0>
}
which is not the IMGdata im looking for
looking for
Have a look at Data-URIs.
They essentially are Base64-encoded entities (documents) formatted as a URI
[{ "name":"red dot", "data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="}, ...]
[UPDATE]
You need to read the file and encode it as Base64 (you also need to strip the newlines away in rails 2.3.x)
data = ActiveSupport::Base64.encode64(File.read("/images/image1.png")).gsub("\n", '')
uri = "data:image/png;base64,#{data}"
I think you are using Ruby on Rails, aren't you?
Then there are some steps needed to download an image (e.g. a png):
Create a mime type
Go to config/initializers/mime_types.rb and insert Mime::Type.register "image/png", :png at the end.
Create an image
For example, you could use the gem Chunky_PNG to create an image, see at http://rubygems.org/gems/chunky_png and https://github.com/wvanbergen/chunky_png/wiki
Prepare your controller
You have to tell your controller, that it can accept pngs. Modify your controller the following way
class UsersController < ApplicationController
respond_to :json, :png
def show
# your own stuff
# ...
respond_with(response) do |format|
format.json
format.png do
send_data ChunkyPNG::Image.new(width, height, ChunkyPNG::Color::TRANSPARENT), :type =>"image/png", :disposition => 'inline'
end
end
end
end
This will create a fully transparent image. If you want to draw something in this, look at the Chunky PNG docs.
It's up to the client how to render it really. This works for me, maybe worth a try.
render json: #thumbnail, type: :jpeg, content_type: 'image/jpeg'

Resources