Google Visualization not appearing in heroku production - ruby-on-rails-3

I have implemented the google_visualr gem and it works perfectly in development. However when I push to heroku the visualization does not show up. All the javascript is present and there is no error or indication in the app logs.
Here is the javascript that is generated. It's exactly the same as dev. Do i have to do anything additional to get the google visualization to run in heroku environment?
<script type='text/javascript'>
google.load('visualization','1', {packages: ['corechart'], callback: function() {
var data_table = new google.visualization.DataTable();data_table.addColumn('string', 'Status');data_table.addColumn('number', 'Count');data_table.addRow([{v: 'Started Applications'}, {v: 10}]);data_table.addRow([{v: 'Completed Applications'}, {v: 1}]);
var chart = new google.visualization.PieChart(document.getElementById('pie_chart'));
chart.draw(data_table, {width: 360, height: 240, title: 'Applications Status Summary', is3D: true, legend: 'bottom'});
}});
</script>

I found the problem was that my call to the google jsapi was not secure so the browser was blocking the request.
<script src='http://www.google.com/jsapi'></script>
I was able to fix this by requesting the jsapi in secure mode using https
<script src='https://www.google.com/jsapi'></script>

There is nothing additional to be done to get the visualizations to work on Heroku.
The demo site is hosted on Heroku too: http://googlevisualr.herokuapp.com/examples/interactive/pie_chart
Just to check, is this in the head tag, at the top of the page?
<script src='http://www.google.com/jsapi'></script>

Related

How do I load Sentry before the main JS bundle loads?

I use Sentry to track client-side errors. However, I loaded my web app in the Edge browser today only to find a blank page. Edge raised a TextEncoder is not defined error because one of the libraries in my bundle referenced TextEncoder which it does not support. Sentry did not report the error because the error occurred before Sentry was initialized.
I use vue-cli to create a Vue project with Sentry being initialized near the top of the main file:
import { init } from '#sentry/browser';
import { environment } from '#/constants';
import { Vue as VueIntegration } from '#sentry/integrations';
export default function(Vue) {
const debug = environment !== 'production';
init({
dsn: 'redacted',
environment,
debug,
integrations: [new VueIntegration({ Vue, logErrors: debug })],
});
}
I've been thinking of initializing Sentry manually with a script tag near the start of the <body> tag. However, the fact that I use the VueIntegration plugin complicates things. Would it be safe to initialize Sentry twice? Once before the main bundle loads and once as I'm doing in the example above?
I noticed there's something in the docs about managing multiple Sentry clients but I'm not sure if that's relevant to my specific case.
One idea I have is just a barebones window.onerror hook before anything else loads but I'm not really sure how to interact with Sentry without pulling in their #sentry/browser package. Ideally I would just communicate with their service using a simple XHR request and my DSN.
My question is what is the recommended way to track errors that occur before Sentry is initialized in the main JS bundle?
I ended up solving it by adding a barebones window.onerror hook that loads inline before the main bundle arrives. The error is immediately sent to our API and then to our Slack #alerts channel. I added rate limiting so people dont abuse it (too much).
index.html (generated by vue-cli except for the new script tag):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
/>
<title>App title</title>
</head>
<body>
<script>
// This gives us basic error tracking until the main app bundle loads and
// initializes Sentry. Allows us to catch errors that would surface before
// Sentry has a chance to catch them like Edge's `TextEncoder is not defined`.
(function() {
function sendBasicClientError(message, error) {
var xhr = new XMLHttpRequest();
var domain =
window.location.hostname === 'localhost'
? 'http://localhost:5000'
: 'https://example.com';
xhr.open('POST', domain + '/api/v1/basic_client_errors');
xhr.setRequestHeader(
'Content-Type',
'application/vnd.api+json; charset=utf-8'
);
xhr.send(
JSON.stringify({
data: {
type: 'basic_client_error',
attributes: {
error_message: 'Init error: ' + message + ' ' + navigator.userAgent,
error: error
? JSON.parse(
JSON.stringify(error, Object.getOwnPropertyNames(error))
)
: null,
},
},
})
);
}
window.onerror = function(message, filename, lineno, colno, error) {
sendBasicClientError(
message + ' ' + filename + ':' + lineno + ':' + colno,
error
);
};
})();
</script>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
Right before Sentry loads we clear the hook:
// Clears the simple `window.onerror` from `index.html` so that Sentry can
// take over now that it's ready.
window.onerror = () => {};
init({
dsn: 'redacted',
environment,
debug,
integrations: [new VueIntegration({ Vue, logErrors: debug })],
});
Rails controller:
module Api
module V1
class BasicClientErrorsController < ApplicationController
def create
# Can comment out if not using the `pundit` gem.
skip_authorization
# We use `sidekiq` and `slack-ruby-client` gems here.
# Substitute whatever internal error tracking tool you use.
SlackNotifierWorker.perform_async(
basic_client_error_params[:error_message],
'#alerts'
)
head :accepted
end
private
def basic_client_error_params
# We use the `restful-jsonapi` gem to parse the JSON:API format.
restify_param(:basic_client_error).require(:basic_client_error).permit(
:error_message
)
end
end
end
end
Rate limiting with the rack-attack gem:
Rack::Attack.throttle('limit public basic client errors endpoint', limit: 1, period: 60.seconds.to_i) do |req|
req.ip if req.path.end_with?('/basic_client_errors') && req.post?
end
Have you tried this Laxy loading Sentry ?
It's mentioned here that if you set data-lazy to no, or use forceLoad, it'll try to fetch Sentry SDK as soon as possible.
This issue should be handled by the loader, as mentioned here :
Current limitations
Because we inject our SDK asynchronously, we will only monitor global errors and unhandled promise for you until the SDK is fully loaded. That means that we might miss breadcrumbs during the download.
For example, a user clicking on a button on your website is making an XHR request. We will not miss any errors, only breadcrumbs and only up until the SDK is fully loaded. You can reduce this time by manually calling forceLoad or set data-lazy="no".

