Rails - How to test that ActionMailer sent a specific attachment? - ruby-on-rails-3

In my ActionMailer::TestCase test, I'm expecting:
#expected.to = BuyadsproMailer.group_to(campaign.agency.users)
#expected.subject = "You submitted #{offer_log.total} worth of offers for #{offer_log.campaign.name} "
#expected.from = "BuyAds Pro <feedback#buyads.com>"
#expected.body = read_fixture('deliver_to_agency')
#expected.content_type = "multipart/mixed;\r\n boundary=\"something\""
#expected.attachments["#{offer_log.aws_key}.pdf"] = {
:mime_type => 'application/pdf',
:content => fake_pdf.body
}
and stub my mailer to get fake_pdf instead of a real PDF normally fetched from S3 so that I'm sure the bodies of the PDFs match.
However, I get this long error telling me that one email was expected but got a slightly different email:
<...Mime-Version: 1.0\r\nContent-Type: multipart/mixed\r\nContent-Transfer-Encoding: 7bit...> expected but was
<...Mime-Version: 1.0\r\nContent-Type: multipart/mixed;\r\n boundary=\"--==_mimepart_50f06fa9c06e1_118dd3fd552035ae03352b\";\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit...>
I'm not matching the charset or part-boundary of the generated email.
How do I define or stub this aspect of my expected emails?

Here's an example that I copied from my rspec test of a specific attachment, hope that it helps (mail can be creating by calling your mailer method or peeking at the deliveries array after calling .deliver):
mail.attachments.should have(1).attachment
attachment = mail.attachments[0]
attachment.should be_a_kind_of(Mail::Part)
attachment.content_type.should be_start_with('application/ics;')
attachment.filename.should == 'event.ics'

I had something similar where I wanted to check an attached csv's content. I needed something like this because it looks like \r got inserted for newlines:
expect(mail.attachments.first.body.encoded.gsub(/\r/, '')).to(
eq(
<<~CSV
"Foo","Bar"
"1","2"
CSV
)
)

Related

Property Photo Files with PHRETS v2

My php code, below, attemps to download all the photos for a property listing. It successfully queries the RETS server, and creates a file for each photo, but the file does not seem to be a functional image. (MATRIX requires files to be downloaded, instead of URLs.)
The list of photos below suggests that it successfully queries one listing id (47030752) for all photos that exist, (20 photos in this case). In a web browser, the files appear only as a small white square on a black background: e.g. (https://photos.atlantarealestate-homes.com/photos/PHOTO-47030752-9.jpg). The file size (4) also seems to be very low, as compared to that of a real photo.
du -s PHOTO*
4 PHOTO-47030752-10.jpg
4 PHOTO-47030752-11.jpg
4 PHOTO-47030752-12.jpg
4 PHOTO-47030752-13.jpg
4 PHOTO-47030752-14.jpg
4 PHOTO-47030752-15.jpg
4 PHOTO-47030752-16.jpg
4 PHOTO-47030752-17.jpg
4 PHOTO-47030752-18.jpg
4 PHOTO-47030752-19.jpg
4 PHOTO-47030752-1.jpg
4 PHOTO-47030752-20.jpg
4 PHOTO-47030752-2.jpg
4 PHOTO-47030752-3.jpg
4 PHOTO-47030752-4.jpg
4 PHOTO-47030752-5.jpg
4 PHOTO-47030752-6.jpg
4 PHOTO-47030752-7.jpg
4 PHOTO-47030752-8.jpg
4 PHOTO-47030752-9.jpg
script I'm using:
#!/usr/bin/php
<?php
date_default_timezone_set('this/area');
require_once("composer/vendor/autoload.php");
$config = new \PHRETS\Configuration;
$config->setLoginUrl('https://myurl/login.ashx')
->setUsername('myser')
->setPassword('mypass')
->setRetsVersion('1.7.2');
$rets = new \PHRETS\Session($config);
$connect = $rets->Login();
$system = $rets->GetSystemMetadata();
$resources = $system->getResources();
$classes = $resources->first()->getClasses();
$classes = $rets->GetClassesMetadata('Property');
$host="localhost";
$user="db_user";
$password="db_pass";
$dbname="db_name";
$tablename="db_table";
$link=mysqli_connect ($host, $user, $password, $dbname);
$query="select mlsno, matrix_unique_id, photomodificationtimestamp from fmls_homes left join fmls_images on (matrix_unique_id=mls_no and photonum='1') where photomodificationtimestamp <> last_update or last_update is null limit 1";
print ("$query\n");
$result= mysqli_query ($link, $query);
$num_rows = mysqli_num_rows($result);
print "Fetching Images for $num_rows Homes\n";
while ($Row= mysqli_fetch_array ($result)) {
$matrix_unique_id="$Row[matrix_unique_id]";
$objects = $rets->GetObject('Property', 'LargePhoto', $matrix_unique_id);
foreach ($objects as $object) {
// does this represent some kind of error
$object->isError();
$object->getError(); // returns a \PHRETS\Models\RETSError
// get the record ID associated with this object
$object->getContentId();
// get the sequence number of this object relative to the others with the same ContentId
$object->getObjectId();
// get the object's Content-Type value
$object->getContentType();
// get the description of the object
$object->getContentDescription();
// get the sub-description of the object
$object->getContentSubDescription();
// get the object's binary data
$object->getContent();
// get the size of the object's data
$object->getSize();
// does this object represent the primary object in the set
$object->isPreferred();
// when requesting URLs, access the URL given back
$object->getLocation();
// use the given URL and make it look like the RETS server gave the object directly
$object->setContent(file_get_contents($object->getLocation()));
$listing = $object->getContentId();
$number = $object->getObjectId();
$url = $object->getLocation();
//$photo = $object->getContent();
$size = $object->getSize();
$desc = $object->getContentDescription();
if ($number >= '1') {
file_put_contents("/bigdirs/fmls_pics/PHOTO-{$listing}-{$number}.jpg", "$object->getContent();");
print "$listing - $number - $size $desc\n";
} //end if
} //end foreach
} //end while
mysqli_close ($link);
fclose($f);
php?>
Are there any suggested changes to capture photos into the created files? This command creates the photo files:
file_put_contents("/bigdirs/fmls_pics/PHOTO-{$listing}-{$number}.jpg", "$object->getContent();");
There may be some parts of this script that wouldn't work in live production, but are sufficient for testing. This script seems to successfully query for the information needed from the RETS server. The problem is just simply that the actual files created do not seem to be functional photos.
Thanks in Advance! :)
Your code sample is a mix of the official documentation and a usable implementation. The problem is with this line:
$object->setContent(file_get_contents($object->getLocation()));
You should completely take that out. That's actually overriding the image you downloaded with nothing before you get a chance to save the contents to a file. With that removed, it should work as expected.

