SlideShare a Scribd company logo
Functional widgets in Rails

        Sebastian Sito
Co to jest widget?

  mała aplikacja wbudowana w stronę
  WWW
  może być funkcjonalna lub statyczna
Przykład?

 AlleWidget
 Google Gadgets
 Facebook like buttons
Na początek statyczny content

<script type="text/javascript"
  src="http://hostapp.com/api/widget/main"></script>
Uwaga na Operę!

<script type="text/javascript"
  src="http://hostapp.com/api/widget/main.js"></script>
Po stronie aplikacji

app/controllers/widget_controller.rb

class Api::WidgetController < ApplicationController
   layout :nil
   def main
     respond_to do |format|
        format.js
     end
   end
end
Po stronie aplikacji

app/views/api/widget/main.js.erb

document.write('<div id="widget">');
<%= @title %>
document.write('</div>');
Personalizacja widgetu

app/controllers/widget_controller.rb

class Api::WidgetController < ApplicationController
   layout :nil
   before_filter :validate_api_key
   def main
     respond_to do |format|
        format.js
     end
   end
end
Personalizacja widgetu

config/routes.rb
namespace :api do
  match '/widget/:action/:api_key',
     :controller => 'widget',
     :api_key => /.*/
end

app/controllers/api/widget_controller.rb
def validate_api_key
  render :text => 'Invalid API key'
     unless params[:api_key] and return
  render :text => 'Wrong API credentials'
     if not User.find_by_key(params[:api_key])
     and return
end
Personalizacja widgetu

<script type="text/javascript">
  var __apiKey = "qcg35cgwhojpm839v5";
</script>
<script type="text/javascript"
  src="http://hostapp.com/api/widget/main"></script>
Widget funkcjonalny




Mamy problem: aplikacja i widget to dwie różne domeny!
JSONP z pomocą

Często używany, żeby obejść problemy związane z
komunikacją między domenami.

JSON
var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function () {
 if (xhr.readyState == 4 && xhr.status == 200) {
   // success
 };
};

xhr.open("GET", "http://somewhere", true);
xhr.send();
JSONP z pomocą

JSONP
var tag = document.createElement("script");
tag.src = 'http://somewhere?callback=foo';

document.getElementsByTagName("head")[0].appendChild(tag);
Jaka jest różnica?

Różnica w zapytaniu JSONP polega na tym, że odpowiedź jest
przekazywana jako argument wywołania funkcji - stąd parametr
callback.

WAŻNE!
W odróżnieniu od zwykłego zapytania XHR w zapytaniu
JSONP nie można wyłapać błędów - dostajemy poprostu
ParseError
Jaka jest różnica?

Różnica w zapytaniu JSONP polega na tym, że odpowiedź jest
przekazywana jako argument wywołania funkcji - stąd parametr
callback.

WAŻNE!
W odróżnieniu od zwykłego zapytania XHR w zapytaniu
JSONP nie można wyłapać błędów - dostajemy poprostu
ParseError


            Na szczęście jQuery robi to za nas!
JSONP i Rails 3

Musimy obsłużyć:

http://hostapp.com/api/widget/action?callback=foo
JSONP i Rails 3

Musimy obsłużyć:

http://hostapp.com/api/widget/action?callback=foo

Odpowiedź można sformułować tak:

render :json => @items.to_json, :callback =>
  params[:callback]
JSONP i Rails 3

Musimy obsłużyć:

http://hostapp.com/api/widget/action?callback=foo

Odpowiedź można sformułować tak:

render :json => @items.to_json, :callback =>
  params[:callback]

Otrzymujemy błędy z powodu innej domeny z którą chcemy się
połączyć?
SameOriginPolicy

class Api::WidgetController < ApplicationController
   after_filter :set_access_control_headers
end
SameOriginPolicy

class Api::WidgetController < ApplicationController
   after_filter :set_access_control_headers
end

def set_access_control_headers
  headers['Access-Control-Allow-Origin'] = '*'
  headers['Access-Control-Request-Method'] = '*'
