Skip to content

Instantly share code, notes, and snippets.

@nunosilva800
Last active September 28, 2017 12:35
Show Gist options
  • Save nunosilva800/3abdb11751eeb5d661af33897aabf127 to your computer and use it in GitHub Desktop.
Save nunosilva800/3abdb11751eeb5d661af33897aabf127 to your computer and use it in GitHub Desktop.
A Widget on Rails

This is an example of how to implement a "widget" with Ruby on Rails.

The widget is added to a webpage with the example on test_widget.html.erb :

<div id="my-widget"></div>
<script src="https://my-domain.com/widget.js" type="text/javascript"></script>

This will request the JS code from the server, ensuring you can change it without having to update the webpage were the widget is.

The JS code from the server will load necessary dependency and create the iframe where the content will be placed.

The iframe's url point to the server that will respond with the desired HTML.

# app/config/routes.rb
Rails.application.routes.draw do
#...
get 'widget', to: 'widgets#widget'
get 'test_widget', to: 'widgets#test_widget'
#...
end
<!-- app/views/widgets/test_widget.html.erb -->
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
</head>
<body>
<div id='wrapper' style="width:400px; height: 600px; margin:75px; background-color:yellow">
<div id="my-widget"></div>
<script src="<%= root_url %>widget.js" type="text/javascript"></script>
</div>
</body>
</html>
<!-- app/views/widgets/widget.html.erb -->
<div class="widget-container">
Hello world, it's: <%= Time.current %>.
</div>
// app/views/widgets/widget.js
var MyWidgetJS = {
getScript: function(url, success) {
var done, head, script;
script = document.createElement('script');
script.src = url;
head = document.getElementsByTagName('head')[0];
done = false;
script.onload = script.onreadystatechange = function() {
if (!done && (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete')) {
done = true;
success();
script.onload = script.onreadystatechange = null;
return head.removeChild(script);
}
};
return head.appendChild(script);
},
load: function() {
var $elem, $iframe;
$elem = $('#my-widget');
var url = "<%= widget_url %>";
if ($elem.length > 0) {
$elem.empty();
$iframe = $('<iframe>').attr('src', url)
.attr('frameborder', '0')
.attr('id', 'widget-iframe')
.attr('allowtransparency', 'true');
return $elem.append($iframe);
}
},
};
if (typeof jQuery === 'undefined') {
MyWidgetJS.getScript('//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', function() {
return MyWidgetJS.load();
});
} else {
MyWidgetJS.load();
}
<!-- app/views/layouts/widget_layout.html.erb -->
<!DOCTYPE html>
<html>
<head>
<title>My Widget</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<%# stylesheet_link_tag 'widget', media: 'all' %> <!-- Have custom CSS? -->
</head>
<body>
<%= yield %>
</body>
</html>
#app/controllers/widgets_controller.rb
class WidgetsController < ApplicationController
skip_before_filter :verify_authenticity_token
after_action :allow_iframe
layout 'widget'
def widget
respond_to do |format|
format.html do
# load data to show in the view
# @data = ...
render :widget
end
format.js do
render :widget
end
end
end
def test_widget
render :test_widget, layout: false
end
private
def allow_iframe
response.headers.except! 'X-Frame-Options'
end
def get_rumours
if params[:id]
Rumour.displayed.where(id: params[:id])
else
Rails.cache.fetch('rumours_for_widget', expires_in: 5.minutes) do
Rumour.order(timestamp: :desc).displayed.limit(5)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment