Ruby on Rails. für Java Entwickler - Ende der Schmerzen - first, last = :mariano, :kamp email = #{first}.#{last}@de.ibm.com



Similar documents
This tutorial explains basics about EJB3 and shows a simple work through to set up a EJB 3 project, create a entity bean and a session bean facade.

1. Was ist das? II. Wie funktioniert das? III. Wo funktioniert das nicht?

Ruby on Rails. Computerlabor

Java Server Pages combined with servlets in action. Generals. Java Servlets

We are not repeating all the basics here. Have a look at the basic EJB tutorials before you start this tutorial.

Hibernate Language Binding Guide For The Connection Cloud Using Java Persistence API (JAP)

Developing an EJB3 Application. on WebSphere 6.1. using RAD 7.5

How To Create A Model In Ruby (Orm)

Intruduction to Groovy & Grails programming languages beyond Java

Ruby on Rails is a web application framework written in Ruby, a dynamically typed programming language The amazing productivity claims of Rails is

Search Engines Chapter 2 Architecture Felix Naumann

6.170 Tutorial 3 - Ruby Basics

JAVA PROGRAMMING PATTERN FOR THE PREFERENCES USABILITY MECHANISM

Update to V10. Automic Support: Best Practices Josef Scharl. Please ask your questions here Event code 6262

OTN Developer Day Enterprise Java. Hands on Lab Manual JPA 2.0 and Object Relational Mapping Basics

Microsoft Certified IT Professional (MCITP) MCTS: Windows 7, Configuration ( )

Comparing Dynamic and Static Language Approaches to Web Frameworks

Author: Sascha Wolski Sebastian Hennebrueder Tutorials for Struts, EJB, xdoclet and eclipse.

ida.com excellence in dependable automation

Web Service Caching Using Command Cache

Dynamic website development using the Grails Platform. Joshua Davis Senior Architect Cognizant Technology Solutions

Thomas Rümmler AIT GmbH & Co. KG Christian Schlag AIT GmbH & Co. KG. Central Build and Release Management with TFS

Embedded Software Development and Test in 2011 using a mini- HIL approach

Is Cloud relevant for SOA? Corsin Decurtins

Kotlin for Android Developers

Ruby on Rails. a high-productivity web application framework. blog.curthibbs.us/ Curt Hibbs <curt@hibbs.com>

Not your Father s. Java EE. Lars Röwekamp CIO

Web Development Frameworks

Kapitel 2 Unternehmensarchitektur III

How To Manage Build And Release With Tfs 2013

Building and Deploying Web Scale Social Networking Applications Using Ruby on Rails and Oracle. Kuassi Mensah Group Product Manager

Jetzt können Sie den Befehl 'nsradmin' auch für diverse Check-Operationen verwenden!

Central Release and Build Management with TFS. Christian Schlag

APPLICATION SETUP DOCUMENT

Content Management System (Dokument- og Sagsstyringssystem)

Dozer v User's Guide

Smalltalk in Enterprise Applications. ESUG Conference 2010 Barcelona

Open Text Social Media. Actual Status, Strategy and Roadmap

Ruby on Rails An Agile Developer s Framework

Upgrading Your Skills to MCSA Windows Server 2012 MOC 20417

C:\Documents and Settings\Gijs\Desktop\src\client\Client.java dinsdag 3 november :50

SPICE auf der Überholspur. Vergleich von ISO (TR) und Automotive SPICE

Safe Harbor Statement

1Copyright 2013, Oracle and/or its affiliates. All rights reserved.

LEARNING AGREEMENT FOR STUDIES

Implementing Data Models and Reports with Microsoft SQL Server

Timebox Planning View der agile Ansatz für die visuelle Planung von System Engineering Projekt Portfolios

Ruby & Ruby on Rails for arkitekter. Kim Harding Christensen khc@kimharding.com

Lecture 7: Class design for security

Information Systems 2

JUnit. Introduction to Unit Testing in Java

Masters programmes in Computer Science and Information Systems. Object-Oriented Design and Programming. Sample module entry test xxth December 2013

CommVault Simpana 7.0 Software Suite. und ORACLE Momentaufnahme. Robert Romanski Channel SE

Satzgliedstellung. Regel #4: Adverbien: Die Satzgliedstellung verändert sich nicht, wenn eine adverbiale Bestimmung vorausgeht.

IAC-BOX Network Integration. IAC-BOX Network Integration IACBOX.COM. Version English

Specialized Programme on Web Application Development using Open Source Tools

Vergleich der Versionen von Kapitel 1 des EU-GMP-Leitfaden (Oktober 2012) 01 July November Januar 2013 Kommentar Maas & Peither

A: Ein ganz normaler Prozess B: Best Practices in BPMN 1.x. ITAB / IT Architekturbüro Rüdiger Molle März 2009

Agile Development with Groovy and Grails. Christopher M. Judd. President/Consultant Judd Solutions, LLC

