EMZETT.
Login

Kurz: 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.

Teil des Kurses Ruby

Kapitel 11 von 12 im Kurs Ruby (Abschnitt „Ökosystem“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

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
end

Start 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

Ausgabe:

/ -> 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              # Tests

Die Struktur (MVC):

TeilOrdnerAufgabe
Modelapp/modelsDaten und Geschäftslogik (ActiveRecord)
Viewapp/viewsHTML-Templates (ERB)
Controllerapp/controllersAnfragen entgegennehmen, Antwort wählen
Routenconfig/routes.rbURL -> Controller
Migrationendb/migrateDatenbankschema
# 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 vermeiden

Weitere Einsatzgebiete

BereichWerkzeug
HintergrundjobsSidekiq, GoodJob, Solid Queue
AutomatisierungRake, Thor (CLIs), Chef/Puppet
Static SitesJekyll, Middleman, Bridgetown
Tests/QARSpec, Capybara, Cucumber
Spiele/GrafikGosu, Ruby2D
Skriptingeingebettet (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, Fiber und der async-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 includes vermeiden

Übungsaufgabe

Skizziere in Worten die Rails-Modelle für ein Blog (Artikel, Kommentare, Nutzer) und ihre Beziehungen.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Tests, Gems und Bundler

Weiter: Referenz und Spickzettel

Alle Kapitel: Ruby im Überblick