Ruby Framework

Ruby on Rails

Rails ist das Full-Stack Ruby-Framework, das auf dem Prinzip „Convention over Configuration“ basiert. Es übernimmt die langweiligen Teile – Dateinamen, Tabellennamen, Routen –, damit Sie Ihre Zeit in das Produkt investieren können.

intermediate15 min readUpdated 16. Sept. 2026
app/controllers/posts_controller.rb
ruby
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: %i[show update destroy]

  def index
    @posts = Post.includes(:author).published.recent
  end

  def create
    @post = Current.user.posts.build(post_params)
    if @post.save
      redirect_to @post, notice: "Post created"
    else
      render :new, status: :unprocessable_entity
    end
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    params.require(:post).permit(:title, :body)
  end
end
Veröffentlicht
2004
Erstellt von
David Heinemeier Hansson
Sprache
Ruby
Stil
Convention over configuration
Datenlayer
Active Record ORM
Version
8.x

Warum es wichtig ist

Warum die Entwicklung mit Rails so schnell geht

CRUD an einem Nachmittag

Generators, Migrationen und Scaffolding verwandeln ein Datenmodell in Stunden statt Wochen in eine funktionierende, datenbankgestützte Anwendung.

Convention over configuration

Sinnvolle Standardwerte legen Dateinamen, Tabellennamen und Routen fest. Sie überschreiben diese nur, wenn Ihre Domäne tatsächlich etwas anderes benötigt.

Gems für alles

Für Authentifizierung, Zahlungen, Datei-Uploads, Suche und Admin-Dashboards gibt es ausgereifte, praxiserprobte Gems, die von der Community gepflegt werden.

Das Gesamtbild

MVC, Conventions, Gems

Rails gibt jedem Request die gleiche Struktur: eine Route, ein Controller, ein Model und eine View, benannt so, wie das Framework es bereits erwartet.

Convention over configuration

Entscheiden

Das Framework trifft die Standardentscheidung, sodass Sie es nie tun müssen. Ein Post-Model wird ohne Konfiguration einer posts-Tabelle und einer /posts-Route zugeordnet.

Active Record

Persistieren

Models kapseln Datenbanktabellen mit Assoziationen, Validierungen, Scopes und Migrationen, wodurch SQL aus Ihrem täglichen Code verschwindet.

RESTful resources

Exponieren

resources :posts definiert die sieben konventionellen CRUD-Routen, und Controller folgen für jede Ressource den gleichen Aktionen.

HTML5 auf einen Blick

Die Rails-Toolbox

RESTful routes

resources :posts bietet Ihnen index, show, new, create, edit, update und destroy.

Active Record

Models, Assoziationen und Migrationen beschreiben Ihr Schema in Ruby.

MVC

Controller koordinieren, Models halten die Domäne, Views rendern die Antwort.

Generators

rails generate schreibt Models, Controller, Migrationen und Tests für Sie.

Hotwire

Turbo und Stimulus fügen Interaktivität hinzu, ohne dass eine separate SPA nötig ist.

Background jobs

Active Job zusammen mit Sidekiq führt zeitintensive Aufgaben außerhalb des Request-Zyklus aus.

Eine kurze Geschichte

Zwei Jahrzehnte des Rails-Ways

  1. 2004

    Rails wird aus Basecamp ausgegliedert

    David Heinemeier Hansson extrahiert ein Framework aus der Basecamp-Codebasis und veröffentlicht es als Open Source.

    04
  2. 2005

    Rails 1.0

    Das erste stabile Release macht „Convention over Configuration“ zu einer Mainstream-Idee in der Webentwicklung.

    05
  3. 2008

    Rails 2

    REST wird zum Standard-Routing-Stil und Resources prägen jeden Controller.

    08
  4. 2010

    Rails 3 und Bundler

    Eine sauberere API, Bundler für Abhängigkeiten und die Fusion mit Merb modernisieren den Stack.

    10
  5. 2016

    Rails 5 und Action Cable

    WebSockets ziehen in den Core ein, und der API-only-Modus richtet sich an Single-Page-Frontends.

    16
  6. 2021

    Rails 7 und Hotwire

    Turbo und Stimulus ersetzen Turbolinks, und Import Maps liefern JavaScript ohne Bundler aus.

    21
  7. 2024

    Rails 8

    Solid Queue, Solid Cache und Solid Cable laufen auf der Datenbank, und Kamal vereinfacht das Deployment.

    24

