url for Active Storage in Ruby on Rails - ruby-on-rails

2 and Active Storage (Nginx + Passenger).
I sometimes have problems with rendering images I got the incorrect url.
Sometimes I have the source url https://example.org/rails/active_storage/blobs/.. and sometimes https://example.org/rails/active_storage/disc/..
image_tag url_for(event.logo)
If I reload the page I have got normal img - with the correct url.
I didn't find information on how they generated url, and why they have got different url
Change used method for url
image_tag event.logo - clear method without url_for
Rails.application.routes.url_helpers.rails_blob_path(event.logo, only_path: true)

Related

How do I correctly render images via Hotwire Turbo streams?

My problem: When rendering images using Hotwire/Turbo, all URLs render with host example.org instead of my actual hostname. Regular views are fine, but rendering partials through a Turbo stream leads to ActiveStorage URLs like http://example.org/.../.
Context: I have a simple Todo app, with a working view, partial, and turbo stream which together show a Todo and a list of associated users. When I join a User to a Todo, the turbo stream renders the correct partial, and puts the user's name and avatar in the DOM where I want. However, the image URL from ActiveStorage contains the example.org hostname.
I've set my standard URL options in config/environments/*.rb, including routes.default_url_options[:host], and config.action_mailer.default_url_options[:host]. I also learned about the file config/initializers/application_controller_renderer.rb, where you can set an http_host parameter; however, I've set http_host, the https boolean, and still Turbo is rendering my image_tag with example.org.
Further, I've found limited advice about how to manipulate the default renderer programmatically (in order to fix the issue). This source says to grab ApplicationController.renderer and override the properties, like so:
renderer = ApplicationController.renderer.new(
http_host: request.host_with_port,
https: (request.protocol == "https://"),
"rack.session": request.session
)
but the broadcast_action_to methods do not appear to accept a renderer parameter, so this doesn't actually help me within Turbo.
There must be a configuration that I'm missing, but I'm not finding it in the Turbo or Hotwire documentation.
I was missing config.action_controller.default_url_options. Once I configured that the same as the other default_url_options, my links began to render properly.
In my case I have a dynamic default_url_options as my application is multi-tenant so I added this to ApplicationController:
def default_url_options
{ host: SiteSetting[:entity].domains.first.name, protocol: 'https' }
end
I think this all springs from having an asset_host configuration in place so that normally image url's have the asset host in them. ActiveStorage url's use the current default host (not the asset host of course) because they're actually redirect routes rather than actual files. I'd assume if asset_host isn't set, then the image paths would be relative and not absolute? It'd be ideal if they could just be kept relative regardless.

is it possible to show only a part of the image URL in rails?

I am using Carrierwave and S3 to allow people to upload images and the image URL is displayed as "https://myapp.s3.amazonaws.com/image/53/98ccfeca46.jpg".
I would like to do one of two things.
I would like to show just
"/image/53/98ccfeca46.jpg"
or 2. Use CName to rename the URL to not show "s3.amazonaws.com" so that the image URL will be
https://myapp.com/image/53/98ccfeca46.jpg
How can I achieve these? Is it possible to cut the image URL right after .com?
I am using <%= link_to xyz.image % > to display the URL.
You could create a helper method for displaying the url, and use string sub to cut off the first part of the url.
So in your helpers folder, in the helper for the corresponding model, you might have a function like
def show_url(url)
return url.sub("https://myapp.s3.amazonaws.com", "")
end
And then in your helper you would have <%= link_to show_url(xyz.image) %>
Or indeed something similar, but using regular expressions
def show_url(url)
return url.match(/.com(.+)/)[1]
end
If you're using carrierwave, you can call .path to retrieve the path of the image. I tried this locally and it worked fine but I'm not sure if it will work in production. Try this:
<%= link_to xyz.image.path %>
Alternatively, you can use CloudFront to server you S3 files, which allows you add a bunch of custom CNAMEs to your distribution, so you can have assets.myapp.com/xyz.jpg

Rails - Storing route data in database

