Determining if image exists in Rails 2 - ruby-on-rails

I am trying to check if a file exists so that I can either display the image or a placeholder but the placeholder is always shown. If the conditional statement is removed then the logo is displayed fine.
<% if File.exists?(Rails.root + '/public/images/portal/logos/' + #organisation_id + '.png') %>
<img src="/images/portal/logos/<%= #organisation_id %>.png" alt="<%= #person.organisation.name %>">
<% else %>
<img src="http://placehold.it/300x83&text=Please+upload+your+company+logo">
<% end %>
I've read a few questions but most seem to relate to Rails 3 but seeing as I don't get any errors I thought this would work.

Rails.root is working in rails 2? it may be RAILS_ROOT

Rails.root returns a Pathname. Adding an absolute path to a Pathname removes the existing path in the Pathname.
Ie.
Rails.root #=> #<Pathname:/foo/bar>
Rails.root + "baz" #=> #<Pathname:/foo/bar/baz>
Rails.root + "/baz" #=> #<Pathname:/baz>
If you do
Rails.root + 'public/images/portal/logos/#{#organisation_id}.png'
it should work. Or perhaps even better:
Rails.root.join("public/images/portal/logos", "#{#organisation_id.png')
Compare this to RAILS_ROOT which returns a String:
RAILS_ROOT #=> "/foo/bar"
RAILS_ROOT + "baz" #=> "/foo/barbaz"
RAILS_ROOT + "/baz" #=> "/foo/bar/baz"

Related

Ruby RegEx to locate image assets in an html/erb file

My end goal is to write a script that will loop through all my app/views folders and find any image assets being used within them (jpg, png, svg, gifs) and I can't quite get it but I feel I am close but need a little assistance.
This is how I am getting all my assets
assets_in_assets = []
# I searched for image asset names in this folder
image_asset_path = './app/assets/images'
# I haven't made use the below global variables yet
assets_in_use = []
# I plan to loop through the below folders to see if and where the image
# assets are being used
public_folder = './public'
app_folder = './app'
Find.find(image_asset_path) do |path|
# returns path and file names of all files extensions recursively
if !File.directory?(path) && path =~ /.*[\.jpg$ | \.png$ | .svg$ | \.gif$]/
&& !(path =~ /\.DS_Store/)
new_path = File.basename(path) # equiv to path.to_s.split('/').last
assets_in_assets << new_path
end
end
# The above seems to work, it gives me all the asset image names in an array.
This is how i am trying read a html.erb file to find if and where images are being used.
Here is a sample of part of the page:
<div class="wrapper">
<div class="content-wrapper pull-center center-text">
<img class="pattern-stars" src="<%= image_path('v3/super/pattern-
stars.png') %>" aria-hidden="true">
<h2 class="pull-center uppercase">Built by the Obsessed People at the
Company</h2>
<p class="top-mini">Our pets needed a challenge.</p>
<p class="italicize">So we made one.</p>
<img class="stroke" src="<%= image_path('v3/super/stroke.png') %>"
aria-hidden="true">
</div>
</div>
# The assets I am expecting to find, in this small section, are:
#- pattern-stars.png
#- stroke.png
And my code (I tried two different ways, here is the first):
# My plan is start with one specific file, then expand it once the code works
lines = File.open('./app/views/pages/chewer.html.erb', 'r')
lines.each do |f|
if f =~ / [\w]+\.(jpe?g | png | gif | svg) /xi
puts 'match: ' + f # just wanted to see what's being returned
end
end
# This is what gets returned
# match: <img class="pattern-stars" src="<%= image_path('v3/super
# /pattern-stars.png') %>" aria-hidden="true">
# match: <img class="stroke" src="<%= image_path('v3/super/stroke.png')
# %>" aria-hidden="true">
Not what I was hoping for. I also tried the following:
lines = File.open('./app/views/pages/chewer.html.erb', 'r')
lines.each do |f|
new_f = File.basename(f)
puts 'after split' + new_f # I wanted to see what was being returned
if new_f =~ / [\w]+\.(jpe?g | png | gif | svg) /xi
puts 'match: ' + new_f
end
end
# This is what gets returned
# after split: pattern-stars.png') %>" aria-hidden="true">
# match: pattern-stars.png') %>" aria-hidden="true">
# after split: stroke.png') %>" aria-hidden="true">
# match: stroke.png') %>" aria-hidden="true">
And here I remain blocked. I have searched through S.O. and tried a few things but nothing I have found has helped but it could be that I implemented the solutions incorrectly. I also tried look-behind (using the single ' as a end point) and look-ahead (using a / as a starting point)
If this is a dup or similar to another question, please let me know. I'd appreciate the help (plus an brief explanation, I really want to get a better understanding to improve my skills.
(?:['"])([^'"]+\.(?:png|jpe?g|gif|svg)) seems to work in the one test case you supplied us. It relies on the image paths always being within a string as the 'this is the start of the image path' delimiter and terminates at the extension so even if the string is unclosed should stop at an appropriate place.
Using the above, I eventually got to the following solution;
Find.find(app_folder, public_folder) do |path|
if !File.directory?(path)
&& !(path =~/\.\/app\/assets\/images/)
&& !(path =~ /\.DS_Store/)
&& !(path =~ /\.\/app\/assets\/fonts/)
asset_file = File.read(path)
image_asset = asset_file.scan(/ (?:['"|\s|#])([^'"|\s|#]+\.(?:png | jpe?g |gif | svg)) /xi).flatten
image_asset.each do |image_name|
assets_in_use << [path, File.basename(image_name)]
end
end
end

Rails 4.2 upgrade: Asset names passed to helpers should not include the "/assets/" prefix

I upgraded from Rails 4.1 to 4.2. I get the following error now:
Sprockets::Rails::Helper::AbsoluteAssetPathError at /
Asset names passed to helpers should not include the "/assets/" prefix. Instead of "/assets/spinner.gif", use "spinner.gif"
The error message is clear. However, I don't know what it's talking about. It highlights this line of code:
<div class="loading">
<%= image_tag asset_path('spinner.gif') %>
</div>
I do not use the literal string '/assets/' in that line of code. So what is this error referring to?
I was able to resolve that specific error by removing the call to asset_path and just using image_tag 'spinner.gif'; however, I still get the error right here (I am using Paperclip gem):
<%= image_tag current_user.avatar.url(:thumb) %>
caused by this:
ActionController::Base.helpers.asset_path('missing-user.png')
Again, it is complaining about asset_path.
UPDATE:
Error only occurs when I pass asset_path to image_tag method:
ActionController::Base.helpers.asset_path('missing-user.png')
=> "/assets/missing-user.png"
helper.image_tag(ActionController::Base.helpers.asset_path('missing-user.png'))
Sprockets::Rails::Helper::AbsoluteAssetPathError: Asset names passed to helpers should not include the "/assets/" prefix. Instead of "/assets/missing-user.png", use "missing-user.png"
image_tag will pass the source option to asset_path on its own:
image_tag("icon")
# => <img alt="Icon" src="/assets/icon" />
image_tag("icon.png")
# => <img alt="Icon" src="/assets/icon.png" />
image_tag("/icons/icon.gif", height: '32', width: '32')
# => <img alt="Icon" height="32" src="/icons/icon.gif" width="32" />
So when you call image_tag asset_path('spinner.gif') you're actually doing image_tag( '/assets/spinner.gif' ) which is why you get the sprockets warning.
I resolved the issue but I still don't understand the WHY factor. This only happens when I upgraded from Rails 4.1 to 4.2. Check this out:
ActionController::Base.helpers.asset_path('missing-user.png')
=> "/assets/missing-user.png"
helper.image_tag "/assets/missing-user.png"
Sprockets::Rails::Helper::AbsoluteAssetPathError: Asset names passed to helpers should not include the "/assets/" prefix. Instead of "/assets/missing-user.png", use "missing-user.png"
helper.image_tag "missing-user.png"
=> "<img src=\"/assets/missing-user.png\" alt=\"Missing user\" />"
Based on the above, image_tag does not want you to pass it the literal path string 'assets'. Consequently, in my Paperclip gem helper, I had to od this:
has_attached_file :avatar,
styles: { normal: "128x128>", thumb: "40x40>" },
default_style: :thumb,
default_url: ->(attachment) { 'missing-user.png' }
In other words, I had to remove this:
ActionController::Base.helpers.image_url('missing-user.png')
since image_url returns the string '/assets/missing-user.png'.

rails carrierwave + S3 + json response

I have a rails4 app that using carrierwave with S3 and cloudfront. I only have problem with the fallback image. When I'm using html response (<%= image_tag user.profile.avatar.url(:base_thumb), class: "profile-index-avatar" %>) with the helper everything works fine, but can't figure it out how to make it work with json response.
If I check out the html (built from json) in production on the root page the code is:
1st jbuilder: <img src="https://example.com/small_thumb_default.png">
2st jbuilder: <img src="https://example.com/assets/small_thumb_default.png">
None of these are working.
On the top of this if I go let's say to the users page then it tries to get pic like:
1st jbuilder: <img src="https://example.com/users/small_thumb_default.png">
2nd jbuilder: <img src="https://example.com/users/assets/small_thumb_default.png">.
What should I change?
jbuilder 1st version
json.array! #other_notifications do |notification|
..
json.profile_image_url notification.sender.profile.avatar.url(:small_thumb)
...
end
jbuilder 2nd version
json.array! #other_notifications do |notification|
..
if notification.sender.profile.avatar_url == "default.png"
json.profile_image_url "assets/small_thumb_default.png"
else
json.profile_image_url notification.sender.profile.avatar.url(:small_thumb)
end
...
end
uploader
process :resize_to_fit => [400, 400]
version :base_thumb do
process resize_to_fill: [85, 85]
end
version :small_thumb, :from_version => :base_thumb do
process :resize_to_fill => [40, 40]
end
def default_url
[version_name, "default.png"].compact.join('_')
end
Most likely, the file in question is inside app/assets/ folder, files inside that folder are being precompiled by default and a random digest is being added on the end of the filename. For the described behavior to work your small_thumb_default.png file should be placed inside public/ folder, so it doesn't get a digest appended on precompile. Either that or you should avoid using HTML, do it the Rails way:
# AVOID THIS
<img src="small_thumb_default.png"/>
#THIS IS PREFERABLE
<%= image_tag 'small_thumb_default.png' %>
This way you will get your view rendered with the precompiled filename.

Full url for an image-path in Rails 3

I have an Image, which contains carrierwave uploads:
Image.find(:first).image.url #=> "/uploads/image/4d90/display_foo.jpg"
In my view, I want to find the absolute url for this. Appending the root_url results in a double /.
root_url + image.url #=> http://localhost:3000//uploads/image/4d90/display_foo.jpg
I cannot use url_for (that I know of), because that either allows passing a path, or a list of options to identify the resource and the :only_path option. Since I do't have a resource that can be identified trough "controller"+"action" I cannot use the :only_path option.
url_for(image.url, :only_path => true) #=> wrong amount of parameters, 2 for 1
What would be the cleanest and best way to create a path into a full url in Rails3?
You can also set CarrierWave's asset_host configĀ setting like this:
# config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.storage = :file
config.asset_host = ActionController::Base.asset_host
end
This ^ tells CarrierWave to use your app's config.action_controller.asset_host setting, which can be defined in one of your config/envrionments/[environment].rb files. See here for more info.
Or set it explicitly:
config.asset_host = 'http://example.com'
Restart your app, and you're good to go - no helper methods required.
* I'm using Rails 3.2 and CarrierWave 0.7.1
try path method
Image.find(:first).image.path
UPD
request.host + Image.find(:first).image.url
and you can wrap it as a helper to DRY it forever
request.protocol + request.host_with_port + Image.find(:first).image.url
Another simple method to use is URI.parse, in your case would be
require 'uri'
(URI.parse(root_url) + image.url).to_s
and some examples:
1.9.2p320 :001 > require 'uri'
=> true
1.9.2p320 :002 > a = "http://asdf.com/hello"
=> "http://asdf.com/hello"
1.9.2p320 :003 > b = "/world/hello"
=> "/world/hello"
1.9.2p320 :004 > c = "world"
=> "world"
1.9.2p320 :005 > d = "http://asdf.com/ccc/bbb"
=> "http://asdf.com/ccc/bbb"
1.9.2p320 :006 > e = "http://newurl.com"
=> "http://newurl.com"
1.9.2p320 :007 > (URI.parse(a)+b).to_s
=> "http://asdf.com/world/hello"
1.9.2p320 :008 > (URI.parse(a)+c).to_s
=> "http://asdf.com/world"
1.9.2p320 :009 > (URI.parse(a)+d).to_s
=> "http://asdf.com/ccc/bbb"
1.9.2p320 :010 > (URI.parse(a)+e).to_s
=> "http://newurl.com"
Just taking floor's answer and providing the helper:
# Use with the same arguments as image_tag. Returns the same, except including
# a full path in the src URL. Useful for templates that will be rendered into
# emails etc.
def absolute_image_tag(*args)
raw(image_tag(*args).sub /src="(.*?)"/, "src=\"#{request.protocol}#{request.host_with_port}" + '\1"')
end
There's quite a bunch of answers here. However, I didn't like any of them since all of them rely on me to remember to explicitly add the port, protocol etc. I find this to be the most elegant way of doing this:
full_url = URI( root_url )
full_url.path = Image.first.image.url
# Or maybe you want a link to some asset, like I did:
# full_url.path = image_path("whatevar.jpg")
full_url.to_s
And what is the best thing about it is that we can easily change just one thing and no matter what thing that might be you always do it the same way. Say if you wanted to drop the protocol and and use the The Protocol-relative URL, do this before the final conversion to string.
full_url.scheme = nil
Yay, now I have a way of converting my asset image urls to protocol relative urls that I can use on a code snippet that others might want to add on their site and they'll work regardless of the protocol they use on their site (providing that your site supports either protocol).
I used default_url_options, because request is not available in mailer and avoided duplicating hostname in config.action_controller.asset_host if haven't specified it before.
config.asset_host = ActionDispatch::Http::URL.url_for(ActionMailer::Base.default_url_options)
You can't refer to request object in an email, so how about:
def image_url(*args)
raw(image_tag(*args).sub /src="(.*?)"/, "src=\"//#{ActionMailer::Base.default_url_options[:protocol]}#{ActionMailer::Base.default_url_options[:host]}" + '\1"')
end
You can actually easily get this done by
root_url[0..-2] + image.url
I agree it doesn't look too good, but gets the job done.. :)
I found this trick to avoid double slash:
URI.join(root_url, image.url)

In Rails, how to get current URL (but no paths)

If I'm in a URL such as
http://domain.example/mysite/bla
How can I request just the URL with no paths? Such as
http://domain.example
You can use this
<%= request.protocol + request.host_with_port %>
#=> https://domain.example:3000
<%= request.protocol + request.host %>
#=> https://domain.example
Starting from Rails 3.2 you can also use
<%= request.base_url %>
#=> https://domain.example:3000
request.host should do the trick, or:
request.port.blank? ? request.host : "#{request.host}: #{request.port}"
if you need to include the port too.
Try this
<%=request.scheme + '://' + request.host_with_port%>
If you want to see all available methods on request object then
<%=request.methods.sort%>
For protocol, domain and port
<%= "#{request.protocol + request.host}:#{request.port.to_s}" %>
Here's how you can get your current domain name.
Domain name
request.base_url
# prod: https://example.com
# dev: https://localhost:8000
Getting full path
request.original_url
# prod: https://example.com/path/
# dev: https://localhost:8000/path/
If your port could be anything other than 80 it should be included.
"#{request.protocol}#{request.host_with_port}"
I think this can be useful too, if you're not in a controller.
URI.join(url_for(only_path: false), '/').to_s

Resources