Apps Script webapp: how to authenticate bigquery?

I am trying to get my apps script webapp to execute as "user accessing the webapp", but its bigquery should run as me, the developer. (If I run the webapp as me, everything works...) I looked at the documentation at https://developers.google.com/bigquery/docs/authorization. There is no apps script example, so I tried to get the javascript example working.
<html>
<head>
<script src="https://apis.google.com/js/client.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
function auth() {
gapi.auth.authorize(config, function() {
gapi.client.load('bigquery', 'v2');
$('#client_initiated').html('BigQuery client authorized');
$('#auth_button').fadeOut();
$('#dataset_button').fadeIn();
});
}
// User Submitted Variables
var projectNumber = 'XXXXXXXXXX';
var clientId = 'XXXXXXXXXX.apps.googleusercontent.com';
var config = {
'client_id': clientId,
'scope': 'https://www.googleapis.com/auth/bigquery'
};
function listDatasets() {
var request = gapi.client.bigquery.datasets.list({
'projectId':projectNumber
});
request.execute(function(response) {
$('#result_box').html(JSON.stringify(response.result.datasets, null));
});
}
</script>
</head>
<body>
<button id="auth_button" onclick="auth();">Authorize</button>
<div id="client_initiated"></div>
<button id="dataset_button" style="display:none;" onclick="listDatasets();">Show datasets</button>
<div id="result_box"></div>
</body>
</html>
I generated a client id as a browser app with https://script.google.com as the server address. With the code above, I get this error: Cannot read property 'authorize_m___' of undefined.
My question is twofold: 1) Would an apps script webapp authenticate in the same way as the javascript app authenticates? I.e. can I use that code as a guide for my apps script?
And 2) any suggestions about how to debug the javascript sample code? Note that I ran this code as an apps script webapp.... That is probably an error....
The answer... or workaround answer is given here: How to pass parameters from one Google-Apps-Script to another and execute?
I can use two stage authentication in place of direct authentication: the user logs in as him/herself, I get the user's name to find their files, then switch to a webapp that uses BigQuery and execs as me, the developer.
A good workaround for advanced services authentication under apps scripts....

blueimp Basic Plugin: Not uploading in IE, all versions