Der vollständige Leitfaden

Ruby on Rails: Alles was Sie wissen müssen

Was ist Ruby on Rails?

Rails ist ein Full-Stack-Web-Framework für Ruby. Es liefert alles mit, was eine datenbankgestützte Webanwendung benötigt: ein ORM, ein Router, ein View-Layer, Background-Jobs, Mailer, Caching, WebSockets und ein Test-Harness. Anstatt diese Komponenten selbst auszuwählen und zu verdrahten, erhalten Sie einen kohärenten Stack, der darauf ausgelegt ist, nahtlos zusammenzuarbeiten.

Die definierende Idee ist Convention over Configuration. Das Framework geht von einer sinnvollen Struktur aus — Post befindet sich in app/models/post.rb, wird einer posts-Tabelle zugeordnet und wird von PostsController bereitgestellt — und Sie schreiben nur dann Konfigurationen, wenn Sie von diesen Konventionen abweichen. Das Rails-Team nennt diese Philosophie Omakase, die Wahl des Kochs: Vertrauen Sie den Standardeinstellungen, und Sie werden schneller vorankommen.

Dieser Ansatz ist der Grund, warum Rails seit zwanzig Jahren Produkte von Basecamp und GitHub bis hin zu Shopify und HEY antreibt und warum ein einzelner Entwickler immer noch in einem Wochenende eine ernsthafte Anwendung veröffentlichen kann.

Convention over Configuration

Jedes Rails-Projekt hat das gleiche Grundgerüst, sodass du dich nie fragen musst, wo eine bestimmte Datei hingehört.

app/
├── controllers/    # request handling
├── models/         # domain and persistence
├── views/          # templates
├── jobs/           # background work
├── mailers/        # email
└── javascript/     # Stimulus controllers
config/
├── routes.rb       # the URL map
└── database.yml    # connection settings
db/
└── migrate/        # schema history

Der Vorteil ist die Vorhersehbarkeit. Ein neuer Entwickler öffnet das Repository und weiß sofort, dass sich das User-Model in app/models/user.rb befindet und die dazugehörige Tabelle users heißt. Benennungen sind hier keine Stilfrage, sondern eine Schnittstelle, auf die sich das Framework verlässt.

Der MVC-Request-Zyklus

Rails ist ein Model-View-Controller-Framework, und jeder HTTP-Request folgt demselben Pfad:

  1. Das Routing ordnet die URL einer Controller-Action zu.
  2. Der Controller lädt oder ändert Daten über Models.
  3. Models setzen die Domänenlogik durch und kommunizieren mit der Datenbank.
  4. Ein View rendert die Antwort, meist als HTML.
# config/routes.rb
Rails.application.routes.draw do
  resources :posts
  root "posts#index"
end

Ein Request an GET /posts landet bei PostsController#index, welcher @posts vorbereitet, woraufhin app/views/posts/index.html.erb gerendert wird. Jede Schicht auf ihre Kernaufgabe zu fokussieren, sorgt dafür, dass eine Rails-App auch bei wachsender Größe wartbar bleibt.

Die Kommandozeile ist das Framework

Sie werden Rails kaum über Konfigurationsdateien berühren. Der Großteil der Arbeit findet im Terminal statt.

rails new shop --database=postgresql
cd shop

bin/rails generate scaffold Post title:string body:text published:boolean
bin/rails generate model Comment post:references body:text
bin/rails generate controller Pages home about

bin/rails db:create db:migrate
bin/rails server

