Upload
wynn-netherland
View
194
Download
52
Embed Size (px)
DESCRIPTION
My slide deck from Lone Star Ruby Conference 2008
Citation preview
!"#$$%$$
Javascript andRuby Frameworks
Wynn Netherland
!"#$$%$$ Wynn Netherland
wynn$ script/generate presentation javascript_and_ruby_frameworks
create slides/images/
create slides/title.slide
create slides/icebreaker.slide
create slides/witty.joke
create slides/wrapup.slide
!"#$$%$$ Wynn Netherland
RailsMerbCampingSinatra
RubyPrototypescript.aculo.usjQueryMooToolsYUIExtJS
Javascript
!"#$$%$$ Wynn Netherland
Speaker notes
!"#$$%$$ Wynn Netherland
RailsMerbCampingSinatra
RubyPrototypescript.aculo.usjQueryMooToolsYUIExtJS
Javascript
MerbjQuery
!"#$$%$$ Wynn Netherland
“In short, this is a crash course in how to marry the rapid development approaches that are the core of both Ruby web frameworks and jQuery to build a super-charged environment for quickly prototyping applications. And because Ruby on Rails and Merb are very similar, we’ll be able to cover both web frameworks in a single talk.”
Using jQuery with Ruby Web Frameworks - Yehuda Katz
!"#$$%$$
Who is this Yehuda cat?
Wynn Netherland
(and why is he giving my talk tomorrow?)
!"#$$%$$
Let’s see what we candig up on the interweb.
Wynn Netherland
!"#$$%$$ Wynn Netherland
!"#$$%$$ Wynn Netherland
!"#$$%$$ Wynn Netherland
!"#$$%$$
I’m so excited I gotta tell ya...(Katz’s never kloses!)
Wynn Netherland
!"#$$%$$ Wynn Netherland
!"#$$%$$ Wynn Netherland
Just about anybody can write for this label it would seem.
!"#$$%$$ Wynn Netherland
!"#$$%$$
Yehuda Katz
Wynn Netherland
- Merb core developer- jQuery committer- DataMapper contributor
!"#$$%$$ Wynn Netherland
!"#$$%$$
Yehuda Katz
Wynn Netherland
10:00 am Using jQuery with Ruby Web Frameworks
Don’t miss it!
!"#$$%$$ Wynn Netherland
in stores now
April 2009
!"#$$%$$
so how do we want to spend the next 30 minutes?
Wynn Netherland
!"#$$%$$ Wynn Netherland
wynn$ script/destroy presentation javascript_and_ruby_frameworks
notempty slides/images/
rm slides/title.slide
rm slides/icebreaker.slide
rm slides/witty.joke
rm slides/wrapup.slide
!"#$$%$$
Why Javascript at a Ruby conference?
Wynn Netherland
!"#$$%$$
Why’s Javascript framework
Wynn Netherland
!"#$$%$$ Wynn Netherland
Why Javascript frameworks?
!"#$$%$$
Abstract browser quirks!
Wynn Netherland
navigator.userAgent.indexOf(“MSIE”)
!"#$$%$$
Extend the language
Wynn Netherland
["foo", "bar"].each(function(i) {
console.log(i);
});
!"#$$%$$
Nifty Ajaxi!cation
Wynn Netherland
$("#fighter").load("/fighters/1/specs #fighter .specs");
new Ajax.Updater(container, url);
!"#$$%$$
Event sanity
Wynn Netherland
$('foo').observe('click', clickMe);
!"#$$%$$
E"ects!
Wynn Netherland
$("#fighter").show("slow");
!"#$$%$$
E"ects!
Wynn Netherland
$("#fighter").show("slow");
!"#$$%$$
The lineup
Wynn Netherland
!"#$$%$$
Prototype
Wynn Netherland
!"#$$%$$
Prototype
Wynn Netherland
script.aculo.us
!"#$$%$$
Prototype
Wynn Netherland
- Integrated with Rails but easily used alone- OOP enhancements with Class.create- Utility functions
- Try.these- $, $$, $F, $A, $w
- Robust Ajax support
!"#$$%$$
Prototype and script.aculo.us
Wynn Netherland
- E"ects!- Appear, Fade, Blinds, Pu", etc.
- Drag and drop!- Buildervar element = Builder.node('p', { className:'error' },
'An error has occurred');
!"#$$%$$
jQuery
Wynn Netherland
!"#$$%$$
jQuery
Wynn Netherland
is not a database tool for Java
!"#$$%$$
jQuery
Wynn Netherland
- Syntax based on chaining$("p").text("boo-yah!").show("slow");
- Less code means less iteration irritation- Simpler Ajax$("#portfolio").load("/stocks .prices");
- Can still get down and dirty $.ajax({
type: "POST", url: "/search",
data: "q=pizza&loc=76227", success: function(msg){
alert( "Search results: " + msg ); }
});
!"#$$%$$
jQuery
Wynn Netherland
- Powerful core e"ects- Fade, Blinds, etc.- animate!
$(".message").animate({
"left": "50",
"opacity": 1
}, 500
);
- Designed for plugins- Plays well with others$j = jQuery.noConflict();
!"#$$%$$
Yehuda Katz
Wynn Netherland
10:00 am Using jQuery with Ruby Web Frameworks
Did I mention Yehuda is here?
!"#$$%$$
MooTools
Wynn Netherland
!"#$$%$$
MooTools
Wynn Netherland
- Language enhancements- Array, Hash, Number- OOP extensions with Class, Class.Extras
- Powerful Fx- Ajax- Popular with the designer types
(everything this community does is eye candy)
!"#$$%$$
Yahoo! User Interface (YUI)
Wynn Netherland
!"#$$%$$
Yahoo! User Interface (YUI)
Wynn Netherland
- More than Javascript a framework- CSS tools, UI design patterns, controls
- Namespaces YAHOO.util.Event.on(
YAHOO.util.Dom.get('user-profile'),
'click',
function(ev) {
YAHOO.util.Event.stopEvent(ev);
// code goes here
}
);
- Verbose
!"#$$%$$
ExtJS
Wynn Netherland
!"#$$%$$
ExtJS
Wynn Netherland
- They did what with Javascript?- ExtJS.describe() => "Cross-Browser Rich Internet Application Framework"
- Great GUI components (more on that in moment)
!"#$$%$$
So how do all of these play with Ruby?
Wynn Netherland
!"#$$%$$
Approach #1: Helpers
Wynn Netherland
!"#$$%$$
Approach #1: Helpers
Wynn Netherland
OH: "you don't want to handle this stu" directly"
!"#$$%$$
Approach #1: Helpers
Wynn Netherland
OH: "you don't want to handle this stu" directly"
!"#$$%$$
Helpers
Wynn Netherland
- Clean, tested, less error-prone writing of Javascript- Stay in Ruby, less tag soup in your views<%= link_to_remote "View lesson", {
:url => {
:controller => “lessons”,
:action => “show”,
:id => lesson.id
}, :method => :get } %>
<%= sortable_element("top-ten", :url => { :action =>
"order" }) %>
!"#$$%$$
Helpers
Wynn Netherland
keep an eye on 'em
!"#$$%$$
Helpers
Wynn Netherland
keep an eye on 'em
!"#$$%$$
When Helpers are less than helpful
Wynn Netherland
Consider your DRY view code:<table id="users_list">
<% @users.each do |user| -%> <tr id="user_<%= user.id %>">
<td><%= user.login %></td> <td>
<%= link_to_remote( 'Delete',
:url => user_path(user), :method => 'delete',
:confirm => 'Are you sure?', :complete => "Effect.DropOut('user_#{user.id}')",
:failure => 'alert("Could not delete user: #{user.login}")' )
%> </td>
</tr> <% end -%>
</table>
http://blog.solnic.eu/2007/10/30/why-javascript-helpers-in-rails-are-evil
!"#$$%$$
When Helpers are less than helpful
Wynn Netherland
Wet and sloppy in the browser<table id="users_list">
<tr id="user_2"> <td>jane</td>
<td> <a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/2',
{asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request){Effect.DropOut('user_2')}, onFailure:function(request){alert('Could not delete user:
jane')}}); }; return false;">Delete</a> </td>
</tr> <tr id="user_1">
<td>john</td> <td>
<a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/1', {asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request)
{Effect.DropOut('user_1')}, onFailure:function(request){alert('Could not delete user: john')}}); }; return false;">Delete</a>
</td> </tr>
<tr id="user_4"> <td>paul</td>
<td> <a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/4',
http://blog.solnic.eu/2007/10/30/why-javascript-helpers-in-rails-are-evil
!"#$$%$$
When Helpers are less than helpful
Wynn Netherland
Wet and sloppy in the browser<table id="users_list">
<tr id="user_2"> <td>jane</td>
<td> <a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/2',
{asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request){Effect.DropOut('user_2')}, onFailure:function(request){alert('Could not delete user:
jane')}}); }; return false;">Delete</a> </td>
</tr> <tr id="user_1">
<td>john</td> <td>
<a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/1', {asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request)
{Effect.DropOut('user_1')}, onFailure:function(request){alert('Could not delete user: john')}}); }; return false;">Delete</a>
</td> </tr>
<tr id="user_4"> <td>paul</td>
<td> <a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/4',
http://blog.solnic.eu/2007/10/30/why-javascript-helpers-in-rails-are-evil
!"#$$%$$
Approach #2: Unobtrusive Javascript (UJS)
Wynn Netherland
!"#$$%$$
When Helpers are less than helpful
Wynn Netherland
- Just write good markup<table id="users_list">
<tr id="user_2"> <td>jane</td>
<td><a href="/users/2/confirm_delete">Delete</a></td> </tr>
<tr id="user_1"> <td>john</td>
<td><a href="/users/1/confirm_delete">Delete</a></td> </tr>
<tr id="user_4"> <td>paul</td>
<td><a href="/users/4/confirm_delete">Delete</a></td> </tr>
<tr id="user_3"> <td>peter</td>
<td><a href="/users/3/confirm_delete">Delete</a></td> </tr>
</table>
- Design for no Javascript !rst (if feasible)
http://blog.solnic.eu/2007/10/30/why-javascript-helpers-in-rails-are-evil
!"#$$%$$
When Helpers are less than helpful
Wynn Netherland
Add Hijack the behavior later! (Prototype example)var Users = {
onWindowLoad : function() { $('users_list').getElementsBySelector('tr').each(function(userRow){
userRow.down('a').observe('click', Users.onUserDelete); });
},
onUserDelete : function(event) { if(confirm('Are you sure?')) {
var userId = Event.element(event).up('tr').id.split('_').last(); new Ajax.Request(
'/users/'+userId, { method : 'delete',
on200 : function(){ Effect.DropOut('user_'+userId) }, on500 : function(xhr){ alert(xhr.responseText) }
}); }
}}
Event.observe(window, 'load', Users.onWindowLoad);
http://blog.solnic.eu/2007/10/30/why-javascript-helpers-in-rails-are-evil
!"#$$%$$
UJS tools
Wynn Netherland
- jQuery- Support UJS out of the box by design
- Dan Webb's LowPro- Create class-based inheritable behaviors- Easily attach/detach behavior to elements
- LowPro for jQuery- Ports Class.create to jQuery
- http://ujs4rails.com/ (still active?)
!"#$$%$$
Approach #3: Widgets
Wynn Netherland
UI controls, components, thingamabobbers
!"#$$%$$
Widgets
Wynn Netherland
- Tabs- Grids- Date pickers- Dialogs- Panels- Sliders
!"#$$%$$
Framework support for UI components
Wynn Netherland
- jQuery- jQuery UI (themeable!)- http://plugins.jquery.com
- Prototype- LivePipe UI- http://scripteka.com
- YUI- Huge set of built-in controls and widgets
- ExtJS- Slickest grids and tabs around- Dual licensed, read carefully
!"#$$%$$
Approach #4: MVC in the browser
Wynn Netherland
!"#$$%$$
MVC in the browser
Wynn Netherland
Jerry: "Ah, you're crazy."Kramer: "Am I? Or am I so sane that you just blew your mind?!"Jerry: "It's impossible!"Kramer: "Is it? Or is it so possible that your head is spinning like a top?!"Jerry: "It can't be."Kramer: "Can it? Or is your entire world just crashing down all around you?"Jerry: "Alright, that's enough."Kramer: "Yaaaaaaahhh!!!"
- Jerry and Kramer, in "The Stall"
!"#$$%$$
SproutCore - so crazy it just might work
Wynn Netherland
- Standards based- Build desktop grade apps in your browser- MVC- Databinding - properties, observers- Widgets- Drag-n-drop- Undo/redo- Powers Apple's MobileMe.com service
!"#$$%$$
SproutCore - more Ruby #avor!
Wynn Netherland
- Ruby style syntax- Generators!- Fixtures(!)- Uses Merb for local development
!"#$$%$$
Demo
Wynn Netherland
!"#$$%$$
SproutCore models
Wynn Netherland
// ==========================================================================
// MyApp.Todo// ==========================================================================
require('core');
/** @class
(Document your class here)
@extends SC.Record
@author AuthorName @version 0.1
*/ MyApp.Todo = SC.Record.extend(
/** @scope MyApp.Todo.prototype */ {
todoListType: 'MyApp.TodoList'
}) ;
http://github.com/sproutit/sproutcore/wikis/sproutcore-s-modern-model-layer-part-3
!"#$$%$$
SproutCore models
Wynn Netherland
// ==========================================================================
// MyApp.TodoList// ==========================================================================
require('core');
/** @class
(Document your class here)
@extends SC.Record
@author AuthorName @version 0.1
*/
MyApp.TodoList = SC.Record.extend(/** @scope MyApp.TodoList.prototype */ {
todos: SC.Record.hasMany('MyApp.Todo', 'todoList')
}) ;
http://github.com/sproutit/sproutcore/wikis/sproutcore-s-modern-model-layer-part-3
!"#$$%$$
SproutCore models
Wynn Netherland
// ==========================================================================
// MyApp.Todo Fixtures// ==========================================================================
require('core') ;
MyApp.FIXTURES = MyApp.FIXTURES.concat([
{ guid: 1,
type: 'Todo', name: "Something to do",
todoList: 1 // the guid of the todo list object this todo is related to },
{ guid: 2,
type: 'Todo', name: "Something else to do",
todoList: 1 },
{ guid: 3,
type: 'Todo', name: "Gee, I'm busy.",
todoList: 1 }
]); http://github.com/sproutit/sproutcore/wikis/sproutcore-s-modern-model-layer-part-3
!"#$$%$$
SproutCore models
Wynn Netherland
>>> var c = MyApp.TodoList.find(1).get('todos');
>>> c.count();2
http://github.com/sproutit/sproutcore/wikis/sproutcore-s-modern-model-layer-part-3
!"#$$%$$
SproutCore resources
Wynn Netherland
web: http://www.sproutcore.com/
wikis: http://github.com/sproutit/sproutcore/wikis/
!"#$$%$$
Thanks!
Wynn Netherland
Drop me a line: [email protected]
Web: http://squeejee.comBlog: http://locomotivation.comCode: http://github.com/squeejee http://github.com/pengwynn
Twitter: pengwynn