STORM. Simulation TOol for Real-time Multiprocessor scheduling. Designer Guide V3.3.1 September 2009

Implementing Rexx Handlers in NetRexx/Java/Rexx

Language considerations for developing VoiceXML in German

Specialized Programme on Web Application Development using Open Source Tools

Testen mit Produktionsdaten Fluch oder Segen?

Mit einem Auge auf den mathema/schen Horizont: Was der Lehrer braucht für die Zukun= seiner Schüler

This tutorial has been designed for beginners who would like to use the Ruby framework for developing database-backed web applications.

Coffee Break German. Lesson 09. Study Notes. Coffee Break German: Lesson 09 - Notes page 1 of 17

Introduction U41241-J-Z

Mobile App Design Project #1 Java Boot Camp: Design Model for Chutes and Ladders Board Game

by Jonathan Kohl and Paul Rogers 40 BETTER SOFTWARE APRIL

Computer Programming I

PASS Deutschland e.v. Regionalgruppe Köln/Bonn/Düsseldorf

Canonical Text Service

Tobias Flohre codecentric AG. Ein Standard für die Batch- Entwicklung JSR-352

Exemplar for Internal Assessment Resource German Level 1. Resource title: Planning a School Exchange

O D B C / R O C K E T ( B S / O S D ) V 5. 0 F O R S E S A M / S Q L D A T E : F E B R U A R Y *2 R E L E A S E N O T I C E

Using Filter as JEE LoadBalancer for Enterprise Application Integration(EAI)

Moving from CS 61A Scheme to CS 61B Java

Die SharePoint-Welt für den erfahrenen.net- Entwickler. Fabian Moritz MVP Office SharePoint Server

Ruby in the context of scientific computing

SPECTRUM IM. SSA 3.0: Service AND Event/Alert Umbrella DACHSUG 2011

FOR TEACHERS ONLY The University of the State of New York

AnyWeb AG

Usability in SW-Engineering-Prozessen und in CMMI

Exchange Synchronization AX 2012

Ruby on Rails Web Mashup Projects

Transcription:

Ruby on Rails für Java Entwickler - Ende der Schmerzen - first, last = :mariano, :kamp email = #{first.#{last@de.ibm.com

Ruby on Rails für Java Entwickler - Ende der Schmerzen - first, last = :mariano, :kamp email = #{first.#{last@de.ibm.com

Es war einmal

Vor langer Zeit

1993

In einem fernen Land

Ein Ritter in schimmernder Rüstung

Yukihiro Matsumoto

Yukihiro Matsumoto Matz

Suche nach dem Edelstein

Ruby!

Smalltalk Perl + ~= Ruby http://flickr.com/photos/letioux/110269051/

Smalltalk Perl objektorientierung + dynamik ~= Ruby http://flickr.com/photos/letioux/110269051/

Smalltalk Perl objektorientierung dynamik + reguläre ausdrücke string manipulationen ~= Ruby http://flickr.com/photos/letioux/110269051/

was ist ruby?

programmiersprache

for first

for human beings first

then computers Matz

objektorientiert

objektorientierung kapselung vererbung polymorphie

objektorientierung

objektorientierung everything is an object

objektorientierung ja, ja...

objektorientierung nein, diesmal wirklich!

objektorientierung >> "ruby".class => String

objektorientierung >> "ruby".class IRB-In => String

objektorientierung >> "ruby".class => String IRB-Out

objektorientierung >> 10.class => Fixnum

objektorientierung >> 10.class => Fixnum Java Primitives sind keine Objekte!

objektorientierung >> nil.class => NilClass

objektorientierung >> nil.class => NilClass Java Schlüsselwort null

objektorientierung >> true.class => TrueClass

objektorientierung >> true.class => TrueClass Java Schlüsselwort true

objektorientierung objekte senden und empfangen nachrichten

objektorientierung >> 10.div(2) => 5

objektorientierung >> 10.div(2) => 5 Java Nicht für Primitives

objektorientierung >> 10.send(:div, 2) => 5

objektorientierung >> 10./2 => 5

objektorientierung >> 10/2 => 5

objektorientierung >> 10/2 => 5 Java Nur für Primitives

objektorientierung >> 10.send(:/, 2) => 5

objektorientierung >> String.new "ruby" => "ruby"

objektorientierung >> String.new "ruby" => "ruby" Java Schlüsselwort new

objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil

objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil

objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil

objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil Define a setter

objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil Define a getter

objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil >> d = Dog.new => #<Dog:0x1d4bac> >> d.name="fluffy" => "Fluffy" >> d.name => "Fluffy"

objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil >> d = Dog.new => #<Dog:0x1d4bac> >> d.name="fluffy" => "Fluffy" >> d.name => "Fluffy" Dog d = new Dog()

objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil >> d = Dog.new => #<Dog:0x1d4bac> >> d.name="fluffy" => "Fluffy" >> d.name => "Fluffy" d.setname( Fluffy )