generate schreibt das Model, die Migration, den Controller, die Routes, die Views und die Tests für Sie, und die Ausgabe des Generators teilt Ihnen mit, was geändert wurde. Lesen Sie jede generierte Datei, bevor Sie diese übernehmen – der schnellste Weg, Rails zu lernen, besteht darin, zu studieren, was das Framework schreibt, und anschließend alles zu löschen, was Sie nicht benötigen.

Active Record: Die Model-Layer

Active Record ist das ORM. Eine Model-Klasse kapselt eine Datenbanktabelle, und eine Instanz kapselt eine einzelne Zeile.

Migrations

Migrations sind versionierte, umkehrbare Schema-Änderungen, die in db/migrate gespeichert werden. Sie sind der einzige unterstützte Weg, um die Datenbank zu ändern.

class CreatePosts < ActiveRecord::Migration[8.0]
  def change
    create_table :posts do |t|
      t.string :title, null: false
      t.text :body, null: false
      t.boolean :published, default: false, null: false
      t.references :author, null: false, foreign_key: { to_table: :users }
      t.timestamps
    end

    add_index :posts, %i[published created_at]
  end
end

Führe bin/rails db:migrate aus, um sie anzuwenden, und bin/rails db:rollback, um sie rückgängig zu machen. Da change umkehrbar ist, weiß Rails, wie die Operationen rückgängig gemacht werden können, ohne dass du eine down-Methode schreiben musst.

Associations

Associations beschreiben Beziehungen und generieren komfortable Methoden.

class User < ApplicationRecord
  has_many :posts, dependent: :destroy
  has_many :comments, through: :posts
end

class Post < ApplicationRecord
  belongs_to :author, class_name: "User", inverse_of: :posts
  has_many :comments, dependent: :destroy
  has_one_attached :cover
end

Sobald dies eingerichtet ist, funktionieren user.posts, post.author und post.comments.create(body: "...") alle, und dependent: :destroy verhindert, dass verwaiste Zeilen in der Datenbank verbleiben.

Validations und Scopes

Validations schützen die Domain auf der Model-Layer, über die jeder Schreibzugriff läuft.

class Post < ApplicationRecord
  validates :title, presence: true, length: { maximum: 120 }
  validates :body, presence: true
  validates :slug, uniqueness: true

  scope :published, -> { where(published: true) }
  scope :recent, -> { order(created_at: :desc) }

  before_validation :generate_slug, on: :create

  private

  def generate_slug
    self.slug ||= title.to_s.parameterize
  end
end

Scopes geben Relations zurück und sind daher kombinierbar: Post.published.recent.limit(20) liest sich wie ein Satz und wird als eine einzige Query ausgeführt. Wenn ein Scope länger als ein oder zwei Zeilen wird, solltest du ihn in eine Klassenmethode umwandeln, damit er lesbar bleibt.

N+1 Queries vermeiden

Das häufigste Performance-Problem in Rails ist die N+1 Query: eine Query für eine Liste und dann eine weitere Query für die Association jeder einzelnen Zeile.

# Two queries total, no matter how many posts.
posts = Post.includes(:author, :comments).recent

posts.each do |post|
  puts "#{post.title} by #{post.author.name}"
end

Nutze includes, wenn du auf die Association zugreifen wirst, preload, wenn du eine separate Query möchtest, und eager_load, wenn du zusätzlich nach der Association filterst. Füge das bullet-Gem zur Development-Umgebung hinzu, damit jede N+1 Query markiert wird, bevor sie die Production erreicht.

Controller und RESTful Routes

resources definiert die konventionellen CRUD-Routes und ordnet sie Controller-Actions mit entsprechenden Namen zu.

# config/routes.rb
Rails.application.routes.draw do
  resources :posts do
    resources :comments, only: %i[index create destroy]
  end

  namespace :api do
    namespace :v1 do
      resources :posts, only: %i[index show create update destroy]
    end
  end
end