end
Wszystko razem

Jeśli widget ma wiele funkcji, trzeba jakoś sprytnie ustalić
sposób komunikacji.
Wszystko razem

Jeśli widget ma wiele funkcji, trzeba jakoś sprytnie ustalić
sposób komunikacji.
Ładowanie widgetu

Pomysł polega na umieszczeniu całej logiki komunikacji i
widoku w samym widgecie, dzięki czemu zaoszczędzimy na
requestach (będziemy wysyłać i odbierać tylko dane)

<script type="text/javascript"
  src="http://hostapp.com/api/widget/main"></script>

app/views/api/widget/main.js.erb

if(window.Widget == undefined) {
   window.Widget = { // logic here
}
}
Logika widgetu

if(window.Widget == undefined) {
   window.Widget = {
     Settings: {},
     API: {},
     Handlers: {},
     GUI: {}
   }
}

$(document).ready(function() {
Widget.API.call('init', {});
});
Ustawienia

Settings: {
  api: {
     url: "http://hostapp.com/api/widget"
  }
}
API

API: {
  call: function(action, data) {
  var url = Widget.Settings.api.url + '/' +
     action;
  data['api_key'] = __apiKey;
  $.ajax({
url: url,
data: data,
crossDomain: true,
  dataType: "jsonp",
  success: Widget.API.responseHandler
  });
}
Rails response


def widget_response(action, data)
  response_hash = {:action => action,
     :data => data}
  render :json => response_hash.to_json,
     :callback => params[:callback]
end
API

API: {
  responseHandler: function() {
    Widget.Handlers[action](response.data)
  }
}
Handlers

Handlers: {
  init: function(data) {
     // populate widget with data
     // and draw some GUI
     Widget.GUI.render(data);
  }
}
Jeszcze ciekawiej: IFRAME w widgecie

Co jeśli w swoim widgecie uruchomimy jeszcze inną stronę w
IFRAME i będziemy chcieli mieć możliwość odpowiedzieć z
niego na pewne zdarzenie w IFRAME?
Jeszcze ciekawiej: IFRAME w widgecie

Co jeśli w swoim widgecie uruchomimy jeszcze inną stronę w
IFRAME i będziemy chcieli mieć możliwość odpowiedzieć z
niego na pewne zdarzenie w IFRAME?

                       Hash pooling
Jeszcze ciekawiej: IFRAME w widgecie

Co jeśli w swoim widgecie uruchomimy jeszcze inną stronę w
IFRAME i będziemy chcieli mieć możliwość odpowiedzieć z
niego na pewne zdarzenie w IFRAME?

                           Hash pooling


Widget.interval = setInterval(handleWindowHash,
 1000)

teraz z wewnątrz IFRAME zmieniamy hash okna nadrzędnego

window.location.hash = "trigger_sth"
Przykład
Host App
http://rails-widget-example.heroku.com

Widget
<!doctype html>
<html><head><title>Widget Client</title>
  <script type="text/javascript"
    src="jquery.js"></script>
  <script type="text/javascript">
    var __userSecret = '8102260836164404';
  </script>
    <script type="text/javascript" src="http://
    rails-widget-example.heroku.com/api/widget/main.js">
  </script></head>
  <body>
<div><h1>Widget example</h1></div>
<div id="widget_placeholder"></div>
  </body>
</html>
Dzięki :)

E-mail
  sebastian@emaire.com

Twitter
  @sebastiandreake

Kod aplikacji live
  https://github.com/dreake/widget

More Related Content

Viewers also liked

El isra
El israEl isra
El isra
any_24
 
Cairo, egypt
Cairo, egyptCairo, egypt
Cairo, egypt
hsschool
 
Documenblkkkian
DocumenblkkkianDocumenblkkkian
Documenblkkkian
blanckaa
 
Hbbtv
HbbtvHbbtv
Hbbtv
reinhardh
 