I have a model that stores a path in the database under a column named "link_path" - for example:
Model.first.link_path == /posts/1
(or, put another way, I am caching the controller/model_id in a database table so Rails doesn't have to build it from scratch.)
In my view, I would like to build up a URL using this path information - for example, http://www.mysite.com/posts/1
I currently have the following code in my view:
<a href="<%= "#{request.protocol}#{request.domain}#{request.port_string}#{post.link_path}" %>">
In development all works as expected both when using POW/Nginx and Webrick - e.g., the link builds up to
http://localhost:3000/posts/1).
However, in production, when I hover over the link, it shows correctly (e.g., mysite.com/posts/1) BUT, when I click on the link, the '/' between .com and posts is strangely missing. The page links to http://mysite.composts/1
Any thoughts on how to fix?
Thanks to BrMcMullin - I wasn't aware I could use the URL helpers without calling the model. Since I don't need the weight of link_to, I ended up changing to
url_for(post.link_path)
instead of manually building up using string interpolation and that seems to work as expected.

How to retrieve web site favicons?

I am using Ruby on Rails v3.0.9 and I would like to retrieve the favicon.ico image of each web site for which I set a link.
That is, if in my application I set the http://www.facebook.com/ URL I would like to retrieve the Facebook' icon and use\insert that in my web pages. Of course I would like to do that also for all other web sites.
How can I retrieve favicon.ico icons from web sites in an "automatic" way (with "automatic" I mean to search for a favicon in a web site and get the link to it - I think no because not all web sites have a favicon named exactly 'favicon.ico'. I would like to recognize that in an "automatic" way)?
P.S.: What I would like to make is something like Facebook makes when to add a link\URL in your Facebook page: it recognizes the related web site logo and then appends that to the link\URL.
http://getfavicon.appspot.com/ works great for fetching favicons. Just give it the url for the site and you'll get the favicon back:
http://g.etfv.co/http://www.google.com
Recently I have written some similar solution.
If we want find favicon url, that can be not only .ico file and can be not in the root, we should parse target site html.
In Ruby on Rails, I have used nokogiri gem for html parsing.
First we parse all meta tags where itemprop attribute contains image keyword. It is necessary in situations where target site used https://schema.org/WebPage template, that more modern technology than just link tag.
If we found it, we can use content attribute as favicon url. But we should check it for really URL existence, just to be sure.
If we can't found some meta tags, then we search for standard link tags, where rel attribute contains icon keyword. This is W3C standard situation (https://www.w3.org/2005/10/howto-favicon)
And some code of my solution:
require 'open-uri'
def site_icon_link site
icon_link = nil
url = nil
doc = Nokogiri::HTML(open(site))
metas = doc.css("meta[itemprop*=image]")
if metas.any?
url = metas.first.attributes['content'].value
else
links = doc.css("link[rel*=icon]")
if links.any?
url = links.first.attributes['href'].value
end
end
if url =~ URI::regexp
icon_link = url
elsif (site + url) =~ URI::regexp
icon_link = site + url
end
icon_link
end
The favicons are being found by two ways. First, there is a 'hardcoded', traditional name of `http://example.com/favicon.ico'.
Second, the HTML pages may define the favicon in their <head> sections, by <link rel="icon"...> and a few other. (You may want to read the Wikipedia article about favicon)
So, your automat may fetch the main page of given website, parse it and check whether there are proper <link> tags, and then, as a fallback, try the "hardcoded" favicon.ico name.
I think I missed your question ...
you want to grab a favicon from another site and make it yours?
if that's what you want, you can get directly from the home icon and save it in your public folder.
thus: www.facebook.com favicon: www.facebook.com/favicon.ico
take that image and save with the name favicon in your public folder
done it should be sufficient
if you want it dinamicaly you can use jquery, but if you want that static you can put a image tag pointing to: [root url of the website]/favicon.ico
like this: <%= image_tag "#{website.url}/favicon.ico" %>
With javascript (jQuery), like this: http://jsfiddle.net/aX8T4/
Can't you just use a regular img tag with the src attribute pointing to the favicon?
<img src="http://www.facebook.com/favicon.icon">
This assumes a browser recognizes a .ico file as an image. Helped methods would probably work with this too.
You can do it easily with pismo gem.
Quick example to get the url of Facebook's favicon:
Pismo::Document.new('http://www.facebook.com/').favicon
Here's my ruby method, that will strip the end off a URL, append the favicon, and produce an image tag.
def favicon_for(url)
matches = url.match(/[^:\/]\/(.*)/)
image_tag url.sub(matches[1], '') + '/favicon.ico', {width: '16px', height: '16px'}
end

How to check if an image was found on a web site?

I am using Ruby on Rails v3.0.9 and I would like to check if an image (in my case a favicon.ico icon image) is successfully retrieved from a web site and if not I would like to display a custom image.
In order to retrieve the favicon.ico image related to a web site, in my view file I have:
image_tag "#{web_site.link}/favicon.ico", :size => "16x16"
where web_site.link values are something like the followings:
http://stackoverflow.com/
http://www.stackoverflow.com/
http://facebook.com/
...
How to check if an image was found on a web site (maybe using an if ... else ... end statement or performing some HTTP request before to handle favicon images) and how to handle the above scenario?
Here's how to implement the idea you had in the original question.
The issue with this approach will be that your response times will include however long it takes for the other domain to respond to your request for the image. If that site is having
issues, then your page wont load until the request times out.
<%
img_url = 'http://adomain.com/image.jpg'
res = Net::HTTP.get_response(URI.parse(img_url))
img_url = '[my alternate url]' unless res.code.to_i >= 200 && res.code.to_i < 400 #good codes will be betweem 200 - 399
%>
<%=image_tag img_url%>
The jQuery approach is a bit more involved. I'd suggest something along the following:
create an <img> tag with a transparent spacer image
in the page's javascript run a $.ajax call for the remote image
in the success callback replace the <img>'s src with the remote images's url
in the failure callback replace the <img>'s src with the fallback image's url
Unfortunately, I don't have time to generate the exact code for this right now.
You can't do this with Rails unless you fetch the image server-side before rendering the page. What you could do is fetch it in the client with a JavaScript and if there's trouble retrieving it, then switch to an alternative.

Resources