Controller bleiben “thin”. Sie laden Daten, rufen die Domain auf und wählen eine Antwort aus. Die Business-Logik gehört in Models oder Service-Objekte, nicht in die Actions.

class PostsController < ApplicationController
  before_action :set_post, only: %i[show update destroy]

  def index
    @posts = Post.published.includes(:author).recent
  end

  def create
    @post = Post.new(post_params)
    if @post.save
      redirect_to @post, notice: "Post created."
    else
      render :new, status: :unprocessable_entity
    end
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    params.require(:post).permit(:title, :body, :published, tag_ids: [])
  end
end

Strong Parameters sind nicht optional. params.require(:post).permit(...) ist die Grenze, die verhindert, dass ein Client Spalten setzt, die niemals dafür vorgesehen waren, wie zum Beispiel admin oder role.

Views, ERB und Layouts

Views sind ERB-Templates: HTML mit eingebettetem Ruby. Rails escaped die Ausgabe standardmäßig, wodurch eine ganze Klasse von Cross-Site-Scripting-Bugs eliminiert wird.

<%# app/views/posts/index.html.erb %>
<h1>Posts</h1>

<%= link_to "New post", new_post_path %>

<ul>
  <% @posts.each do |post| %>
    <li>
      <%= link_to post.title, post %>
      <span><%= pluralize(post.comments.size, "comment") %></span>
    </li>
  <% end %>
</ul>

Nutzen Sie <%= %> für die Ausgabe und <% %> zur Ausführung ohne Ausgabe. Ein Layout in app/views/layouts/application.html.erb umschließt jede Seite, und Partials – Dateien, die mit einem Unterstrich beginnen – ermöglichen es Ihnen, Markup mit render "post", post: post oder einfach render @posts wiederzuverwenden.

Hotwire: Turbo und Stimulus

Modernes Rails ermöglicht Interaktivität, ohne dass eine Single-Page-App erforderlich ist. Turbo fängt Links und Formulare ab und tauscht Seitenfragmente über das Netzwerk aus; Stimulus fügt kleine JavaScript-Verhaltensweisen dort hinzu, wo sie tatsächlich benötigt werden.

<%# Turbo Frames scope an update to one part of the page %>
<%= turbo_frame_tag "comments" do %>
  <%= render @post.comments %>
<% end %>
// app/javascript/controllers/dropdown_controller.js
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["menu"];

  toggle() {
    this.menuTarget.classList.toggle("hidden");
  }
}

Das ist Progressive Enhancement in der Praxis: Server-gerendertes HTML bildet die Basis, und JavaScript wertet diese auf. Die meisten Rails-Apps benötigen niemals einen clientseitigen Router.

Assets und import maps

Rails 7 hat die alte Sprockets-Pipeline standardmäßig durch import maps ersetzt und bietet Propshaft als einfachere Asset-Pipeline an. So können Sie eine Library einbinden (pinnen), ohne einen Node-Build-Schritt zu benötigen.

bin/importmap pin local-time
bin/rails assets:precompile

Wenn Sie lieber einen Bundler verwenden möchten, schalten bin/rails javascript:install:esbuild oder :vite das Setup um. Das Prinzip bleibt dasselbe: Liefern Sie das aus, was der Browser versteht, und halten Sie die Toolchain so weit wie möglich heraus, bis sie tatsächlich benötigt wird.

Background-Jobs

Alles, was langsam ist – das Versenden von E-Mails, API-Aufrufe, das Erstellen von Berichten –, gehört in einen Job und nicht in den Request. Active Job dient dabei als gemeinsame Schnittstelle; der Adapter entscheidet, wo die Jobs ausgeführt werden.

class PublishPostJob < ApplicationJob
  queue_as :default

  retry_on Net::ReadTimeout, wait: :polynomially_longer, attempts: 5

  def perform(post_id)
    Post.find(post_id).publish!
  end
end

PublishPostJob.perform_later(post.id)
# config/application.rb
config.active_job.queue_adapter = :solid_queue # or :sidekiq