Herri programa 2011-2015-1
Herri programa 2011-2015-1Herri programa 2011-2015-1
Herri programa 2011-2015-1txojuankar
 

Viewers also liked (7)

El isra
El israEl isra
El isra
 
Cairo, egypt
Cairo, egyptCairo, egypt
Cairo, egypt
 
Mass Audubon
Mass AudubonMass Audubon
Mass Audubon
 
Documenblkkkian
DocumenblkkkianDocumenblkkkian
Documenblkkkian
 
5g angi test
5g angi test5g angi test
5g angi test
 
Hbbtv
HbbtvHbbtv
Hbbtv
 
Herri programa 2011-2015-1
Herri programa 2011-2015-1Herri programa 2011-2015-1
Herri programa 2011-2015-1
 

Similar to Functional widgets in Rails

Programowanie aplikacji dla Windows 8 (WinRT)
Programowanie aplikacji dla Windows 8 (WinRT)Programowanie aplikacji dla Windows 8 (WinRT)
Programowanie aplikacji dla Windows 8 (WinRT)
Bartlomiej Zass
 
JavaScript, Moduły
JavaScript, ModułyJavaScript, Moduły
JavaScript, Moduły
Mariusz Nowak
 
AngularJS - podstawy
AngularJS - podstawyAngularJS - podstawy
AngularJS - podstawy
Apptension
 
Budowa RESTowego api w oparciu o HATEOAS
Budowa RESTowego api w oparciu o HATEOASBudowa RESTowego api w oparciu o HATEOAS
Budowa RESTowego api w oparciu o HATEOAS
Mateusz Stępniak
 
react-pl.pdf
react-pl.pdfreact-pl.pdf
react-pl.pdf
ssuser65180a
 
Patronage 2016 Windows 10 Warsztaty
Patronage 2016 Windows 10 WarsztatyPatronage 2016 Windows 10 Warsztaty
Patronage 2016 Windows 10 Warsztaty
intive
 
Budowa poprawnego i intuicyjnego api REST HATEOAS devfest@2013
Budowa poprawnego i intuicyjnego api REST HATEOAS devfest@2013Budowa poprawnego i intuicyjnego api REST HATEOAS devfest@2013
Budowa poprawnego i intuicyjnego api REST HATEOAS devfest@2013
Mateusz Stępniak
 
NK API - Przykłady
NK API - PrzykładyNK API - Przykłady
NK API - Przykłady
nasza-klasa
 
Wtyczkowe Kompendium - WordUp Lublin
Wtyczkowe Kompendium - WordUp LublinWtyczkowe Kompendium - WordUp Lublin
Wtyczkowe Kompendium - WordUp Lublin
Tomasz Dziuda
 
REST API - teoria i praktyka - WordUp Trójmiasto
REST API - teoria i praktyka - WordUp TrójmiastoREST API - teoria i praktyka - WordUp Trójmiasto
REST API - teoria i praktyka - WordUp Trójmiasto
Tomasz Dziuda
 
Laravel workshops 1
Laravel workshops 1Laravel workshops 1
Laravel workshops 1
Kamil Fojuth
 
Extjs & netzke
Extjs & netzkeExtjs & netzke
Extjs & netzkeGaldoMedia
 
Google App Engine i Google Play Services w Twoich aplikacjach
Google App Engine i Google Play Services w Twoich aplikacjachGoogle App Engine i Google Play Services w Twoich aplikacjach
Google App Engine i Google Play Services w Twoich aplikacjach
3camp
 
Wtyczkowe Kompendium - WordUp Łódź #12
Wtyczkowe Kompendium - WordUp Łódź #12Wtyczkowe Kompendium - WordUp Łódź #12
Wtyczkowe Kompendium - WordUp Łódź #12
Tomasz Dziuda
 
Migrate API w Drupalu [PL]
Migrate API w Drupalu [PL]Migrate API w Drupalu [PL]
Migrate API w Drupalu [PL]
Droptica
 
