Ruby im Web
Das bekannteste Webframework ist Ruby on Rails (2004). Prinzipien: Konvention vor Konfiguration (sinnvolle Standardnamen statt langer Einstellungen) und DRY (Don't Repeat Yourself). Rails bringt alles mit: Routing, Datenbank (ActiveRecord), Templates, Mailer, Hintergrundjobs, Tests, Sicherheit.
Leichtere Alternativen: Sinatra (Mini-Framework), Hanami, Roda, Rack (die gemeinsame Schnittstelle).
Sinatra: ein Webserver in fünf Zeilen
require "sinatra"
require "json"
get "/" do
"Hallo Welt"
end
get "/gruss/:name" do
"Hallo, #{params[:name]}!"
end
post "/api/echo" do
content_type :json
daten = JSON.parse(request.body.read)
{ empfangen: daten }.to_json
endStart mit ruby app.rb, dann http://localhost:4567.
Rack: das Fundament
Jede Rack-App ist ein Objekt, das call(env) versteht und [status, header, body] liefert. Wir testen so eine App ohne Server:
class MiniApp
def call(env)
pfad = env["PATH_INFO"]
case pfad
when "/" then [200, { "content-type" => "text/plain" }, ["Startseite"]]
when %r{\A/nutzer/(\d+)\z} then [200, { "content-type" => "text/plain" }, ["Nutzer #{$1}"]]
else [404, { "content-type" => "text/plain" }, ["nicht gefunden"]]
end
end
end
app = MiniApp.new
["/", "/nutzer/42", "/gibtsnicht"].each do |pfad|
status, header, body = app.call("PATH_INFO" => pfad)
puts "#{pfad} -> #{status} #{header['content-type']} #{body.join}"
end/ -> 200 text/plain Startseite /nutzer/42 -> 200 text/plain Nutzer 42 /gibtsnicht -> 404 text/plain nicht gefunden
Rails im Überblick
gem install rails
rails new blog # Projekt anlegen
cd blog
rails generate scaffold Artikel titel:string text:text
rails db:migrate # Tabellen anlegen
rails server # http://localhost:3000
rails console # interaktiv mit der App arbeiten
rails test # TestsDie Struktur (MVC):
| Teil | Ordner | Aufgabe |
|---|---|---|
| Model | app/models | Daten und Geschäftslogik (ActiveRecord) |
| View | app/views | HTML-Templates (ERB) |
| Controller | app/controllers | Anfragen entgegennehmen, Antwort wählen |
| Routen | config/routes.rb | URL -> Controller |
| Migrationen | db/migrate | Datenbankschema |
# app/models/artikel.rb
class Artikel < ApplicationRecord
has_many :kommentare, dependent: :destroy
validates :titel, presence: true, length: { maximum: 120 }
scope :neueste, -> { order(created_at: :desc).limit(5) }
end
# app/controllers/artikel_controller.rb
class ArtikelController < ApplicationController
def index
@artikel = Artikel.neueste
end
def create
@artikel = Artikel.new(artikel_params)
if @artikel.save
redirect_to @artikel, notice: "Gespeichert"
else
render :new, status: :unprocessable_entity
end
end
private
def artikel_params = params.require(:artikel).permit(:titel, :text)
end
# config/routes.rb
Rails.application.routes.draw do
resources :artikel
root "artikel#index"
end<%# app/views/artikel/index.html.erb %>
<h1>Artikel</h1>
<% @artikel.each do |a| %>
<h2><%= link_to a.titel, a %></h2>
<p><%= truncate(a.text, length: 100) %></p>
<% end %><%= %> gibt aus (HTML wird automatisch escaped), <% %> führt nur aus.
ActiveRecord: Datenbank wie Ruby-Objekte
Artikel.create(titel: "Hallo", text: "Welt")
Artikel.find(1)
Artikel.where(titel: "Hallo").order(:created_at).first
Artikel.where("created_at > ?", 1.week.ago).count
artikel.update(titel: "Neu")
artikel.destroy
Artikel.includes(:kommentare).each { |a| a.kommentare.size } # N+1-Problem vermeidenWeitere Einsatzgebiete
| Bereich | Werkzeug |
|---|---|
| Hintergrundjobs | Sidekiq, GoodJob, Solid Queue |
| Automatisierung | Rake, Thor (CLIs), Chef/Puppet |
| Static Sites | Jekyll, Middleman, Bridgetown |
| Tests/QA | RSpec, Capybara, Cucumber |
| Spiele/Grafik | Gosu, Ruby2D |
| Skripting | eingebettet (z. B. in Metasploit, Homebrew) |
Performance und Betrieb
- Ruby 3 ist deutlich schneller als 2.x (YJIT-Compiler:
ruby --yjit) - Nebenläufigkeit: Threads (mit GVL),
Ractor,Fiberund derasync-Gem - Deployment: Puma als Server, Docker, Kamal, Heroku, Render, Fly.io
Merke
- Rails: MVC, Konvention vor Konfiguration, ActiveRecord, Migrationen
- Sinatra/Rack für schlanke Dienste
rails new,generate,db:migrate,server,console,test- N+1-Abfragen mit
includesvermeiden
Aufgabe
Skizziere in Worten die Rails-Modelle für ein Blog (Artikel, Kommentare, Nutzer) und ihre Beziehungen.