Rails 8 wird mit Solid Queue ausgeliefert, wodurch Jobs direkt in der Datenbank gespeichert werden und kein Redis benötigt wird. So hat eine Single-Server-App eine Komponente weniger, die gewartet werden muss. Sidekiq bleibt bei hohem Volumen eine starke Option.

Testing

Rails generiert für alles, was es erstellt, automatisch Tests. Minitest ist bereits integriert und schnell; RSpec ist die beliebte Alternative mit einer ausdrucksstärkeren Syntax.

# test/models/post_test.rb
require "test_helper"

class PostTest < ActiveSupport::TestCase
  test "requires a title" do
    post = Post.new(body: "Hello")
    assert_not post.valid?
    assert_includes post.errors[:title], "can't be blank"
  end
end
# spec/models/post_spec.rb
RSpec.describe Post, type: :model do
  it "is invalid without a title" do
    expect(Post.new(body: "Hello")).not_to be_valid
  end
end

Controller-Tests führen echte Anfragen im Prozess aus, wodurch Routing- und Parameter-Fehler abgefangen werden, die Unit-Tests übersehen.

# test/controllers/posts_controller_test.rb
class PostsControllerTest < ActionDispatch::IntegrationTest
  test "lists published posts" do
    Post.create!(title: "Hi", body: "There", published: true)
    get posts_url
    assert_response :success
  end
end

Führen Sie alles mit bin/rails test oder bundle exec rspec aus. Fügen Sie bin/rails test:system für browsergesteuerte System-Tests hinzu, wenn ein Flow wichtig genug ist, um ihn End-to-End zu testen.

Die Rails Console

bin/rails console bootet deine Anwendung, wobei jedes Model und jeder Helper verfügbar ist. Es ist der schnellste Weg, um Daten zu explorieren, eine Query zu testen und einen Bug zu reproduzieren.

bin/rails console
bin/rails console --sandbox   # rolls back all changes on exit
Post.published.recent.limit(5)
Post.where(published: false).update_all(published: true)
Post.includes(:author).find_each { |post| puts post.title }

--sandbox dient als Sicherheitsnetz während deiner Experimente: Jeder Schreibvorgang wird beim Beenden zurückgerollt (rolled back).

Best Practices

  • Halten Sie Controller schlank; verschieben Sie die Domain-Logik in Models oder Service-Objekte.
  • Nutzen Sie Eager Loading für Assoziationen mit includes und achten Sie in den Logs auf N+1-Queries.
  • Ändern Sie die Datenbank ausschließlich über Migrationen und committen Sie diese zusammen mit dem Code.
  • Verwenden Sie Strong Parameters für jeden Schreibvorgang und validieren Sie auf der Model-Ebene.
  • Fügen Sie Datenbank-Indizes für die Spalten hinzu, nach denen Sie filtern und sortieren.
  • Lagern Sie zeitintensive Aufgaben in Background Jobs aus, anstatt sie im Request-Zyklus auszuführen.
  • Schreiben Sie für jeden behobenen Bug einen Test und halten Sie die Test-Suite performant.

Häufige Fehler

  • Das Rendern einer Liste ohne includes, was zu einem N+1-Problem in der Production führt.
  • Das Platzieren von Business-Logik in Controllern, bis die Actions hunderte Zeilen lang sind.
  • Die direkte Verwendung von params[:post] anstelle von Strong Parameters.
  • Das manuelle Editieren von db/schema.rb anstatt einer Migration zu schreiben.
  • Das Vergessen von dependent:-Optionen, wodurch verwaiste Datensätze zurückbleiben.
  • Der Griff zu einem Service Object oder einem Gem, bevor das Model dies wirklich benötigt.
  • Das Ausführen komplexer Queries in Views anstatt die Daten im Controller zu laden.

Wie geht es weiter?