I am using the blueimp fileupload basic plugin in my project. It all works well in Safari, Firefox, Chrome but there is a problem with Internet Explorer 9 and below:
The start callback gets called and in the network tab of developer tools I see the ajax call being executed. However the file is never being upload (I checked on the server, too) and the call eventually ends up in a 408 request timeout.
Any hints on what could be the reason?
Here are my relevant code parts:
<input class="input-file" id="fileupload" name="files[]" data-url="/app_dev.php/backend/ajax/upload/wish/1850cf918a43d42" type="file">
<script type="text/javascript" src="js/jquery/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="js/uploader/vendor/jquery.ui.widget.js"></script>
<script type="text/javascript" src="js/uploader/jquery.fileupload.js"></script>
<script type="text/javascript" src="js/uploader/jquery.iframe-transport.js"></script>
<script>
$(document).ready(function() {
$('#fileupload').fileupload({
dataType: 'json',
dropZone: null,
start: function (e, data){
console.log('start'); //fires in all browsers = fine
},
progress: function (e, data){
console.log('progress'); //fires in Safari, FF, Chrome = fine
},
done: function (e, data) {
console.log('done'); //never getting here in IE cause file doesn't get uploaded.
}
});
</script>
Problem fixed!
There were two issues. One had to do with local network settings.
The other was to implement the correct handling of content type negotiation. See https://github.com/blueimp/jQuery-File-Upload/wiki/Setup for more details.
Just my 5 ยข:
I had a very hard time trying to make it work with pretty links! Following dumps were totally empty!
var_dump($_FILES);
var_dump($_POST);
var_dump($_GET);
So:
$('#fileupload').fileupload({
url: 'http://code.dev/products/postUpload' // <--- remove trailing slash!!!
});

Google web fonts and SSL error

My site is working well with Google webfonts UNTIL the user hits the SSL portion of the site.
At that point, chrome throws the partial encoding error, and my cufon menu losses it's kerning.
I'm including my webfont with this css:
#font-face {
src: local('Lusitana'), url(https://themes.googleusercontent.com/static/fonts/lusitana
/v1/tAIvAkRzqMJf8Y4fM1R7PXYhjbSpvc47ee6xR_80Hnw.woff) format('woff');
}
My js console then gives me this error:
[blocked] The page at https://domain.com/ecommerce.php ran insecure content from
http://fonts.googleapis.com/css?family=Lusitana:regular,700&subset=latin.
Any ideas how I can get google fonts to force SSL?
Have you tried replacing https:// with // in the url? The request should use the correct protocol automatically.
locate this line on your HTML page (or template):
<link href='http://fonts.googleapis.com/css?family=Dosis:400,700' rel='stylesheet' type='text/css'>
and change it to this:
<link href='//fonts.googleapis.com/css?family=Dosis:400,700' rel='stylesheet' type='text/css'>
This simple change will make your browser call the Google Font page in the applicable mode (HTTP vs HTTPS).
Enjoy!
To load google fonts that will work in non-secure, and SSL mode, try the following in your page header - (and remove what you've got there calling a https:// inside the CSS):
<script type="text/javascript">
WebFontConfig = { google: { families: [ 'Droid+Serif::latin' ] } };
(function() {
var wf = document.createElement('script');
wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
'://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
</script>
In my example, I'm using Droid Serif font, so swap that with yours.
You can read more on this here.
I also had this error caused by a theme in WordPress. It caused slow page loading and the following error reported by development console:
Mixed Content: The page at 'https://xxxxxxx.co.uk/' was loaded over HTTPS, but requested an insecure stylesheet 'http://fonts.googleapis.com/css?
family=Droid+Serif%3A400%2C700%2C400italic%2C700italic&ver=5.4.1'. This
request has been blocked; the content must be served over HTTPS.
The culprit was Wordpress theme called "Fresh and Clean". It inherits code written in 2014 which contains 'pre-SSL' coding practices
To resolve the problem all need to do is make changes inside the following file in the theme:
/wp-content/themes/wpex-freshandclean/functions/scripts.php
Look inside for any occurences of http:// and change each one to https://

Streaming Video - jwplayer, amazon s3 and cloudfront

I have a streaming distribution at s6b99lczhnef6.cloudfront.net on Amazon. The origin is a bucket in S3. The bucket has a video video.mp4. It's public.
I am trying to test streaming this video with jwplayer, following is the code:
<html>
<head>
<script type="text/javascript" src="jwplayer/jwplayer.js"></script>
</head>
<body>
<div id="container">Loading the player ...</div>
<script type="text/javascript">
jwplayer("container").setup({
flashplayer: "jwplayer/player.swf",
file: "video.mp4",
height: 270,
provider: "rtmp",
streamer: "rtmp://s6b99lczhnef6.cloudfront.net/cfx/st",
width: 480
});
</script>
</body>
</html>
The video is not playing. There are no JS errors. What could be going wrong?
The amazon documentation is valid for JW Player 5.9, and JW Player's documentation is fairly sparse on using CloudFront streaming. As briefly explained here, specifying the streaming source has changed with JW Player 6. This is the new way to specify a streaming source:
<div id='mediaplayer'>This text will be replaced</div>
<script type="text/javascript">
jwplayer('mediaplayer').setup({
'id': 'playerID',
'width': '720',
'height': '480',
'file': 'rtmp://s1cxpk7od1m10r.cloudfront.net/cfx/st/your_streaming_file.mp4',
'primary':'flash',
'autostart' : 'true',
});
</script>
If your stream is in the folder, you might have some issues using the file reference above. I'm not sure why rtmp://s1cxpk7od1m10r.cloudfront.net/cfx/st/folder/your_streaming_file.mp4 wouldn't work for me (I think it has something to do with URL encoding), however using this for the file param when accessing a streaming resource located in a folder worked for me:
rtmp://s1cxpk7od1m10r.cloudfront.net/cfx/st/mp4:folder/your_streaming_file.mp4
If you want to test your connection string and get some debugging output, checkout this streaming diagnostic tool.
You do not need to specify a bucketname anywhere in the embed code.
I think you have to give file string value as bucketname/video.mp4 else all seems fine.
No, that is not correct because he is using CloudFront.
I see in-consequent use of quotes. Try this:
<div id="container">Loading the player ...</div>
<script type="text/javascript">
jwplayer("container").setup({
'flashplayer': 'jwplayer/player.swf',
'file': 'video.mp4',
'height': '270',
'provider': 'rtmp',
'streamer': 'rtmp://s6b99lczhnef6.cloudfront.net/cfx/st',
'width': '480'
});
</script>
Here is a tutorial that explains the formatting and options in great detail.
http://www.miracletutorials.com/embed-streaming-video-audio-with-html5-fallback/
If that does not work, it is possible your video is not optimized for streaming.
Try out this tutorial to convert your video:
http://www.miracletutorials.com/how-to-encode-video-for-web-iphone-ipad-ipod/
I hope this helps?
No, you do not need to provide a bucketname. The cloudfront distribution already points to a bucket.
Loading the HTML page from a server other than 'localhost' works.