Is there a way to use images out of our nitro app directory, while using nitro in a private (closed to everyone but local users) server?
Example:
I have a nitro app in /home/user/app accessible through http://localhost, and an image I want to be shown located in /home/user/images/image.png.
As I've noticed,
doesn't work, since it looks for the image in "http://localhost/home/user/images/image.png", which is obviously wrong. What I want to know is if there's a way around this?
This question popped up while I was developing a small browser-based database interface for images, like Danbooru, but for home use. I haven't yet found a "normal" app that does this the way I want it to (no, I hate F-spot) -- easy image tagging, duplicate finder and gorgeous looking (css all teh way) --, so I decided to do it myself.
(3 attempts)
Kashia answered:
General way:
First, create a action in a crontroller to "serve" the image:
require 'nitro/cgi/stream' def image img = request['img'] response.content_type = 'img/gif' # or whatever stream File.open('/home/user/images/'+img) end
This would basically just return the picture, when you use a URL like /image?img=foo.gif.
From the idea, it should work like this, you should of course do more error checking.
UPDATE:
I take it, that the source field in your database table for the pictures points to a real path in the filesystem. bad, very, no cookies for you, don't do this, change your db or else the ants will come crawling into your system.
That said, my proposed solution is the first half to solve what you want, you already have the second part, there's just a little glue missing.
You have the path to the pictures in a database which you query by Og and just use the image.source as URL to it. Just as you would use the image.source you can use the above action to get pictures:
photos.xhtml
<?r unless @photos.empty? for image in @photos ?> <a href="#{image.source}"> <img src="/image?img=#{image.source}" /></a> <?r end else ?> <p>Nothing found for your query</p> <?r end ?>
This will exactly do what you said, offer the image for download, which the browser will do when encountering an <img> tag. It just routes your image requests through the def image action. If you really want to stay with the full-path-to-image option, you should put extensive checking into the image function, if the given path is really a picture, if it is allowed to read it, if it isn't some kind of system path etc.
I hope this helps.
UPDATE 2:
I thought the puts would put to the browser, sorry. I changed the action so it uses the stream mechanism provided by nitro/cgi/stream.rb. When given a IO object (like File.open) it streams it to the browser.
UPDATE 3:
Forgot to add the (probably) required require for the stream command.
Fabian answered:
Wouldn't it be much easier to just set a symlink? In unixes:
ln -s /home/user/images /home/user/app/public/images
Meqif answered:
(Dang it, forgot about using the appropriate tags...)
Thanks for your answer, Kashia. However, I may have not expressed myself well. The snippet you provided serves the file for download, which isn't what I'm looking for.
Here's what I'm using at the moment (warning: clunky code ahead):
controller.rb:
... def photos @photos = [] @query = request['q'] || request['search'] || request['query'] || request['tags'] unless @query.nil? sql_query = @query.map {|x| "name LIKE '%#{x}%'" }.join(" OR ") @photos = Photo.find(:condition => sql_query) end end ...
index.xhtml:
... <form id="grabber" client="grab" draggable="true"> <img id="spinner" src="spinner.gif" /> <input type="text" id="tags" name="tags" /> <input type="submit" /> <div id="photos"> </div> </form> ...
photos.xhtml
<?r unless @photos == [] for image in @photos ?> <a href="#{image.source}"><img src="#{image.source}" /></a> <?r end else ?> <p>Nothing found for your query</p> <?r end ?>
It simply looks for an entry in the DB which matches the query given through the form. The DB returns matching entries, whose full paths (path+name -- source) are asked then in photos.xhtml. A bit too complex, a lot clunky, but works when I have a symlink called home in public, linked to (surprise) /home. This way, although nitro still looks for the images in http://localhost/(source), it finds them, so works.
Sorry for your trouble.
UPDATE:
Thanks for your reply.
You guessed right, source == images' full path. You mentioned it was bad practice to store source in the DB. I suspected that, although I don't actually know how this could be used for damaging something, and it was the easiest way to do what I wanted (at least in theory). Thanks for telling me that.
Hmm... With the code you provided (changed accordingly, of course), the images are actually spat to debug stdout. Only noticed that now. Oh, and there's a little typo in def image, resonse --> response.
Maybe it would be better if I uploaded a tar.gz of the directory instead of posting snippets?
Thanks for your help.
--
Fabian: As I said when I first replied to Kashia's answer, I'm using that. It's the easiest way, but a dirty one. It's also non-portable and insecure. That's why I want to do it another way. Thanks for your answer, nonetheless.
--
UPDATE2
That should work, but I get this:
DEBUG: Compiling action 'Kuro#image' DEBUG: Compiling action 'Kuro#stream' ERROR: Error while handling '/image'. ERROR: undefined method `stream' for #<Kuro:0xa77257d0> /usr/lib/ruby/gems/1.8/gems/nitro-0.31.0/lib/nitro/controller.rb:111:in `method_missing'
This is mighty weird.
My problem is actually half solved, since I first create a thumbnail of the requested image(s), store them in public/thumbs and use them. Now, the problem is still there in case I want to show the original image individually.
You've been a great help, I feel we're getting near the solution for this. I don't understand why stream isn't recognized, since I use
class Kuro < Nitro::Controller