objektorientierung >> class Dog >> def name=(new_name) >> @name=new_name >> end >> def name >> @name >> end >> end => nil >> d = Dog.new => #<Dog:0x1d4bac> >> d.name="fluffy" => "Fluffy" >> d.name => "Fluffy" d.getname()

dynamisch

dynamik

dynamik everything is open

dynamik sogar die ruby libraries

dynamik >> class Fixnum >> def even? >> self % 2 == 0 >> end >> end => nil >> 10.even? => true >> 9.even? => false

dynamik >> class Fixnum >> def even? >> self % 2 == 0 >> end >> end => nil >> 10.even? => true >> 9.even? => false Java Subclassing, wenn erlaubt Helper Klassen -> StringUtil

dynamik und bereits lebende objekte

dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end

dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end

dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end

dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end

dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end

dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end

dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end

dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end >> Player.find(:all).size => 4

dynamik class << ActiveRecord::Base.connection alias : old_execute :execute def execute(statement, name) puts "Executing: #{statement" old_execute (statement, name) end end >> Player.find(:all).size Executing: SELECT * FROM players => 4

dynamik

dynamik weak typing

dynamik strong/static typing weak typing

dynamik strong/static typing dynamic typing weak typing

dynamik dynamic typing >> def sum(a, b) >> a+b >> end => nil

dynamik dynamic typing >> def sum(a, b) >> a+b >> end => nil >> sum(1,2) => 3

dynamik dynamic typing >> def sum(a, b) >> a+b >> end => nil >> sum("a","z") => "AZ"

dynamik dynamic typing >> def sum(a, b) >> a+b >> end => nil >> sum("a",2)

dynamik dynamic typing >> def sum(a, b) >> a+b >> end => nil >> sum("a",2) TypeError: can't convert Fixnum into String

dynamik :method_missing

dynamik >> class Receiver >> def method_missing(action, *args) >> puts "My method #{action was called," >> puts "with parameters: #{args.inspect" >> end >> end

dynamik >> class Receiver >> def method_missing(action, *args) >> puts "My method #{action was called," >> puts "with parameters: #{args.inspect" >> end >> end >> r = Receiver.new => #<Receiver:0x33d43c>

dynamik >> class Receiver >> def method_missing(action, *args) >> puts "My method #{action was called," >> puts "with parameters: #{args.inspect" >> end >> end >> r = Receiver.new => #<Receiver:0x33d43c> >> r.test My method test was called, with parameters: [] => nil

dynamik >> class Receiver >> def method_missing(action, *args) >> puts "My method #{action was called," >> puts "with parameters: #{args.inspect" >> end >> end >> r = Receiver.new => #<Receiver:0x33d43c> >> r.test My method test was called, with parameters: [] => nil >> r.add 1,"b", 2 My method add was called, with parameters: [1, "b", 2] => nil

dynamik >> class Receiver >> def method_missing(action, *args) >> puts "My method #{action was called," >> puts "with parameters: #{args.inspect" >> end >> end >> r = Receiver.new => #<Receiver:0x33d43c> >> r.test My method test was called, with parameters: [] => nil >> r.add 1,"b", 2 My method add was called, with parameters: [1, "b", 2] => nil Proxy? Mock? State Machine? CSV Reader? AOP?

dynamik meta programmierung

dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil

dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil Definiert on the fly : :name, :name=, :age, :age=

dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil Überschreibt den setter für age.

dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil >> d = Dog.new => #<Dog:0x318498>

dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil >> d.name = "Fluffy" => "Fluffy" >> d.age = 2 => 2

dynamik >> class Dog >> attr_accessor :name, :age >> def age=(new_age) >> @age=new_age*7 >> end >> end => nil >> d.age => 14

dynamik und vieles mehr...

blocks/closures (nur ganz kurz)

closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end

closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end

closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2

closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2

closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2

closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2

closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2

closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2 >> log("output"){puts "Chunky Bacon" Now executing Output. Chunky Bacon Done with Output. => nil

closures >> def log(name) >> puts "Now executing #{name." >> result = yield >> puts "Done with #{name." >> result >> end >> log("addition"){1+1 Now executing Addition. Done with Addition. => 2 >> log("output"){puts "Chunky Bacon" Now executing Output. Chunky Bacon Done with Output. => nil >> ["chunky","bacon"].each { element puts element chunky bacon

demo!

2000

Dave Thomas

Andy Hunt

Pragmatic Programmers

Pragmatic Programmers

Pragmatic Programmers "Learn at least one new [programming] language every year. Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut."

Pickaxe

Google Trends http://www.google.com/trends?q=%22ruby+on+rails%22%2c+ejb&ctab=0&geo=all&date=all

Programming Language Trends http://radar.oreilly.com/archives/2006/08/programming_language_trends_1.html

Script Kiddies...

... Ritter...

Kent Beck

Kent Beck

Kent Beck

Kent Beck

Kent Beck I always knew one day Smalltalk would replace Java. I just didn't know it would be called Ruby.

Martin Fowler

Martin Fowler

Martin Fowler

Martin Fowler

Martin Fowler I like the ruby language for its rich yet uncluttered syntax and the well designed frameworks that come with it.

was ist nun Rails?

2004

der geistige vater

Google/O Reilly: Best Hacker

Google/O Reilly: Best Hacker

David Heinemeier Hanson (DHH)

rails ist...

mvc framwork

aus einem guss

extrahiert aus laufender anwendung

conventions configuration

conventions over configuration

opinionated software

zuckerbrot & peitsche

DRY (don t repeat yourself) drücke alles nur einmal aus

elegant

conventions

conventions Klassen- und Tabellen

conventions Klassen- und Tabellen Klassennamen sind Singular. Tabellennamen sind Plural.

conventions Klassen- und Tabellen Klassennamen sind Singular. Tabellennamen sind Plural. Klassennamen sind CamelCase. Tabellennamen sind Kleinbuchstaben, verbunden durch _.

conventions Klassen- und Tabellen Klassennamen sind Singular. Tabellennamen sind Plural. Klassennamen sind CamelCase. Tabellennamen sind Kleinbuchstaben, verbunden durch _. Bsp.: TurnState => turn_states OrderReceipt => order_receipts Person => people

conventions Spalten- und Attribute Spaltenname == Attributname Jede Tabelle hat eine id -Spalte

conventions Relationen Spaltennamen des foreign keys entspricht dem Namen der Klasse plus _id.

conventions Relationen Spaltennamen des foreign keys entspricht dem Namen der Klasse plus _id. Customer id name * Book id name author

conventions Relationen Spaltennamen des foreign keys entspricht dem Namen der Klasse plus _id. Customer id name * Book id name author Der Tabelle books wird die Spalte customer_id angefügt.

conventions... und mehr...

und? bringt s was?

JEE vs Rails http://flickr.com/photos/candiedwomanire/2238529

JEE vs Rails Java Beispielcode von Sebastian Hennebrueder http://www.laliluna.de id Customer name * Book id name author http://www.laliluna.de/ejb-3-struts-tutorial-jboss.html

/** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import java.util.set; JEE vs Rails import javax.persistence.cascadetype; import javax.persistence.entity; import javax.persistence.fetchtype; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.onetomany; import javax.persistence.sequencegenerator; import javax.persistence.table; /** * @author hennebrueder * */ @Entity @Table(name="customer") @SequenceGenerator(name="customer_sequence", sequencename="customer_id_seq") public class Customer { private Integer id; private String name; Customer id name private List books =new ArrayList(); public Customer(){ super(); public Customer(Integer id, String name){ super(); this.id=id; this.name=name; @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedby="customer", targetentity=book.class) public List getbooks() { return books; public void setbooks(list books) { this.books = books; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="customer_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String getname() { return name; public void setname(string name) { this.name = name; @Override public String tostring() { return "Customer: " + getid() + " Name " + getname();

Model -> Table @Entity @Table(name="customer") [..] public class Customer { Customer id name [..] Rails: class Customer < ActiveRecord::Base end Convention: Class Name = Customer => Table Name = Customers sonst: set_table_name( customer )

Primary Key [..] @SequenceGenerator(name="customer_sequence", sequencename="customer_id_seq") public class Customer { [..] Customer id name @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="customer_sequence") public Integer getid() { Rails: Entfällt. Convention: Primary Key => id, sequence

Relationen @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedby="customer", targetentity=book.class) public List getbooks() { return books; Customer id name public void setbooks(list books) { this.books = books; Rails: has_many :books Convention: targetentity = Singular des Entitätennames, sonst, :class_name = Book Getter/Setter dynamisch

Attributes private Integer id; private String name; private List books =new ArrayList(); public Customer(){ super(); public Customer(Integer id, String name){ super(); this.id=id; this.name=name; public Integer getid() { return id; public void setid(integer id) { this.id = id; public String getname() { return name; public void setname(string name) { this.name = name; Customer id name Rails: create_table :customers do t # keine id spalte t.column :name, :string end Convention: Name der Spalte = Name des Attributs Getter und Setter dynamisch

tostring() @Override public String tostring() { return "Customer: "+getid()+" Name "+getname(); Customer id name Rails: Entfällt, Default: #<Customer:0x2417c14 @attributes={"name"=>"donald Duck", "id"=>"1"> Alternativ: def to_s Customer: #{id Name #{name end => "Customer: 1 Name Donald Duck"

CustomerDAO, CustomerDAOImpl save/persist merge findall findbyid findbycustomer (BookDAO...) Customer id name Book id name author Rails: Alle Methoden bereits im Framework generisch enthalten findbyx dynamisch -> findbyname, findbyauthor, findbycustomer, findbytitleandauthor...

Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end

Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end

Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end

Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end

Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end

Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end

Migration Customer id name * Book id name author class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end

Der Code Customer id name * Book id name author class Customer < ActiveRecord::Base end has_many :books class Book < ActiveRecord::Base end belongs_to :customer

Perfection in Design This Wikipedia and Wikimedia Commons image is from the user Chris 73 and is freely available at http://commons.wikimedia.org/ wiki/image:antoine_de_saint-exup%c3%a9ry_lyon.jpg under the creative commons cc-by-sa 2.5 license.

Perfection in Design Antoine de Saint-Exupéry This Wikipedia and Wikimedia Commons image is from the user Chris 73 and is freely available at http://commons.wikimedia.org/ wiki/image:antoine_de_saint-exup%c3%a9ry_lyon.jpg under the creative commons cc-by-sa 2.5 license.

Perfection in Design You know you ve achieved perfection in design, not when you have nothing more to add, but when you have nothing more to take away. Antoine de Saint-Exupéry This Wikipedia and Wikimedia Commons image is from the user Chris 73 and is freely available at http://commons.wikimedia.org/ wiki/image:antoine_de_saint-exup%c3%a9ry_lyon.jpg under the creative commons cc-by-sa 2.5 license.

JEE vs Rails Migration Customer Book

/** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import java.util.set; import javax.persistence.cascadetype; import javax.persistence.entity; import javax.persistence.fetchtype; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.onetomany; import javax.persistence.sequencegenerator; import javax.persistence.table; /** * @author hennebrueder * */ @Entity @Table(name="customer") @SequenceGenerator(name="customer_sequence", sequencename="customer_id_seq") public class Customer { private Integer id; private String name; private List books =new ArrayList(); public Customer(){ super(); public Customer(Integer id, String name){ super(); this.id=id; this.name=name; @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedby="customer", targetentity=book.class) public List getbooks() { return books; public void setbooks(list books) { this.books = books; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="customer_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String getname() { return name; public void setname(string name) { this.name = name; @Override public String tostring() { return "Customer: " + getid() + " Name " + getname(); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.stateless; import javax.persistence.entity; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; /** * @author hennebrueder * */ @Stateless public class CustomerDaoImp implements CustomerDao { @PersistenceContext private EntityManager em; public static final String RemoteJNDIName = CustomerDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = CustomerDaoImp.class.getSimpleName() + "/local"; /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#save(de.laliluna.example.ejb.book) */ public void save(customer customer) { em.persist(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#reattach(de.laliluna.example.ejb.book) */ public void merge(customer customer) { em.merge(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findall() */ public List findall() { return em.createquery("from Customer").getResultList(); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findbyid(java.lang.integer) */ public Customer findbyid(integer id) { Customer customer = em.find(customer.class, id); return customer; /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import javax.ejb.stateful; import javax.ejb.stateless; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; import org.apache.log4j.logger; import sun.security.krb5.internal.crypto.bo; /** * @author hennebrueder * */ @Stateless public class BookDaoImp implements BookDao { @PersistenceContext private EntityManager em; private Logger log = Logger.getLogger(this.getClass()); /* * (non-javadoc) * * @see de.laliluna.example.ejb.bookdao#save(de.laliluna.example.ejb.book) */ public void save(book book) { log.debug("persist book: " + book); em.persist(book); public void merge(book book) { em.merge(book); public List findall() { log.debug("find All books"); return em.createquery("from Book").getResultList(); public static final String RemoteJNDIName = BookDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = BookDaoImp.class.getSimpleName() + "/local"; public Book findbyid(integer id) { return em.find(book.class, id); public List findbycustomer(customer customer) { log.debug("find by customer"); return em.createquery("from Book b where b.customer = :customer").setparameter("customer", customer).getresultlist(); package de.laliluna.library; import java.util.list; import javax.ejb.local; import org.jboss.annotation.ejb.localbinding; @Local public interface BookDao { public void save(book book); public void merge(book book); public List findall(); public List findbycustomer(customer customer); public Book findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.local; /** * @author hennebrueder * */ @Local public interface CustomerDao { public void save(customer customer); public void merge(customer customer); public List findall(); public Customer findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.io.serializable; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.joincolumn; import javax.persistence.manytoone; import javax.persistence.sequencegenerator; import javax.persistence.table; import org.hibernate.annotations.genericgenerator; /** * @author hennebrueder * */ @Entity @Table(name = "book") @SequenceGenerator(name = "book_sequence", sequencename = "book_id_seq") public class Book implements Serializable { private Integer id; private String title; private String author; private Customer customer; public Book() { super(); public Book(Integer id, String title, String author) { super(); this.id = id; this.title = title; this.author = author; @ManyToOne @JoinColumn(name = "customer_id") public Customer getcustomer() { return customer; public void setcustomer(customer customer) { this.customer = customer; public String getauthor() { return author; public void setauthor(string author) { this.author = author; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String gettitle() { return title; public void settitle(string title) { this.title = title; @Override public String tostring() { return "Book: " + getid() + " Title " + gettitle() + " Author " + getauthor(); JEE vs Rails Migration Customer Book

/** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import java.util.set; import javax.persistence.cascadetype; import javax.persistence.entity; import javax.persistence.fetchtype; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.onetomany; import javax.persistence.sequencegenerator; import javax.persistence.table; /** * @author hennebrueder * */ @Entity @Table(name="customer") @SequenceGenerator(name="customer_sequence", sequencename="customer_id_seq") public class Customer { private Integer id; private String name; private List books =new ArrayList(); public Customer(){ super(); public Customer(Integer id, String name){ super(); this.id=id; this.name=name; @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedby="customer", targetentity=book.class) public List getbooks() { return books; public void setbooks(list books) { this.books = books; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="customer_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String getname() { return name; public void setname(string name) { this.name = name; @Override public String tostring() { return "Customer: " + getid() + " Name " + getname(); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.stateless; import javax.persistence.entity; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; /** * @author hennebrueder * */ @Stateless public class CustomerDaoImp implements CustomerDao { @PersistenceContext private EntityManager em; public static final String RemoteJNDIName = CustomerDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = CustomerDaoImp.class.getSimpleName() + "/local"; /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#save(de.laliluna.example.ejb.book) */ public void save(customer customer) { em.persist(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#reattach(de.laliluna.example.ejb.book) */ public void merge(customer customer) { em.merge(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findall() */ public List findall() { return em.createquery("from Customer").getResultList(); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findbyid(java.lang.integer) */ public Customer findbyid(integer id) { Customer customer = em.find(customer.class, id); return customer; /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import javax.ejb.stateful; import javax.ejb.stateless; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; import org.apache.log4j.logger; import sun.security.krb5.internal.crypto.bo; /** * @author hennebrueder * */ @Stateless public class BookDaoImp implements BookDao { @PersistenceContext private EntityManager em; private Logger log = Logger.getLogger(this.getClass()); /* * (non-javadoc) * * @see de.laliluna.example.ejb.bookdao#save(de.laliluna.example.ejb.book) */ public void save(book book) { log.debug("persist book: " + book); em.persist(book); public void merge(book book) { em.merge(book); public List findall() { log.debug("find All books"); return em.createquery("from Book").getResultList(); public static final String RemoteJNDIName = BookDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = BookDaoImp.class.getSimpleName() + "/local"; public Book findbyid(integer id) { return em.find(book.class, id); public List findbycustomer(customer customer) { log.debug("find by customer"); return em.createquery("from Book b where b.customer = :customer").setparameter("customer", customer).getresultlist(); package de.laliluna.library; import java.util.list; import javax.ejb.local; import org.jboss.annotation.ejb.localbinding; @Local public interface BookDao { public void save(book book); public void merge(book book); public List findall(); public List findbycustomer(customer customer); public Book findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.local; /** * @author hennebrueder * */ @Local public interface CustomerDao { public void save(customer customer); public void merge(customer customer); public List findall(); public Customer findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.io.serializable; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.joincolumn; import javax.persistence.manytoone; import javax.persistence.sequencegenerator; import javax.persistence.table; import org.hibernate.annotations.genericgenerator; /** * @author hennebrueder * */ @Entity @Table(name = "book") @SequenceGenerator(name = "book_sequence", sequencename = "book_id_seq") public class Book implements Serializable { private Integer id; private String title; private String author; private Customer customer; public Book() { super(); public Book(Integer id, String title, String author) { super(); this.id = id; this.title = title; this.author = author; @ManyToOne @JoinColumn(name = "customer_id") public Customer getcustomer() { return customer; public void setcustomer(customer customer) { this.customer = customer; public String getauthor() { return author; public void setauthor(string author) { this.author = author; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String gettitle() { return title; public void settitle(string title) { this.title = title; @Override public String tostring() { return "Book: " + getid() + " Title " + gettitle() + " Author " + getauthor(); class Customer < ActiveRecord::Base has_many :books end class Book < ActiveRecord::Base belongs_to :customer end class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end JEE vs Rails Migration Customer Book

/** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import java.util.set; import javax.persistence.cascadetype; import javax.persistence.entity; import javax.persistence.fetchtype; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.onetomany; import javax.persistence.sequencegenerator; import javax.persistence.table; /** * @author hennebrueder * */ @Entity @Table(name="customer") @SequenceGenerator(name="customer_sequence", sequencename="customer_id_seq") public class Customer { private Integer id; private String name; private List books =new ArrayList(); public Customer(){ super(); public Customer(Integer id, String name){ super(); this.id=id; this.name=name; @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedby="customer", targetentity=book.class) public List getbooks() { return books; public void setbooks(list books) { this.books = books; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="customer_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String getname() { return name; public void setname(string name) { this.name = name; @Override public String tostring() { return "Customer: " + getid() + " Name " + getname(); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.stateless; import javax.persistence.entity; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; /** * @author hennebrueder * */ @Stateless public class CustomerDaoImp implements CustomerDao { @PersistenceContext private EntityManager em; public static final String RemoteJNDIName = CustomerDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = CustomerDaoImp.class.getSimpleName() + "/local"; /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#save(de.laliluna.example.ejb.book) */ public void save(customer customer) { em.persist(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#reattach(de.laliluna.example.ejb.book) */ public void merge(customer customer) { em.merge(customer); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findall() */ public List findall() { return em.createquery("from Customer").getResultList(); /* (non-javadoc) * @see de.laliluna.example.ejb.customerdao#findbyid(java.lang.integer) */ public Customer findbyid(integer id) { Customer customer = em.find(customer.class, id); return customer; /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.arraylist; import java.util.list; import javax.ejb.stateful; import javax.ejb.stateless; import javax.persistence.entitymanager; import javax.persistence.persistencecontext; import org.apache.log4j.logger; import sun.security.krb5.internal.crypto.bo; /** * @author hennebrueder * */ @Stateless public class BookDaoImp implements BookDao { @PersistenceContext private EntityManager em; private Logger log = Logger.getLogger(this.getClass()); /* * (non-javadoc) * * @see de.laliluna.example.ejb.bookdao#save(de.laliluna.example.ejb.book) */ public void save(book book) { log.debug("persist book: " + book); em.persist(book); public void merge(book book) { em.merge(book); public List findall() { log.debug("find All books"); return em.createquery("from Book").getResultList(); public static final String RemoteJNDIName = BookDaoImp.class.getSimpleName() + "/remote"; public static final String LocalJNDIName = BookDaoImp.class.getSimpleName() + "/local"; public Book findbyid(integer id) { return em.find(book.class, id); public List findbycustomer(customer customer) { log.debug("find by customer"); return em.createquery("from Book b where b.customer = :customer").setparameter("customer", customer).getresultlist(); package de.laliluna.library; import java.util.list; import javax.ejb.local; import org.jboss.annotation.ejb.localbinding; @Local public interface BookDao { public void save(book book); public void merge(book book); public List findall(); public List findbycustomer(customer customer); public Book findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Mar 15, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.util.list; import javax.ejb.local; /** * @author hennebrueder * */ @Local public interface CustomerDao { public void save(customer customer); public void merge(customer customer); public List findall(); public Customer findbyid(integer id); /** * * @author Sebastian Hennebrueder * created Feb 27, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.library; import java.io.serializable; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.joincolumn; import javax.persistence.manytoone; import javax.persistence.sequencegenerator; import javax.persistence.table; import org.hibernate.annotations.genericgenerator; /** * @author hennebrueder * */ @Entity @Table(name = "book") @SequenceGenerator(name = "book_sequence", sequencename = "book_id_seq") public class Book implements Serializable { private Integer id; private String title; private String author; private Customer customer; public Book() { super(); public Book(Integer id, String title, String author) { super(); this.id = id; this.title = title; this.author = author; @ManyToOne @JoinColumn(name = "customer_id") public Customer getcustomer() { return customer; public void setcustomer(customer customer) { this.customer = customer; public String getauthor() { return author; public void setauthor(string author) { this.author = author; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_sequence") public Integer getid() { return id; public void setid(integer id) { this.id = id; public String gettitle() { return title; public void settitle(string title) { this.title = title; @Override public String tostring() { return "Book: " + getid() + " Title " + gettitle() + " Author " + getauthor(); class Customer < ActiveRecord::Base has_many :books end class Book < ActiveRecord::Base belongs_to :customer end class Initial < ActiveRecord::Migration def self.up create_table :books do t t.column :name, :string t.column :author, :string t.column :customer_id, :integer end create_table :customers do t t.column :name, :string end end def self.down drop_table :books drop_table :customers end end JEE vs Rails Migration Customer Book Conventions at work!

Signal / Noise

Signal / Noise public void testbook() { Book book = new Book(null,"My first bean book", "Sebastian"); em.persist(book); Book book2 = new Book(null,"another book", "Paul"); em.persist(book2); Book book3 = new Book(null,"EJB 3 developer guide","sebastian"); em.persist(book3); [..] def test_book book = Book.create(:name => "My first bean book", :author => "Sebastian") book2 = Book.create(:name => "another book", :author => "Paul") book3 = Book.create(:name => "EJB 3 dev guide", :author => "Sebastian") [..]

Signal / Noise public void testbook() { Book book = new Book(null,"My first bean book", "Sebastian"); em.persist(book); Book book2 = new Book(null,"another book", "Paul"); em.persist(book2); Book book3 = new Book(null,"EJB 3 developer guide","sebastian"); em.persist(book3); [..] def test_book book = Book.create(:name => "My first bean book", :author => "Sebastian") book2 = Book.create(:name => "another book", :author => "Paul") book3 = Book.create(:name => "EJB 3 dev guide", :author => "Sebastian") [..]

Signal / Noise [..] System.out.println("list some books"); List somebooks = em.createquery("from Book b where b.author=:name").setparameter("name", "Sebastian").getResultList(); for (Iterator iter = somebooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); System.out.println("list all books"); List allbooks = em.createquery("from Book").getResultList(); for (Iterator iter = allbooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); [..] puts "list some books" Book.find_all_by_author("Sebastian").each { book puts book.inspect puts "list all books" Book.find(:all).each { book puts book.inspect

Signal / Noise [..] System.out.println("list some books"); List somebooks = em.createquery("from Book b where b.author=:name").setparameter("name", "Sebastian").getResultList(); for (Iterator iter = somebooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); System.out.println("list all books"); List allbooks = em.createquery("from Book").getResultList(); for (Iterator iter = allbooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); [..] puts "list some books" Book.find_all_by_author("Sebastian").each { book puts book.inspect puts "list all books" Book.find(:all).each { book puts book.inspect

Signal / Noise [..] System.out.println("list some books"); List somebooks = em.createquery("from Book b where b.author=:name").setparameter("name", "Sebastian").getResultList(); for (Iterator iter = somebooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); JDK 1.5 to the rescue (Generics, foreach) System.out.println("list all books"); List allbooks = em.createquery("from Book").getResultList(); for (Iterator iter = allbooks.iterator(); iter.hasnext();){ Book element = (Book) iter.next(); System.out.println(element); [..] puts "list some books" Book.find_all_by_author("Sebastian").each { book puts book.inspect puts "list all books" Book.find(:all).each { book puts book.inspect

Signal / Noise public void testrelation() { [..] Drei Books und zwei Customers angelegt customer1.getbooks().add(book); book.setcustomer(customer1); customer2.getbooks().add(book2); customer2.getbooks().add(book3); [..] Drei Books und zwei Customers angelegt customer1.books << book customer2.books << [book2, book3]

Signal / Noise public void testrelation() { [..] Drei Books und zwei Customers angelegt customer1.getbooks().add(book); book.setcustomer(customer1); customer2.getbooks().add(book2); customer2.getbooks().add(book3); [..] Drei Books und zwei Customers angelegt customer1.books << book customer2.books << [book2, book3]

Und mehr... class Book < ActiveRecord::Base belongs_to :customer has_many :chapters has_many :sections, :through => :chapters validates_presence_of :author validates_uniqueness_of :name validates_length_of :name, :within => 6..20, :too_long => "pick shorter name", :too_short => "pick longer name" end

Batteries included Rails bringt einiges mit: Struktur Build Testunterstützung Entwicklungs-, Test- und Produktionsumgebung Kein eigenes Denken notwendig Skripte und Automatismen verwenden gleiche Lokationen

Applikation

Applikation

Applikation

Applikation

Applikation

Applikation

Applikation

Applikation

Applikation

Applikation

Umgebung / Konfiguration

Umgebung / Konfiguration

Umgebung / Konfiguration

Umgebung / Konfiguration

Umgebung / Konfiguration

Umgebung / Konfiguration

Umgebung / Konfiguration

Umgebung / Konfiguration

Umgebung / Konfiguration

Umgebung / Konfiguration

Static Content / Skripte

Static Content / Skripte

Static Content / Skripte

Static Content / Skripte

Static Content / Skripte

Static Content / Skripte

Static Content / Skripte

Static Content / Skripte

Test

Test

Test

Test

Test

Test

Test

Test

wie geht s weiter?

Why The Lucky Stiff s: http://tryruby.hobix.com/ Inklusive Tutorial

A language that doesn t affect the way you think about programming is not worth knowing Alan Perlis

A language that doesn t affect the way you think about programming is not worth knowing Alan Perlis Jim Weirich s: 10 Things Every Java Programmer Should Now About Ruby http://onestepback.org/articles/10things/ Viele Dinge in dieser Präsentation dort geklaut.

Pickaxe 2nd edition Umfassend

The Ruby Way Umfassend Detailliert Zweites Buch?

Ruby for Rails Metaprogrammierung

Creating a Weblog in 15 Minutes http://media.rubyonrails.org/video/rails_take2_with_sound.mov

Agile Web Development with Rails (AWDR) 2nd Edition in Vorbereitung 1st Edition auch in Deutsch erhältlich

Rapid Web Development mit Ruby on Rails Deutsch 2nd Edition gerade erschienen

Weiterführend

http://rubyonrails.org http://ruby-lang.org

... und so lebten sie...

... glücklich...

... bis an s Ende ihrer Tage.

Danke! The text of this presentation is licensed under the Creative Commons License, Attribution-ShareAlike 2.5. As I don t have all the rights to the images in this presentation, the images and the Java source code are not covered by this license. I would also like to thank Babie Tanaka and the flickr users letioux and candiedwomanire that granted me the right to use their images. This work is licensed under the Creative Commons Attribution-ShareAlike 2.5 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.5/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.