Ruby on Rails ActionMailer Images Issue - ruby-on-rails

I'm trying to use embedded images in my E-Mail, but if I try to load a file from my image folder as a header, it's not displaying in the email:
The image is an inline attachment:
def export_bill_email(user)
#user = user
attachments.inline["logo.jpg"] = File.read("#{Rails.root}/app/assets/images/bdh_caption_logo.jpg")
make_bootstrap_mail(
to: 'xxx',
from: 'xxx',
subject: 'xxx'
)
end
Then in my view, I try to call it the following way:
<%= image_tag(attachments["logo.jpg"].url, width: '100', height: '100') %>
Is it not displaying cause of development mode? I also tried forwarding with ngrok, but still, it's just displaying a broken image sign in my received email.
The strange thing is: If I use a direct hyperlink to an image, it is displayed so it has to do something with the image URL I guess, but I can't figure it out.
Thanks for any good advice!

Okay I got it working in production, I think the problem is that the image can't bei downloaded from localhost cause it's not publically accessible by the mail client. If I run it on my Webserver it's working fine.

Related

AWS QuickSight rails integration authorization code error

I have a rails application that needs to add QuickSight. Found that for these purposes it is necessary to use the get_dashboard_embed_url method. This method returns me the URL, but following it (manually, through an iframe tag) I get this error text
Embedding failed because of invalid URL or authorization code. Both of these must be valid and the authorization code must not be expired for embedding to work.
Where can I find the authenticate code? How can I get it? Thanks for your help
This is how i fetch the url
credential_options = {
client: Aws::STS::Client.new(region: ENV['AWS_REGION']),
role_arn: ENV['QUICK_SIGHT_ROLE_ARN'],
role_session_name: self.user_email
}
assume_role_credential = Aws::AssumeRoleCredentials.new(credential_options)
qs_client = Aws::QuickSight::Client.new({
credentials: assume_role_credential,
region: ENV['AWS_REGION']
})
begin
qs_client.register_user({
identity_type: 'IAM', # accepts IAM, QUICKSIGHT
email: self.user_email,
user_role: 'READER', # accepts ADMIN, AUTHOR, READER, RESTRICTED_AUTHOR, RESTRICTED_READER
iam_arn: ENV['QUICK_SIGHT_ROLE_ARN'],
session_name: self.user,
aws_account_id: ENV['AWS_ACCOUNT_ID'],
namespace: 'default'
})
rescue
end
options = {
aws_account_id: ENV['AWS_ACCOUNT_ID'],
dashboard_id: ENV['QUICK_SIGHT_DASHBOARD_ID'],
identity_type: 'IAM',
session_lifetime_in_minutes: 300,
undo_redo_disabled: false,
reset_disabled: false
}
qs_client.get_dashboard_embed_url(options, {}).embed_url
And how i try to display
iframe src=#url class='w-100 h-100' style='min-height: 500px;'
At the first, sorry for my weak english, but i hope that you'll understand what i mean
Ok, after completing these points, everything began to work for me. Also read "Underwater rocks", this is very important points list which will save you tons of time
Replace my code in question with this
def fetch_url # this method fetch embed dashboard url
credential_options = {
client: Aws::STS::Client.new(
region: ENV['AWS_REGION'],
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
),
role_arn: ENV['QUICK_SIGHT_ROLE_ARN'],
role_session_name: self.user_email # This is attr_accessor :user_email
}
assume_role_credential = Aws::AssumeRoleCredentials.new(credential_options)
qs_client = Aws::QuickSight::Client.new({
credentials: assume_role_credential,
region: ENV['AWS_REGION']
})
begin
qs_client.register_user({
identity_type: 'IAM', # accepts IAM, QUICKSIGHT
email: self.user_email,
user_role: 'READER', # accepts ADMIN, AUTHOR, READER, RESTRICTED_AUTHOR, RESTRICTED_READER
iam_arn: ENV['QUICK_SIGHT_ROLE_ARN'],
session_name: self.user_email,
aws_account_id: 'ENV['AWS_ACCOUNT_ID']',
namespace: 'default'
})
rescue
end
options = {
aws_account_id: ENV['AWS_ACCOUNT_ID'],
dashboard_id: ENV['QUICK_SIGHT_DASHBOARD_ID'],
identity_type: 'IAM',
session_lifetime_in_minutes: 300,
undo_redo_disabled: false,
reset_disabled: false
}
qs_client.get_dashboard_embed_url(options).embed_url
end
Go to Manage QuickSight panel https://your-quicksight-region(us-east-2 for example).quicksight.aws.amazon.com/sn/admin#users and click on "Manage permissions" button (button is placed above of the table with users)
On the new page click on "Create" button and select "Sharing dashboards" checkbox. Set the name of the permission, click on the "Create" button
In your controller action: #url = fetch_url # fetch_url - method from 1 point
Add to your view: iframe src=#url OR you can use a amazon-quicksight-embedding-sdk but for me the iframe works pretty well
Underwater rocks
Remember that dashboard url (which you are get with this method qs_client.get_dashboard_embed_url(options).embed_url) can be used only once, i.e. you can't open two browsers tabs with the same URL. When you are will pass this URL to iframe, this URL will cease to be working and you will no longer be able to use it in others browser windows or others iframe's
Add your app domain to whitelist domains on the QuickSight. You can do it in the Manage QuickSight panel https://your-quicksight-region.quicksight.aws.amazon.com/sn/admin#embedding
!!!IMPORTANT!!! if you are trying to embed dashboard to your localhost:your_server_port_number rails server, then you will always get the error message into the iframe (but if you go to this URL through the address bar of the browser, then you should see your dashboard (comment out / remove the iframe so it doesn't use the link, because every embedded dashboard url is disposable)). This is because localhost:your_server_port_number is not provided in the whitelist (Underwater rocks p.2). For resolving this issue and testing your work you can use ngrok (maybe it's available only for macOS, i'm not sure).
When you'll download the ngrok open your terminal and run command
$ ./path_to_ngrok_script/./ngrok http your_server_port_number
For me it's:
$ ~/./scripts/ngrok http 3000
After that do these 3 things for adding your work station to QuickSight whitelist:
In the terminal with ngrok copy generated domain which starts with
the https (i'll name it ngrok_domain), NOT WITH HTTP. For
example: https://047956358355.ngrok.io
Go to the Underwater rocks p.2 and add ngrok_domain
Open your browser and go to the path with iframe, but use ngrok_domain instead of localhost:3000. For example, your embedded dashboard path is localhost:3000/embed_dashboard. Change it to https://047956358355.ngrok.io/embed_dashboard
After all these steps all is start working for me. I'm sure that some of the points here are superfluous, but i'm really tired of working with this integration, so here you yourself decide what should be left and what should be removed.
I hope my answer helped at least someone

Direct link (no redirect) to files in ActiveStorage

Using url_for() on a file stored in active storage returns a url that leads to the application and then redirects to the actual location. Because of a bug in firefox with CORS, the redirect breaks my application.
Is there any way to get the direct link to the file with ActiveStorage?
You can do this
record.active_storage_object.blob.service_url
Found here https://github.com/rails/rails/blob/master/activestorage/app/controllers/active_storage/blobs_controller.rb
I had to dig through the rails source to create this so I have no idea how recommended it is but this works for disk storage at least.
ActiveStorage::Current.host = "yourhostname"
attachment_blob = ActiveStorage::Attachment.find_by(record_type: "YourModel", record_id: record.id).blob
direct_url = ActiveStorage::Blob.service.url(
attachment_blob.key,
expires_in: 20000,
disposition: "attachment",
filename: attachment_blob.filename,
content_type: attachment_blob.content_type
)
For me, rails_blob_url(#blog.pdf) (if you're trying to get the file stored as #blog.pdf) worked best.

Image is not shown in email MVC

I have a strange problem.
I need to send an e-mail from an MVC site. I have an html template for the email, which looks like this(the image part):
...
<img class="auto-style4" src="{PictureSrc}" /><br />
<img src="data:image/png;base64,{pictureBase64}">
....
From the controller I'm replacing the parameters like this:
case "PictureSrc":
string imagePath = "";
imagePath = "~/Images/email-logo.png";
//string base64 = Convert.ToBase64String(System.IO.File.ReadAllBytes(HttpContext.Server.MapPath(imagePath)));
//content = content.Replace("{pictureBase64}", base64);
content = content.Replace("{" + property + "}", HttpContext.Server.MapPath(imagePath));
break;
1.First I have tried to add the path for the image. This way works on my local machine, but not on the server where the live site is.
I've tried to add the URL for the image. WhenI have pasted the URL in to the browser, the image was shown, but in the sent email the image was not shown, not in my local machine, not on the server.
The interesting thing is that I'm sending these mails to outlook accounts. There the images are not shown, but if I send the mail to my yahoo account there the image is shown.
I've tried to convert image to base 64, as you can see on the code and replacing this way the image src. This way again the image was not shown, not on my local machine, not on the server side if I send the mail to outlook accounts. If I send the mail to a yahoo account, the mail is shown.
Can you please advise what can I try in order to resolve this problem?
I ran into this same issue with Outlook a few months ago. While researching, I learned that Outlook tends to strip emails of embedded images. I resolved it by using the CID technique. This technique consists of attaching the image to the email and referencing it in the email template with the image's CID.
First, you would need to get your image's CID. There are plenty of CID converters online to do this. Then, you just need to use the CID in the img src attribute of your template: <img src="cid:" + yourCID + "/>".
Note: this WILL increase the size of your email due to the image being attached.

How do I mask Facebook graph api URLs for pictures?

I'm trying to display Facebook profile pictures on my site, but don't want to leak the facebook id's of the people in the source.
For example, this URL: http://graph.facebook.com/4/picture will redirect to: http://profile.ak.fbcdn.net/hprofile-ak-snc4/157340_4_3955636_q.jpg when you load it in a browser. I'd like to get the 2nd url (CDN url) and use it as my img src since it doesn't show the facebook id in the url.
I'm doing this in Ruby on Rails at the moment and am curious if there's a better way that what I have done below:
def picture_square(facebook_id, secure=false)
raw_url = "http://graph.facebook.com/" facebook_id + "/picture?type=square"
if secure
binary_img = ''
open(raw_url) do |f|
binary_img = f.read
end
encoded_img = Base64.encode64(binary_img)
return 'data:image/jpg;base64,' + encoded_img.to_s
else
return raw_url
end
end
You could call this with the following HTML (using the above example):
<img src="<%= picture_square(4, true) %>"
This definitely works and uses the inline image properties to actually render the image, but it's a bit slow if you have a bunch of images that you're trying to load.
Is there a way in Ruby that I can get the redirected URL and just return that instead of trying to get the actual raw binary data and encode it to base64?
Make a call to the graph API with this url:
http://graph.facebook.com/4/?fields=picture&type=large
This will return the image you are looking for inside the json response. The other option would be to make an http request to the first url you posted and then inspect the HTTP headers to read the location header..

Uploading a file to Facebook using Koala on Ruby on Rails

I followed the following blogpost to figure out how to create Facebook events remotely using my app. I've been having problems loading the images from my app, however, because I do not have images stored locally on my app, they are stored in AWS.
#graph = Koala::Facebook::GraphAPI.new(#token)
picture = Koala::UploadableIO.new(#event.photo.url(:small))
params = {
:picture => picture,
:name => 'Event name',
:description => 'Event descriptio
:start_time => datetime,
}
is the following code I am currently using to send pictures to Facebook when Facebook events are created on my app. The problem is, however, that Rails is throwing the error: No such file or directory - http://s3.amazonaws.com/ColumbiaEventsApp/photos/21/small.jpeg?1312521889.
Does anybody who's more experienced with Rails development know if there is a way for me to treat a URL like a path to a file? The UploadableIO class expects a path to a file, and I'm struggling to figure out if there's a way in Ruby to treat URL's like filepaths. The way that photos stored on the app can be loaded to Facebook is as follows:
picture = Koala::UploadableIO.new(File.open("PATH TO YOUR EVENT IMAGE"))
if that helps.
I appreciate any new insights into this issue.
Ok so I played around and figured out how to post pictures.
Basically what I did was use the 'open-uri' library to convert the image links into file objects, which can then be passed to UploadableIO and sent to Facebook. This is the code that worked:
require 'open-uri'
OpenURI::Buffer.send :remove_const, 'StringMax' if OpenURI::Buffer.const_defined?('StringMax')
OpenURI::Buffer.const_set 'StringMax', 0
picture = Koala::UploadableIO.new(open(#event.photo.url(:small)).path, 'image')
params = {
picture: picture,
name: #event.name,
description: #event.description,
location: #event.location,
start_time: datetime
}
#graph.put_object('me', 'events', params )
The OpenURI constant StringMax needed to be changed because the image files I was using were small enough that the files were being processed as Strings rather than File Objects.
Hope this helps anyone trying to fix this!
With Koala 1.2.1 it's a very elegant solution. Here is sample code for creating an album and uploading to it from a remote, AWS link (btw this took about 30 lines in PHP w/ the PHP SDK!
#foo = Foo.find(params[:foo_id])
albuminfo = #graph.put_object('me','albums', :name=>#foo.title)
album_id = albuminfo["id"]
#graph.put_picture(#foo.remote_image_path,{}, album_id)
Facebook recently released an update that lets you post pictures using publicly accessible URLs (http://developers.facebook.com/blog/post/526/). The Koala library you're using supports that (https://github.com/arsduo/koala/blob/master/lib/koala/graph_api.rb#L102), so you should be able to post the pictures you're hosting on S3 without having to use OpenURI::Buffer.
For Facebook Ad Images, you unfortunately currently cannot do it by URL, thus:
require 'open-uri'
img_data = open(my_post.image.url :medium).read
img = graph.put_connections('act_X', 'adimages', bytes: Base64.encode64(img_data))

Resources