Rails vermittelt eine beständige Denkweise: Ressourcen, Konventionen und ein fester Platz für jedes Anliegen. Wenn Ihnen das „Batteries-included“-Modell gefällt, verfolgt Laravel dieselbe Philosophie in PHP, während Django dies in Python tut. Da das Routing in Rails auf Ressourcen basiert, erläutert der Guide zu REST APIs die dahinterstehenden Konzepte. Und da die meisten Rails-Apps auf einer relationalen Datenbank laufen, sollten Sie als Nächstes Ihr Wissen über PostgreSQL vertiefen.

In der Praxis

Die vier Dateien hinter einer Ressource

Wechseln Sie zwischen Route, Controller, Model und Migration, um zu sehen, wie Rails eine Ressource miteinander verknüpft.

config/routes.rb
Rails.application.routes.draw do
  resources :posts do
    resources :comments, only: %i[index create destroy]
    member do
      post :publish
    end
  end

  namespace :api do
    namespace :v1 do
      resources :posts, only: %i[index show create update destroy]
    end
  end

  root "posts#index"
end

Laden von Assoziationen

Der Zugriff auf eine Assoziation innerhalb einer Schleife löst eine Abfrage pro Zeile aus. Laden Sie diese einmal eager, und die gesamte Seite benötigt nur zwei Abfragen.

Bevorzugt
posts = Post.includes(:author, :comments).recent
posts.each { |post| puts post.author.name }
Vermeiden
posts = Post.recent
posts.each { |post| puts post.author.name }
# one query per post: the classic N+1

Annahme von Inputs

Strong Parameters definieren eine Whitelist dessen, was ein Request setzen darf. Das Übergeben des rohen Hashs erlaubt es einem Client, jede Spalte zu setzen, einschließlich Admin-Flags.

Bevorzugt
def post_params
  params.require(:post).permit(:title, :body, tag_ids: [])
end
Vermeiden
Post.new(params[:post])
# mass assignment: role and admin are fair game

Abwägungen

Ist Rails der richtige Standard?

Rails tauscht etwas Freiheit gegen Geschwindigkeit bei der Auslieferung ein. Das ist ein großartiger Deal, bis Ihre App die Konventionen überwächst.

Strengths

  • Sie liefern Features, kein Plumbing

    Routing, Migrationen, Validierung, Mailer, Jobs und Caching sind alle enthalten und bereits miteinander verknüpft, sodass ein kleines Team ein großes Produkt bauen kann.

  • Die Konventionen sind eine gemeinsame Sprache

    Jeder Rails-Entwickler kann jede Rails-App öffnen und sofort wissen, wo sich die Dinge befinden. Das macht Recruiting und Onboarding dramatisch einfacher.

  • Das Gem-Ökosystem ist tief

    Devise, Pundit, Sidekiq, RSpec und unzählige andere lösen die Probleme, mit denen jede Anwendung irgendwann konfrontiert wird.

Trade-offs

  • Die Magie verbirgt das Framework

    Konventionen fühlen sich mühelos an, bis etwas nicht konventionell ist. Debugging erfordert das Verständnis des zugrunde liegenden Rails-Quellcodes, nicht nur Ihres eigenen Codes.

  • Performance benötigt Aufmerksamkeit

    Eine naive Rails-App ist nicht langsam, aber N+1-Abfragen, fehlende Indizes und schwere Views summieren sich. Profiling ist eine notwendige Fähigkeit, keine optionale.

  • Der Full-Stack ist meinungsstark

    Rails setzt HTML, eine relationale Datenbank und eine eigene Asset-Strategie voraus. Wenn Ihre Architektur davon abweicht, kämpfen Sie mehr gegen die Defaults, als Sie sie nutzen.

Häufig gestellte Fragen

Häufig gestellte Fragen

Keep learning

Related topics from the roadmap.

$ Lernen Sie jetzt

Bereit, Rails zu lernen?

Unser interaktives Tutorial führt Sie Schritt für Schritt durch Rails — mit Quizzen und echtem Code, den Sie im Browser ausführen können.