Co nowego w VS 2013 dla programistów ASP.NET?
Co nowego w VS 2013 dla programistów ASP.NET?Co nowego w VS 2013 dla programistów ASP.NET?
Co nowego w VS 2013 dla programistów ASP.NET?
Bartlomiej Zass
 
Co nowego w ASP.NET MVC 4?
Co nowego w ASP.NET MVC 4?Co nowego w ASP.NET MVC 4?
Co nowego w ASP.NET MVC 4?
tkryskiewicz
 
Websites vs Cloud Services - OLMUG
Websites vs Cloud Services - OLMUGWebsites vs Cloud Services - OLMUG
Websites vs Cloud Services - OLMUG
Bart Zaremba
 
Asynchroniczne testy JavaScript aplikacji webowych
Asynchroniczne testy JavaScript aplikacji webowychAsynchroniczne testy JavaScript aplikacji webowych
Asynchroniczne testy JavaScript aplikacji webowych
Future Processing
 
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarkaThymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
Maciej Ziarko
 

Similar to Functional widgets in Rails (20)

Programowanie aplikacji dla Windows 8 (WinRT)
Programowanie aplikacji dla Windows 8 (WinRT)Programowanie aplikacji dla Windows 8 (WinRT)
Programowanie aplikacji dla Windows 8 (WinRT)
 
JavaScript, Moduły
JavaScript, ModułyJavaScript, Moduły
JavaScript, Moduły
 
AngularJS - podstawy
AngularJS - podstawyAngularJS - podstawy
AngularJS - podstawy
 
Budowa RESTowego api w oparciu o HATEOAS
Budowa RESTowego api w oparciu o HATEOASBudowa RESTowego api w oparciu o HATEOAS
Budowa RESTowego api w oparciu o HATEOAS
 
react-pl.pdf
react-pl.pdfreact-pl.pdf
react-pl.pdf
 
Patronage 2016 Windows 10 Warsztaty
Patronage 2016 Windows 10 WarsztatyPatronage 2016 Windows 10 Warsztaty
Patronage 2016 Windows 10 Warsztaty
 
Budowa poprawnego i intuicyjnego api REST HATEOAS devfest@2013
Budowa poprawnego i intuicyjnego api REST HATEOAS devfest@2013Budowa poprawnego i intuicyjnego api REST HATEOAS devfest@2013
Budowa poprawnego i intuicyjnego api REST HATEOAS devfest@2013
 
NK API - Przykłady
NK API - PrzykładyNK API - Przykłady
NK API - Przykłady
 
Wtyczkowe Kompendium - WordUp Lublin
Wtyczkowe Kompendium - WordUp LublinWtyczkowe Kompendium - WordUp Lublin
Wtyczkowe Kompendium - WordUp Lublin
 
REST API - teoria i praktyka - WordUp Trójmiasto
REST API - teoria i praktyka - WordUp TrójmiastoREST API - teoria i praktyka - WordUp Trójmiasto
REST API - teoria i praktyka - WordUp Trójmiasto
 
Laravel workshops 1
Laravel workshops 1Laravel workshops 1
Laravel workshops 1
 
Extjs & netzke
Extjs & netzkeExtjs & netzke
Extjs & netzke
 
Google App Engine i Google Play Services w Twoich aplikacjach
Google App Engine i Google Play Services w Twoich aplikacjachGoogle App Engine i Google Play Services w Twoich aplikacjach
Google App Engine i Google Play Services w Twoich aplikacjach
 
Wtyczkowe Kompendium - WordUp Łódź #12
Wtyczkowe Kompendium - WordUp Łódź #12Wtyczkowe Kompendium - WordUp Łódź #12
Wtyczkowe Kompendium - WordUp Łódź #12
 
Migrate API w Drupalu [PL]
Migrate API w Drupalu [PL]Migrate API w Drupalu [PL]
Migrate API w Drupalu [PL]
 
