34
Functional widgets in Rails Sebastian Sito

Functional widgets in Rails

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Functional widgets in Rails

Functional widgets in Rails

Sebastian Sito

Page 2: Functional widgets in Rails

Co to jest widget?

mała aplikacja wbudowana w stronę WWWmoże być funkcjonalna lub statyczna

Page 3: Functional widgets in Rails

Przykład?

AlleWidgetGoogle GadgetsFacebook like buttons

Page 4: Functional widgets in Rails

Na początek statyczny content

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

Page 5: Functional widgets in Rails

Uwaga na Operę!

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

Page 6: Functional widgets in Rails

Po stronie aplikacji

app/controllers/widget_controller.rb

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

Page 7: Functional widgets in Rails

Po stronie aplikacji

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

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

Page 8: Functional widgets in Rails

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 endend

Page 9: Functional widgets in Rails

Personalizacja widgetu

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

app/controllers/api/widget_controller.rbdef 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 returnend

Page 10: Functional widgets in Rails

Personalizacja widgetu

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

Page 11: Functional widgets in Rails

Widget funkcjonalny

Mamy problem: aplikacja i widget to dwie różne domeny!

Page 12: Functional widgets in Rails

JSONP z pomocą

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

JSONvar xhr = new XMLHttpRequest();

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

xhr.open("GET", "http://somewhere", true);xhr.send();

Page 13: Functional widgets in Rails

JSONP z pomocą

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

document.getElementsByTagName("head")[0].appendChild(tag);

Page 14: Functional widgets in Rails

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

Page 15: Functional widgets in Rails

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!

Page 16: Functional widgets in Rails

JSONP i Rails 3

Musimy obsłużyć:

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

Page 17: Functional widgets in Rails

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]

Page 18: Functional widgets in Rails

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ć?

Page 19: Functional widgets in Rails

SameOriginPolicy

class Api::WidgetController < ApplicationController after_filter :set_access_control_headersend

Page 20: Functional widgets in Rails

SameOriginPolicy

class Api::WidgetController < ApplicationController after_filter :set_access_control_headersend

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

Page 21: Functional widgets in Rails

Wszystko razem

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

Page 22: Functional widgets in Rails

Wszystko razem

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

Page 23: Functional widgets in Rails

Ł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 }}

Page 24: Functional widgets in Rails

Logika widgetu

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

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

Page 25: Functional widgets in Rails

Ustawienia

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

Page 26: Functional widgets in Rails

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 });}

Page 27: Functional widgets in Rails

Rails response

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

Page 28: Functional widgets in Rails

API

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

Page 29: Functional widgets in Rails

Handlers

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

Page 30: Functional widgets in Rails

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?

Page 31: Functional widgets in Rails

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

Page 32: Functional widgets in Rails

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"

Page 33: Functional widgets in Rails

Przykład

Host Apphttp://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>

Page 34: Functional widgets in Rails

Dzięki :)

E-mail [email protected]

Twitter @sebastiandreake

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