How to attach images in mailer from active storage association in Rails

In rails 5.2, I have a model using has_many_attached :images. I would like to send out an email that includes all associated images as attachments.
My mailer method currently looks like:
def discrepancy_alert(asset_discrepancy_id, options={})
#asset_discrepancy = AssetDiscrepancy.find asset_discrepancy_id
#asset_discrepancy.images.each_with_index do |img,i|
attachments["img_#{ i }"] = File.read(img)
end
mail to: 'noone#gmail.com', subject: "email subject"
end
obviously, File.read does not work here because img is not a path, it is a blob. I have not been able to find any info on this in the docs
Question One:
Is there a rails method for attaching a blob like this?
I can use the following instead:
#asset_discrepancy.images.each_with_index do |img,i|
attachments["img_#{ i }"] = img.blob.download
end
Question Two:
the download method could use a log of RAM, is this usage ill advised?
It seems, with the addition of ActiveStorage, that rails mailers would have some new methods for interaction between the two....I have not seen anything in the docs. All the mailer attachments[] examples use paths to a local file.
in app/mailers/mailer.rb:
if #content.image.attached?
#filename = object.id.to_s + object.image.filename.extension_with_delimiter
if ActiveStorage::Blob.service.respond_to?(:path_for)
attachments.inline[#filename] = File.read(ActiveStorage::Blob.service.send(:path_for, object.image.key))
elsif ActiveStorage::Blob.service.respond_to?(:download)
attachments.inline[#filename] = object.image.download
end
end
in mailer view:
if #filename
image_tag(attachments[#filename].url)
else
image_tag(attachments['placeholder.png'].url)
end
This worked for me in production using Amazon S3.
in mailer view:
if #object.images
#object.images.each do |image|
path = "https://www.example.com" + Rails.application.routes.url_helpers.rails_blob_path(image, only_path: true)
<img src="<%=path%>">
end
end
Here is the working solution for active storage url in email template. I have seen the images visible in gmail. You can use "rails_blob_url". This works for file stored in aws s3.
mailer.rb
....
#image_url = Rails.application.routes.url_helpers.rails_blob_url(blob),
....
mailer view file
<img src="<%= #image_url %>">

Yii + Zend gdata. Youtube upload

I want to upload videos with next way:
I just upload file to server (as usual)
My server-side Yii-application takes that video and uploads it on Youtube from a special account on youTube
What do i have:
My YouTube (google) account name and email. "name" or "name#gmail.com"
My password
A developer Key, which I found in Google's "Product Dashboard"
A name of the application, which names 'myapp':
Product Dashboard: myapp
So, I read some docs in google and decided that best way for me is to use ClientLogin auth type, because I have only one account to use and I have all necessary data. I found an example for ZendFramework's GData and I imported it into my Yii application.
I specially simplified the code just to upload one single video from /upload directory to test that it works. I expect to find a video in my YT account uploaded. Of course there is no video and here I am :-) Complete code of the action is below:
Yii::import('application.vendors.*');
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_YouTube');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
$yt_user = 'myYTname';
$yt_pass = 'myYTpass';
$yt_source = 'myapp';
$yt_api_key = 'veryVERYlongKEYhere';
$authenticationURL= 'https://www.google.com/accounts/ClientLogin';
$httpClient = Zend_Gdata_ClientLogin::getHttpClient(
$username = $yt_user,
$password = $yt_pass,
$service = 'youtube',
$client = null,
$source = $yt_source,
$loginToken = null,
$loginCaptcha = null,
$authenticationURL
);
$yt = new Zend_Gdata_YouTube($httpClient, $yt_source, null, $yt_api_key);
$myVideoEntry = new Zend_Gdata_YouTube_VideoEntry();
$filesource = $yt->newMediaFileSource(Yii::getpathOfAlias('webroot').'/upload/videos/video.mp4');
$filesource->setContentType('video/mp4');
$filesource->setSlug('video.mp4');
$myVideoEntry->setMediaSource($filesource);
$myVideoEntry->setVideoTitle('My Test Movie');
$myVideoEntry->setVideoDescription('My Test Movie description');
$myVideoEntry->setVideoCategory('Autos');
$myVideoEntry->SetVideoTags('cars, funny');
$myVideoEntry->setVideoDeveloperTags(array('mydevtag', 'anotherdevtag'));
$uploadUrl = "http://uploads.gdata.youtube.com/feeds/api/users/{$yt_user}/uploads";
try {
$newEntry = $yt->insertEntry($myVideoEntry, $uploadUrl, 'Zend_Gdata_YouTube_VideoEntry');
} catch (Zend_Gdata_App_HttpException $httpException) {
echo $httpException->getRawResponseBody();
} catch (Zend_Gdata_App_Exception $e) {
echo $e->getMessage();
}
As you can see, there is a lot of default code from the official example. But it doesn't work. Noone echo shows me information. But when I deleted try-catch, I got an error:
Zend_Gdata_App_HttpException
Read timed out after 10 seconds
So, this problem is solved by myself :)
First of all: don't try to upload from localhost!
Then in my case I got an error, that I didn't say my dev-key! So, if you got the same error, try to change this:
$newEntry = $yt->insertEntry($myVideoEntry, $uploadUrl, 'Zend_Gdata_YouTube_VideoEntry');
by adding the 4th parameter - extra headers:
$yt->insertEntry($myVideoEntry, $uploadUrl, 'Zend_Gdata_YouTube_VideoEntry', array(
'X-GData-Key' => 'key=yourBIGbigBIGdeveloperKEYhere'
));
Good luck and have fun with youtube API!

Ruby on Rails - string to array weird formatting in email parsing

I can get the body of an email in String format like so
body = params[:plain]
And when I output it, it looks like:
Hi there.
--
John B.
Sent from my iPhone.
Now, when I try and split by newline body.split("\n") I get:
---
- ! 'Hi there.'
- ''
- ! '-- '
- John B.
- ''
- Sent from my iPhone.
I don't really understand the extra hyphens and bangs. Any thoughts?
Also if I do body[2] I get --, but body.index("--") returns me nothing.
UPDATE
In my ReceivingMails controller:
...
def create
body = params[:plain]
parsed_body = parse_body(body)
Comment.new(:content => parsed_body)
end
private
def parse_body(body)
split = body.split("\n")
sig_index = split.index("-- ")
return split[0, sig_index].join("\n")
end
In my view, comments are shown as: <%= simple_format(comment.content)%>
UPDATE 2
When I do something like, body.split("\n").to_s I get what the expected array should look like (as String): ["Hi there. ", "", "-- ", "John B.", "", "Sent from my iPhone."]
I don't think params[:plain] is actually a string - I think you should test it to find out what it actually is. For example try:
puts params[:plain].class

Error while inserting image in table using Prawn

I am working with Prawn to generate a pdf, I have to insert an image in a cell of a table.
My code is like this:
image = "path to file"
subject = [["FORMATIVE I "," SUMATIVE ","GRAPH"],
[formative_1,sumative, {:image => image}]
]
table subject
But, I get an error which says:
prawn/table/cell.rb:127:in `make': Content type not recognized: nil (ArgumentError)
How can I resolve this? Any help is greatly appreciated.
Cheers!
In the current version of Prawn 0.12.0 it is not possible to embed images in a Prawn::Table, but this feature seems to be under way, see here. At the moment you have to write your own table, something like
data = [[{:image => "red.png"},{:text => "Red"}],
[{:image => "blue.png"},{:text => "Blue"}]]
data.each_with_index do |row,i|
row.each_with_index do |cell,j|
bounding_box [x_pos,y_pos], :width => cell_width, :height => cell_height do
image(cell[:image], ...) if cell[:image].present?
text_box(cell[:text], ...) if cell[:text].present?
end
x_pos = (x_pos + cell_width)
end
y_pos = (y_pos - cell_height)
end
Prawn in version 0.12.0 doesn't give the possibility to insert image in a cell. Look at this for further information. It works on the next version 1.0.0.rc1. Just change your version. You can also use the tricky way, but I advise you not to do so.
The manual is available here.
The commit and explanation for that feature from the author. Here