Co nowego w VS 2013 dla programistów ASP.NET?
Co nowego w VS 2013 dla programistów ASP.NET?Co nowego w VS 2013 dla programistów ASP.NET?
Co nowego w VS 2013 dla programistów ASP.NET?
 
Co nowego w ASP.NET MVC 4?
Co nowego w ASP.NET MVC 4?Co nowego w ASP.NET MVC 4?
Co nowego w ASP.NET MVC 4?
 
Websites vs Cloud Services - OLMUG
Websites vs Cloud Services - OLMUGWebsites vs Cloud Services - OLMUG
Websites vs Cloud Services - OLMUG
 
Asynchroniczne testy JavaScript aplikacji webowych
Asynchroniczne testy JavaScript aplikacji webowychAsynchroniczne testy JavaScript aplikacji webowych
Asynchroniczne testy JavaScript aplikacji webowych
 
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarkaThymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
 

Functional widgets in Rails

  • 1. Functional widgets in Rails Sebastian Sito
  • 2. Co to jest widget? mała aplikacja wbudowana w stronę WWW może być funkcjonalna lub statyczna
  • 3. Przykład? AlleWidget Google Gadgets Facebook like buttons
  • 4. Na początek statyczny content <script type="text/javascript" src="http://hostapp.com/api/widget/main"></script>
  • 5. Uwaga na Operę! <script type="text/javascript" src="http://hostapp.com/api/widget/main.js"></script>
  • 6. Po stronie aplikacji app/controllers/widget_controller.rb class Api::WidgetController < ApplicationController layout :nil def main respond_to do |format| format.js end end end
  • 7. Po stronie aplikacji app/views/api/widget/main.js.erb document.write('<div id="widget">'); <%= @title %> document.write('</div>');
  • 8. Personalizacja widgetu app/controllers/widget_controller.rb class Api::WidgetController < ApplicationController layout :nil before_filter :validate_api_key def main respond_to do |format| format.js end end end
  • 9. Personalizacja widgetu config/routes.rb namespace :api do match '/widget/:action/:api_key', :controller => 'widget', :api_key => /.*/ end app/controllers/api/widget_controller.rb def validate_api_key render :text => 'Invalid API key' unless params[:api_key] and return render :text => 'Wrong API credentials' if not User.find_by_key(params[:api_key]) and return end
  • 10. Personalizacja widgetu <script type="text/javascript"> var __apiKey = "qcg35cgwhojpm839v5"; </script> <script type="text/javascript" src="http://hostapp.com/api/widget/main"></script>
  • 11. Widget funkcjonalny Mamy problem: aplikacja i widget to dwie różne domeny!
  • 12. JSONP z pomocą Często używany, żeby obejść problemy związane z komunikacją między domenami. JSON var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { // success }; }; xhr.open("GET", "http://somewhere", true); xhr.send();
  • 13. JSONP z pomocą JSONP var tag = document.createElement("script"); tag.src = 'http://somewhere?callback=foo'; document.getElementsByTagName("head")[0].appendChild(tag);
  • 14. Jaka jest różnica? Różnica w zapytaniu JSONP polega na tym, że odpowiedź jest przekazywana jako argument wywołania funkcji - stąd parametr callback. WAŻNE! W odróżnieniu od zwykłego zapytania XHR w zapytaniu JSONP nie można wyłapać błędów - dostajemy poprostu ParseError
  • 15. Jaka jest różnica? Różnica w zapytaniu JSONP polega na tym, że odpowiedź jest przekazywana jako argument wywołania funkcji - stąd parametr callback. WAŻNE! W odróżnieniu od zwykłego zapytania XHR w zapytaniu JSONP nie można wyłapać błędów - dostajemy poprostu ParseError Na szczęście jQuery robi to za nas!
  • 16. JSONP i Rails 3 Musimy obsłużyć: http://hostapp.com/api/widget/action?callback=foo
  • 17. JSONP i Rails 3 Musimy obsłużyć: http://hostapp.com/api/widget/action?callback=foo Odpowiedź można sformułować tak: render :json => @items.to_json, :callback => params[:callback]
  • 18. JSONP i Rails 3 Musimy obsłużyć: http://hostapp.com/api/widget/action?callback=foo Odpowiedź można sformułować tak: render :json => @items.to_json, :callback => params[:callback] Otrzymujemy błędy z powodu innej domeny z którą chcemy się połączyć?
  • 19. SameOriginPolicy class Api::WidgetController < ApplicationController after_filter :set_access_control_headers end
  • 20. SameOriginPolicy class Api::WidgetController < ApplicationController after_filter :set_access_control_headers end def set_access_control_headers headers['Access-Control-Allow-Origin'] = '*' headers['Access-Control-Request-Method'] = '*' end
  • 21. Wszystko razem Jeśli widget ma wiele funkcji, trzeba jakoś sprytnie ustalić sposób komunikacji.
  • 22. Wszystko razem Jeśli widget ma wiele funkcji, trzeba jakoś sprytnie ustalić sposób komunikacji.
  • 23. Ładowanie widgetu Pomysł polega na umieszczeniu całej logiki komunikacji i widoku w samym widgecie, dzięki czemu zaoszczędzimy na requestach (będziemy wysyłać i odbierać tylko dane) <script type="text/javascript" src="http://hostapp.com/api/widget/main"></script> app/views/api/widget/main.js.erb if(window.Widget == undefined) { window.Widget = { // logic here } }
  • 24. Logika widgetu if(window.Widget == undefined) { window.Widget = { Settings: {}, API: {}, Handlers: {}, GUI: {} } } $(document).ready(function() { Widget.API.call('init', {}); });
  • 25. Ustawienia Settings: { api: { url: "http://hostapp.com/api/widget" } }
  • 26. API API: { call: function(action, data) { var url = Widget.Settings.api.url + '/' + action; data['api_key'] = __apiKey; $.ajax({ url: url, data: data, crossDomain: true, dataType: "jsonp", success: Widget.API.responseHandler }); }
  • 27. Rails response def widget_response(action, data) response_hash = {:action => action, :data => data} render :json => response_hash.to_json, :callback => params[:callback] end
  • 28. API API: { responseHandler: function() { Widget.Handlers[action](response.data) } }
  • 29. Handlers Handlers: { init: function(data) { // populate widget with data // and draw some GUI Widget.GUI.render(data); } }
  • 30. Jeszcze ciekawiej: IFRAME w widgecie Co jeśli w swoim widgecie uruchomimy jeszcze inną stronę w IFRAME i będziemy chcieli mieć możliwość odpowiedzieć z niego na pewne zdarzenie w IFRAME?
  • 31. Jeszcze ciekawiej: IFRAME w widgecie Co jeśli w swoim widgecie uruchomimy jeszcze inną stronę w IFRAME i będziemy chcieli mieć możliwość odpowiedzieć z niego na pewne zdarzenie w IFRAME? Hash pooling
  • 32. Jeszcze ciekawiej: IFRAME w widgecie Co jeśli w swoim widgecie uruchomimy jeszcze inną stronę w IFRAME i będziemy chcieli mieć możliwość odpowiedzieć z niego na pewne zdarzenie w IFRAME? Hash pooling Widget.interval = setInterval(handleWindowHash, 1000) teraz z wewnątrz IFRAME zmieniamy hash okna nadrzędnego window.location.hash = "trigger_sth"
  • 33. Przykład Host App http://rails-widget-example.heroku.com Widget <!doctype html> <html><head><title>Widget Client</title> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> var __userSecret = '8102260836164404'; </script> <script type="text/javascript" src="http:// rails-widget-example.heroku.com/api/widget/main.js"> </script></head> <body> <div><h1>Widget example</h1></div> <div id="widget_placeholder"></div> </body> </html>
  • 34. Dzięki :) E-mail sebastian@emaire.com Twitter @sebastiandreake Kod aplikacji live https://github.com/dreake/widget