<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ruby on Rails &#8211; webmatze.de</title>
	<atom:link href="https://webmatze.de/category/webseiten-erstellen/ruby_on_rails/feed/" rel="self" type="application/rss+xml" />
	<link>https://webmatze.de</link>
	<description>Profi Tipps für einen erfolgreichen Internetauftritt</description>
	<lastBuildDate>Wed, 11 Feb 2026 19:18:31 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>
	<item>
		<title>AI Coding-Agents sicher ausführen mit sandbox-shell (sx)</title>
		<link>https://webmatze.de/ai-coding-agents-sicher-ausfuehren-mit-sandbox-shell-sx/</link>
					<comments>https://webmatze.de/ai-coding-agents-sicher-ausfuehren-mit-sandbox-shell-sx/#respond</comments>
		
		<dc:creator><![CDATA[Mathias Karstädt]]></dc:creator>
		<pubDate>Wed, 11 Feb 2026 19:18:31 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Allgemeines]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[claude]]></category>
		<category><![CDATA[codex]]></category>
		<category><![CDATA[sandbox]]></category>
		<guid isPermaLink="false">https://webmatze.de/?p=1142</guid>

					<description><![CDATA[Tools wie Claude Code oder Codex sind unglaublich produktiv. Sie schreiben Code, führen Tests aus, installieren Dependencies und arbeiten eigenständig an Features. Aber: Dafür brauchen sie Zugriff auf dein Terminal. Und genau da wird es spannend. Denn ein AI-Agent mit Shell-Zugriff kann im Prinzip alles, was du auch kannst. Deine SSH-Keys lesen, AWS-Credentials zugreifen, Dateien [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Tools wie Claude Code oder Codex sind unglaublich produktiv. Sie schreiben Code, führen Tests aus, installieren Dependencies und arbeiten eigenständig an Features. Aber: Dafür brauchen sie Zugriff auf dein Terminal. Und genau da wird es spannend.</p>
<p>Denn ein AI-Agent mit Shell-Zugriff kann im Prinzip alles, was du auch kannst. Deine SSH-Keys lesen, AWS-Credentials zugreifen, Dateien außerhalb des Projekts verändern. Nicht weil die Tools bösartig sind, sondern weil ein <code>npm install</code> mit einem manipulierten Paket oder ein falsch interpretierter Prompt reichen kann.</p>
<p>Die Frage ist also: Wie gibst du einem AI-Agent genug Rechte zum Arbeiten, ohne ihm gleich die Schlüssel zu deinem ganzen System zu geben?</p>
<h2>sandbox-shell (sx): macOS Seatbelt für Entwickler</h2>
<p>macOS hat mit Seatbelt ein mächtiges Sandboxing-System eingebaut. Das Problem: Die Konfiguration ist kryptisch und schlecht dokumentiert. Genau hier setzt <code>sx</code> an. Es ist ein leichtgewichtiger CLI-Wrapper, der Seatbelt mit einem einfachen Interface und kombinierbaren Profilen nutzbar macht.</p>
<p>Das Prinzip ist Deny-by-Default:</p>
<ul>
<li>Dateisystem: Nur das Projektverzeichnis + <code>/tmp</code> sind beschreibbar</li>
<li>Netzwerk: Standardmäßig komplett blockiert</li>
<li>Sensible Pfade: <code>~/.ssh</code>, <code>~/.aws</code>, <code>~/Documents</code> usw. sind gesperrt</li>
</ul>
<h3>Installation</h3>
<pre><code class="language-bash">brew tap agentic-dev3o/sx
brew install sx</code></pre>
<p>Optional: Shell-Integration für Prompt-Indikatoren und Aliases:</p>
<pre><code class="language-bash"># In ~/.zshrc einfügen
source $(brew --prefix)/share/sx/sx.zsh</code></pre>
<p>Damit bekommt ihr im Terminal einen Indikator, ob ihr gerade in einer Sandbox arbeitet (<code>[sx:offline]</code>, <code>[sx:localhost]</code>, <code>[sx:online]</code>), und praktische Aliases wie <code>sxo</code> (online) und <code>sxl</code> (localhost).</p>
<h2>Globale Konfiguration</h2>
<p>In <code>~/.config/sx/config.toml</code> definiert ihr, welche Pfade eure Tools generell lesen und schreiben dürfen. Das hängt davon ab, welchen Ruby-Version-Manager ihr nutzt. Hier ein Beispiel für <code>mise</code>:</p>
<pre><code class="language-toml">[filesystem]
allow_read = [
    &quot;~/.gitconfig&quot;,
    &quot;~/.config/git/&quot;,
    &quot;~/.bundle/&quot;,
    &quot;~/.gem/&quot;,
    &quot;~/.local/share/mise/&quot;,
    &quot;~/.config/mise/&quot;,
]

allow_write = [
    &quot;~/.bundle/&quot;,
    &quot;~/.gem/&quot;,
    &quot;~/.cache/&quot;,
]</code></pre>
<p>Nutzt ihr <code>rbenv</code>, ersetzt die <code>mise</code>-Pfade durch <code>~/.rbenv/</code>. Bei <code>asdf</code> entsprechend <code>~/.asdf/</code>.</p>
<h2>Projekt-Konfiguration</h2>
<p>Im Projektverzeichnis könnt ihr mit <code>sx --init</code> eine <code>.sandbox.toml</code> anlegen:</p>
<pre><code class="language-bash">cd mein-projekt
sx --init</code></pre>
<p>Für ein typisches Rails-Projekt mit MySQL, Redis und Memcache in Docker sieht die Konfiguration so aus:</p>
<pre><code class="language-toml">[sandbox]
inherit_global = true

# Localhost für Datenbankzugriff über Docker
network = &quot;localhost&quot;

[shell]
pass_env = [&quot;RUBY_DEBUG_ENABLE&quot;]</code></pre>
<p>Die <code>pass_env</code>-Einstellung ist wichtig: Der Ruby-Debugger (<code>rdbg</code>) versucht beim Start automatisch einen Unix-Socket zu öffnen, was Seatbelt im Localhost-Modus blockiert. Mit <code>RUBY_DEBUG_ENABLE=0</code> als Environment-Variable umgeht ihr das Problem.</p>
<h2>Was blockiert die Sandbox konkret?</h2>
<p>Ein <code>sx --explain</code> zeigt euch genau, was erlaubt und was gesperrt ist:</p>
<pre><code class="language-bash">=== Sandbox Configuration ===

Network Mode: Localhost

Working Directory (full access):
  /Users/mathias/Workspace/mein-projekt

Denied Read Paths:
  - ~/.ssh
  - ~/.aws
  - ~/.docker/config.json
  - ~/Documents
  - ~/Desktop
  - ~/Downloads</code></pre>
<p>Und das könnt ihr leicht verifizieren:</p>
<pre><code class="language-bash"># Funktioniert – Projektdateien sind lesbar
sx -- cat README.md

# Blockiert – SSH-Keys sind geschützt
sx -- cat ~/.ssh/id_rsa
# =&gt; No such file or directory

# Blockiert – kein Schreibzugriff außerhalb des Projekts
sx -- touch ~/Desktop/test
# =&gt; Operation not permitted</code></pre>
<p>Seatbelt macht die gesperrten Dateien quasi unsichtbar. Ein Prozess in der Sandbox weiß nicht einmal, dass <code>~/.ssh/id_rsa</code> existiert.</p>
<h2>Netzwerk-Modi</h2>
<p><code>sx</code> bietet drei Netzwerk-Modi, die ihr je nach Aufgabe kombiniert:</p>
<table>
<thead>
<tr>
<th>Modus</th>
<th>Befehl</th>
<th>Erlaubt</th>
</tr>
</thead>
<tbody>
<tr>
<td>Offline</td>
<td><code>sx --</code></td>
<td>Kein Netzwerk</td>
</tr>
<tr>
<td>Localhost</td>
<td><code>sx localhost --</code></td>
<td>Nur 127.0.0.1 (Docker-Services)</td>
</tr>
<tr>
<td>Online</td>
<td><code>sx online --</code></td>
<td>Voller Netzwerkzugriff</td>
</tr>
</tbody>
</table>
<p>In der Praxis heißt das:</p>
<pre><code class="language-bash"># Linting braucht kein Netzwerk
sx -- bundle exec rubocop

# Tests brauchen die lokale Datenbank
RUBY_DEBUG_ENABLE=0 sx localhost -- bundle exec rspec

# Gems installieren braucht Internet
sx online -- bundle install</code></pre>
<h2>Einsatz mit AI Coding-Agents</h2>
<p>Jetzt zum eigentlichen Punkt: Warum das Ganze besonders relevant für AI-Tools ist.</p>
<h3>Claude Code</h3>
<p>Claude Code hat einen eingebauten <code>--dangerously-skip-permissions</code>-Modus, der alle Bestätigungsdialoge überspringt. Praktisch, aber riskant. Mit <code>sx</code> könnt ihr diesen Modus nutzen und trotzdem sicher bleiben:</p>
<pre><code class="language-bash">sx claude -- claude --dangerously-skip-permissions</code></pre>
<p>Das <code>claude</code>-Profil gibt Claude Zugriff auf <code>~/.claude</code>, während alles andere gesperrt bleibt. Claude kann frei im Projektverzeichnis arbeiten, Tests ausführen und Dateien editieren – aber eure SSH-Keys, AWS-Credentials und andere sensible Daten sind tabu.</p>
<h3>OpenAI Codex</h3>
<p>Für Codex gilt das gleiche Prinzip:</p>
<pre><code class="language-bash">sx localhost -- codex</code></pre>
<h3>Warum nicht einfach Docker?</h3>
<p>Docker ist natürlich auch eine Option, aber <code>sx</code> hat ein paar Vorteile für den täglichen Einsatz:</p>
<ul>
<li><strong>Kein Overhead</strong>: Kein Container-Build, kein Volume-Mounting, keine Port-Forwards</li>
<li><strong>Native Performance</strong>: Läuft direkt auf dem Host, keine Virtualisierung</li>
<li><strong>Einfache Integration</strong>: Ein Prefix vor dem Befehl, fertig</li>
<li><strong>Zugriff auf lokale Tools</strong>: Eure installierte Ruby-Version, eure Shell-Config – alles da</li>
</ul>
<h2>Mein Alltags-Setup</h2>
<p>So sieht mein typischer Workflow aus:</p>
<table>
<thead>
<tr>
<th>Aufgabe</th>
<th>Befehl</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tests ausführen</td>
<td><code>RUBY_DEBUG_ENABLE=0 sx localhost -- bundle exec rspec</code></td>
</tr>
<tr>
<td>Einzelnen Test</td>
<td><code>RUBY_DEBUG_ENABLE=0 sx localhost -- bundle exec rspec spec/models/user_spec.rb</code></td>
</tr>
<tr>
<td>Linting</td>
<td><code>sx -- bundle exec rubocop</code></td>
</tr>
<tr>
<td>Gems installieren</td>
<td><code>sx online -- bundle install</code></td>
</tr>
<tr>
<td>Rails Server</td>
<td><code>RUBY_DEBUG_ENABLE=0 sx localhost -- bin/rails server</code></td>
</tr>
<tr>
<td>Rails Console</td>
<td><code>RUBY_DEBUG_ENABLE=0 sx localhost -- bin/rails console</code></td>
</tr>
<tr>
<td>AI-Agent starten</td>
<td><code>sx claude -- claude</code></td>
</tr>
<tr>
<td>Git Push</td>
<td>Außerhalb der Sandbox (SSH-Keys blockiert)</td>
</tr>
</tbody>
</table>
<h2>Fazit</h2>
<p>AI Coding-Agents sind gekommen, um zu bleiben. Die Produktivitätsgewinne sind real. Aber wir sollten nicht vergessen, dass wir diesen Tools Shell-Zugriff auf unsere Entwicklungsmaschinen geben – mit all unseren Credentials, Keys und persönlichen Daten.</p>
<p><code>sx</code> löst das elegant: Ein Befehlsprefix, ein paar Zeilen Config, und eure AI-Agents arbeiten in einer Sandbox, die sie alles tun lässt, was sie für die Entwicklung brauchen – und nichts darüber hinaus.</p>
<p>Viel Spaß beim Ausprobieren!</p>
<p><strong>Links:</strong></p>
<ul>
<li><a href="https://github.com/agentic-dev3o/sandbox-shell">sandbox-shell auf GitHub</a></li>
<li><a href="https://claude.ai/claude-code">Claude Code</a></li>
<li><a href="https://developer.apple.com/documentation/security">macOS Seatbelt Dokumentation</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://webmatze.de/ai-coding-agents-sicher-ausfuehren-mit-sandbox-shell-sx/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Recordables in Rails: Delegated Types praxisnah erklärt</title>
		<link>https://webmatze.de/recordables-in-rails-delegated-types-praxisnah-erklaert/</link>
					<comments>https://webmatze.de/recordables-in-rails-delegated-types-praxisnah-erklaert/#respond</comments>
		
		<dc:creator><![CDATA[Mathias Karstädt]]></dc:creator>
		<pubDate>Fri, 19 Dec 2025 19:15:37 +0000</pubDate>
				<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[Recordable Pattern]]></category>
		<category><![CDATA[ruby]]></category>
		<guid isPermaLink="false">https://webmatze.de/?p=1122</guid>

					<description><![CDATA[In diesem Beitrag zeige ich dir das Recordable Pattern, das 37signals (Basecamp, HEY) einsetzt, und erkläre es Schritt für Schritt anhand von lauffähigen Rails-Code-Beispielen. Zielgruppe sind Anfänger bis Fortgeschrittene Ruby on Rails Entwickler, die polymorphe Datenmodelle sauber, skalierbar und gut paginierbar bauen möchten. Warum das Ganze? Klassische Ansätze wie Single Table Inheritance (STI) oder „nackte“ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>In diesem Beitrag zeige ich dir das Recordable Pattern, das 37signals (Basecamp, HEY) einsetzt, und erkläre es Schritt für Schritt anhand von lauffähigen Rails-Code-Beispielen. Zielgruppe sind Anfänger bis Fortgeschrittene Ruby on Rails Entwickler, die polymorphe Datenmodelle sauber, skalierbar und gut paginierbar bauen möchten.</p>
<p><iframe title="The Rails Delegated Type Pattern with Jeffrey Hardy" width="500" height="281" src="https://www.youtube.com/embed/m90sl-Uvu0Y?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<p>Warum das Ganze? Klassische Ansätze wie Single Table Inheritance (STI) oder „nackte“ polymorphe Assoziationen stoßen schnell an Grenzen: STI bläht Tabellen auf, polymorphes CRUD bleibt oft mühsam zu paginieren. Das Recordable Pattern nutzt Rails’ <a href="http://https://api.rubyonrails.org/classes/ActiveRecord/DelegatedType.html" title="Delegated Types">Delegated Types</a>, um eine dünne, performante „Superklasse“-Tabelle (Recording) mit schlanken „Subklasse“-Tabellen (Recordables wie Message, Document, Comment) zu kombinieren.</p>
<hr />
<h2>Das Grundprinzip</h2>
<ul>
<li>Eine zentrale Tabelle <strong>„recordings“</strong> hält alle gemeinsamen Metadaten (z. B. Bucket, Creator, Timestamps) und verweist polymorph auf den „konkreten Inhalt“ (recordable).</li>
<li>Jede konkrete Recordable (Message, Document, Comment) hat eine eigene Tabelle mit genau ihren Feldern.</li>
<li>Abfragen, Pagination und gemeinsame Logik passieren über Recording; konkretes Verhalten (z. B. <code>export_html</code>) lebt bei den Recordables.</li>
</ul>
<p>So bleibst du:</p>
<ul>
<li>flexibel (neue Typen ohne Recording-Migration),</li>
<li>performant (einheitliche Timeline auf der dünnen Recording-Tabelle),</li>
<li>sauber getrennt (Metadaten vs. Inhalte).</li>
</ul>
<hr />
<h2>Minimales Datenmodell</h2>
<p>Migration (gekürzt auf das Wesentliche):</p>
<pre><code class="language-ruby">create_table :recordings do |t|
  t.references :bucket,  null: false, foreign_key: true
  t.references :creator, null: false, foreign_key: { to_table: :users }
  t.string  :recordable_type, null: false
  t.bigint  :recordable_id,   null: false
  t.index [:recordable_type, :recordable_id]
  t.bigint :parent_id # optional: Recording-Baum (Unterelemente)
  t.index :parent_id
  t.timestamps
end
add_foreign_key :recordings, :recordings, column: :parent_id

create_table :messages do |t|
  t.string :title,   null: false
  t.text   :content, null: false
  t.timestamps
end

create_table :documents do |t|
  t.string :title, null: false
  t.text   :body
  t.string :external_url
  t.timestamps
end

create_table :comments do |t|
  t.text :body, null: false
  t.timestamps
end</code></pre>
<hr />
<h2>Models und Concerns</h2>
<p>Recording: die „Superklasse“ mit Delegation</p>
<pre><code class="language-ruby">class Recording &lt; ApplicationRecord
  belongs_to :bucket
  belongs_to :creator, class_name: &quot;User&quot;

  delegated_type :recordable, types: %w[Message Document Comment], dependent: :destroy

  # optional: Baumstruktur
  belongs_to :parent, class_name: &quot;Recording&quot;, optional: true
  has_many   :children, class_name: &quot;Recording&quot;, foreign_key: :parent_id, dependent: :nullify

  # Bequeme Filter-Scopes kommen mit delegated_type:
  # Recording.messages, Recording.documents, Recording.comments
end</code></pre>
<p>Recordable-Concern: gemeinsame API für Inhalte</p>
<pre><code class="language-ruby">module Recordable
  extend ActiveSupport::Concern

  included do
    has_many :recordings, as: :recordable, inverse_of: :recordable
  end

  def display_title
    respond_to?(:title) ? title : self.class.name
  end

  def export_html
    &quot;#{display_title}&quot;
  end
end</code></pre>
<p>Konkrete Typen:</p>
<pre><code class="language-ruby">class Message &lt; ApplicationRecord
  include Recordable
  validates :title, :content, presence: true

  def export_html
    &quot;#{title}#{content}&quot;
  end
end

class Document &lt; ApplicationRecord
  include Recordable
  validates :title, presence: true

  def export_html
    if external_url.present?
      &quot;#{title}External: #{external_url}&quot;
    else
      &quot;#{title}#{body}&quot;
    end
  end
end

class Comment &lt; ApplicationRecord
  include Recordable
  validates :body, presence: true

  def display_title
    body.truncate(40)
  end

  def export_html
    &quot;#{body}&quot;
  end
end</code></pre>
<hr />
<h2>Erstellen und Paginieren einer Timeline</h2>
<p>Bucket kapselt die Aufnahme neuer Inhalte („record“) und die Timeline. Bucket ist hier eher abstrakt und könnte genausogut auch ein Projekt sein, oder ein Kunde:</p>
<pre><code class="language-ruby">class Bucket &lt; ApplicationRecord
  has_many :recordings, dependent: :destroy

  def timeline(limit: 50)
    recordings.order(created_at: :desc).limit(limit).includes(:recordable)
  end

  def record(recordable, creator:, parent: nil, color: nil)
    recordings.create!(recordable: recordable, creator: creator, parent: parent, color: color)
  end
end</code></pre>
<p>Typische Abfragen:</p>
<pre><code class="language-ruby">bucket = Bucket.find(1)

# Gesamte Timeline effizient paginieren
bucket.timeline(limit: 50).each do |rec|
  puts &quot;[#{rec.recordable_type}] #{rec.recordable.display_title}&quot;
end

# Nur bestimmte Typen (Scopes via delegated_type)
Recording.messages.where(bucket: bucket).limit(20)
Recording.documents.where(bucket: bucket).order(created_at: :desc)</code></pre>
<hr />
<h2>Versionierung per Repointing (immutable Recordables)</h2>
<p>Statt Inhalte zu „updaten“, erzeugst du neue Recordables und verweist die Recording-Zeile auf die neue Version. Das hält Historie sauber und macht Kopieren effizient.</p>
<pre><code class="language-ruby">class Recording &lt; ApplicationRecord
  # ...

  def repoint_to!(new_recordable)
    update!(recordable: new_recordable)
  end
end

# Beispiel: Message ? neue Document-Version
msg_rec = bucket.record(Message.create!(title: &quot;Kickoff&quot;, content: &quot;Welcome!&quot;), creator: user)
new_doc = Document.create!(title: &quot;Specs v2&quot;, body: &quot;Updated requirements&quot;)
msg_rec.repoint_to!(new_doc) # Recording zeigt nun auf Document</code></pre>
<p>Wenn du eine echte Ereignis-Historie brauchst, ergänze ein <code>Event</code>-Model und schreibe beim <code>record</code>/<code>repoint_to!</code> Einträge (z. B. „created“, „repointed“, inkl. vorher/nachher <code>recordable_type/_id</code>). Das hält Audit-Trails und erlaubt Timeline-Features (siehe Video/37signals-Artikel).</p>
<hr />
<h2>Copy &amp; Move: Subtrees kopieren</h2>
<p>Ein Vorteil des Patterns: Kopieren und Verschieben ganzer Teilbäume wird planbar und schnell, weil Recordings leichtgewichtig sind und Recordables immutable dupliziert werden. Eine einfache Kopier-Serviceklasse:</p>
<pre><code class="language-ruby">class Copier
  def self.copy!(source_recording:, destination_bucket:, creator:)
    new(source_recording, destination_bucket, creator).copy!
  end

  def initialize(source_recording, destination_bucket, creator)
    @source_recording   = source_recording
    @destination_bucket = destination_bucket
    @creator            = creator
  end

  def copy!
    ActiveRecord::Base.transaction do
      copied_root = copy_recording(@source_recording, parent: nil)
      @source_recording.children.each { |child| copy_branch(child, parent: copied_root) }
      copied_root
    end
  end

  private

  def copy_branch(node, parent:)
    copied = copy_recording(node, parent: parent)
    node.children.each { |child| copy_branch(child, parent: copied) }
    copied
  end

  def copy_recording(original, parent:)
    new_recordable = duplicate_recordable(original.recordable)
    @destination_bucket.record(new_recordable, creator: @creator, parent: parent, color: original.color)
  end

  def duplicate_recordable(recordable)
    case recordable
    when Message
      Message.create!(title: recordable.title, content: recordable.content)
    when Document
      Document.create!(title: recordable.title, body: recordable.body, external_url: recordable.external_url)
    when Comment
      Comment.create!(body: recordable.body)
    else
      raise ArgumentError, &quot;Unsupported recordable: #{recordable.class.name}&quot;
    end
  end
end</code></pre>
<hr />
<h2>Vergleich mit STI und „plain“ Polymorphismus</h2>
<ul>
<li><strong>STI</strong>: Einfache Fälle ok. Bei divergenten Typen entsteht Tabellen-Bloat, viele NULL-Spalten, Migrationen werden groß, Erweiterbarkeit leidet.</li>
<li><strong>Polymorphismus ohne <code>delegated_type</code></strong>: Funktioniert, aber es fehlen bequeme Scopes/Convenience-Methoden; unified Pagination ist oft hakelig.</li>
<li><strong>Recordables + <code>delegated_type</code></strong>: Einheitliche Timeline über eine dünne Tabelle, klare Trennung von Meta vs. Inhalt, leichte Erweiterbarkeit (neuen Typ hinzufügen statt zentrale Tabelle migrieren), gute Performance bei Abfragen.</li>
</ul>
<hr />
<h2>Wann solltest du das Pattern nutzen?</h2>
<ul>
<li>Du brauchst eine gemischte, paginierbare Timeline (z. B. Aktivitätsfeed über Messages, Documents, Comments).</li>
<li>Deine Typen unterscheiden sich stark in ihren Attributen.</li>
<li>Du willst Polymorphismus am Parent (Recording) und saubere Delegation an die Inhalte.</li>
</ul>
<p>Wann eher nicht?</p>
<ul>
<li>Deine Subtypen sind fast identisch (STI könnte reichen).</li>
<li>Du hast keine gemeinsamen Abfragen über Typgrenzen hinweg.</li>
</ul>
<hr />
<h2>Best Practices</h2>
<ul>
<li>Halte Recording schlank: nur Metadaten und die polymorphe Referenz. Keine großen Textfelder.</li>
<li>Packe typenübergreifende Logik in Recording (oder Concerns), typenspezifische Logik in die Recordables.</li>
<li>Nutze <code>delegate</code> am Recording für gemeinsame Schnittstellen, z. B. <code>delegate :export_html, to: :recordable</code>.</li>
<li>Wenn Auditing/History wichtig ist, ergänze Events und schreibe Änderungen mit.</li>
<li>Autorisierung: Recording bündelt viele Aktionen – prüfe Berechtigungen konsequent.</li>
</ul>
<hr />
<h2>Fazit</h2>
<p>Das Recordable Pattern mit <code>delegated_type</code> ist eine elegante, praxiserprobte Lösung für polymorphe Inhalte in Rails. Es bringt dir:</p>
<ul>
<li>eine einheitliche, performante Timeline,</li>
<li>klare Verantwortlichkeiten zwischen Metadaten und Inhaltsobjekten,</li>
<li>einfache Erweiterbarkeit ohne große Migrationen,</li>
<li>saubere APIs durch Delegation.</li>
</ul>
<p>Wenn du Feed-ähnliche Strukturen, Versionierung und Kopier-Features brauchst, wirst du mit Recordings/Recordables sehr schnell produktiv.</p>
<p>Viel Spaß beim Ausprobieren – und schreib mir gern, wenn du Fragen hast oder Beispiele aus deinem Projekt teilen willst!</p>
<p>— Mathias (webmatze.de)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://webmatze.de/recordables-in-rails-delegated-types-praxisnah-erklaert/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Mein neues Zufalls-&#8222;Dad Joke&#8220; Ruby Gem: ICanHazDadJoke</title>
		<link>https://webmatze.de/mein-neues-zufalls-dad-joke-ruby-gem-icanhazdadjoke/</link>
					<comments>https://webmatze.de/mein-neues-zufalls-dad-joke-ruby-gem-icanhazdadjoke/#respond</comments>
		
		<dc:creator><![CDATA[Mathias Karstädt]]></dc:creator>
		<pubDate>Tue, 14 May 2024 23:07:04 +0000</pubDate>
				<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[dad jokes]]></category>
		<category><![CDATA[ruby gem]]></category>
		<guid isPermaLink="false">https://webmatze.de/?p=1040</guid>

					<description><![CDATA[Hallo zusammen! Ich freue mich, euch heute mein neuestes Ruby Gem vorzustellen: icanhazdadjoke. Wie der Name schon verrät, ermöglicht dieses Gem euch, auf einfache Weise zufällige "Dad Jokes" aus der icanhazdadjoke API abzurufen. Wer liebt nicht einen guten, alten, schlechten Witz? Was ist ein "Dad Joke"? "Dad Jokes" sind einfache, oft vorhersehbare und klischeehafte Witze, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Hallo zusammen!</p>



<p>Ich freue mich, euch heute mein neuestes Ruby Gem vorzustellen: <code>icanhazdadjoke</code>. Wie der Name schon verrät, ermöglicht dieses Gem euch, auf einfache Weise zufällige "Dad Jokes" aus der <a title="icanhazdadjoke API" href="https://icanhazdadjoke.com/api">icanhazdadjoke API</a> abzurufen. Wer liebt nicht einen guten, alten, schlechten Witz?</p>



<h2 class="wp-block-heading">Was ist ein "Dad Joke"?</h2>



<p>"Dad Jokes" sind einfache, oft vorhersehbare und klischeehafte Witze, die typischerweise von Vätern erzählt werden. Sie zeichnen sich durch ihre Wortspiele und ihren harmlosen Humor aus. Beispiele gefällig? Hier sind ein paar Klassiker:</p>



<ul class="wp-block-list">
<li>Warum können Geister so schlecht lügen? Weil man sie durchschauen kann!</li>



<li>Wie nennt man einen Bumerang, der nicht zurückkommt? Einen Stock!</li>
</ul>



<p>Ha! Ich weiß.</p>



<h2 class="wp-block-heading">Funktionen des Gems</h2>



<p>Mit <code>icanhazdadjoke</code> könnt ihr ganz einfach zufällige Witze abrufen und in euren Ruby-Anwendungen verwenden oder direkt im Terminal aufrufen. Das Gem ist leicht zu installieren und noch einfacher zu benutzen. Hier sind einige der Hauptfunktionen:</p>



<ul class="wp-block-list">
<li><strong>Zufällige Witze abrufen</strong>: Holt euch einen zufälligen Witz mit einer einzigen Zeile Code.</li>



<li><strong>Leicht erweiterbar</strong>: Das Gem ist so konzipiert, dass es leicht erweitert und in bestehende Projekte integriert werden kann.</li>
</ul>



<h2 class="wp-block-heading">Installation</h2>



<p>Die Installation des Gems ist einfach und dauert nur einen Moment. Führt einfach folgenden Befehl in eurem Terminal aus:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">gem install icanhazdadjoke</code></pre>



<h2 class="wp-block-heading">Nutzung</h2>



<p>Nachdem ihr das Gem installiert habt, könnt ihr es in eurem Projekt verwenden. Hier ist ein kurzes Beispiel, wie ihr einen zufälligen Witz abrufen könnt:</p>



<pre class="wp-block-code"><code lang="ruby" class="language-ruby">require 'icanhazdadjoke'

joke = ICanHazDadJoke.fetch_joke
puts joke</code></pre>



<p>So einfach ist das! Ihr könnt den abgerufenen Witz dann überall in eurem Code verwenden, wo ihr ihn braucht.</p>



<h2 class="wp-block-heading">Beispielprojekt</h2>



<p>Hier ist ein kleines Beispielprojekt, das zeigt, wie man das Gem in einer einfachen Ruby-Anwendung verwenden kann:</p>



<pre class="wp-block-code"><code lang="ruby" class="language-ruby">require 'sinatra'
require 'icanhazdadjoke'

get <span class="hljs-string">'/'</span> <span class="hljs-keyword">do</span>
  joke = <span class="hljs-title class_">ICanHazDadJoke</span>.fetch_joke
  <span class="hljs-string">"&lt;h1>Dad Joke&lt;/h1>&lt;p><span class="hljs-subst">#{joke}</span>&lt;/p>"</span>
<span class="hljs-keyword">end</span>
</code></pre>



<p>Dieses einfache Sinatra-Projekt erstellt einen kleinen Webserver, der bei jedem Aufruf der Startseite einen neuen Witz anzeigt.</p>



<h2 class="wp-block-heading">Fazit</h2>



<p>Ich hoffe, euch gefällt mein neues Gem <code>icanhazdadjoke</code>. Es war ein lustiges Projekt und ich freue mich darauf zu sehen, wie ihr es in euren eigenen Projekten verwendet. Wenn ihr Fragen oder Anregungen habt, lasst es mich gerne wissen. Den Code und weitere Informationen findet ihr auf <a href="https://github.com/webmatze/icanhazdadjoke">GitHub</a>.</p>



<p>Viel Spaß beim Programmieren und vergesst nicht, hin und wieder einen guten "Dad Joke" zu erzählen!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://webmatze.de/mein-neues-zufalls-dad-joke-ruby-gem-icanhazdadjoke/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Ruby on Rails auf Ubuntu 11.10 installieren</title>
		<link>https://webmatze.de/ruby-on-rails-auf-ubuntu-11-10-installieren/</link>
					<comments>https://webmatze.de/ruby-on-rails-auf-ubuntu-11-10-installieren/#comments</comments>
		
		<dc:creator><![CDATA[Mathias Karstädt]]></dc:creator>
		<pubDate>Sat, 15 Oct 2011 14:17:06 +0000</pubDate>
				<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[ubuntu]]></category>
		<guid isPermaLink="false">http://webmatze.de/?p=689</guid>

					<description><![CDATA[Seit einigen Tagen (Oktober 2011) ist die neuste Version von Ubuntu zum Download freigegeben. Ubuntu 11.10 oder auch Oneiric Ocelot genannt, ist ein wirklich ausgereiftes und leicht zu bedienendes Linux Betriebssystem, welches kostenlos zum Download bereit steht. Da Linux schon von Natur aus viele Funktionen und Helfer für Programmierer bereit hält, eignet es sich auch [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Seit einigen Tagen (Oktober 2011) ist die neuste Version von <a title="Ubuntu Linux" href="http://www.ubuntu.com/">Ubuntu</a> zum <a title="Download Ubuntu hier" href="http://www.ubuntu.com/download">Download</a> freigegeben. <strong>Ubuntu 11.10</strong> oder auch <strong>Oneiric Ocelot</strong> genannt, ist ein wirklich ausgereiftes und leicht zu bedienendes Linux Betriebssystem, welches kostenlos zum Download bereit steht. Da Linux schon von Natur aus viele Funktionen und Helfer für Programmierer bereit hält, eignet es sich auch hervorragend zur Entwicklung von <strong>Ruby on Rails</strong> Anwendungen.</p>
<p><a title="Ruby on Rails" href="http://rubyonrails.org/">Ruby on Rails</a> hingegen ist derzeit eines der populärsten und produktivsten OpenSource Frameworks, mit dem sich sehr schnell umfangreiche Webanwendungen erstellen lassen. Wer schon damit gearbeitet hat, weiß wieviel Spaß es machen kann.</p>
<p><a title="Ruby Homepage" href="http://www.ruby-lang.org">Ruby</a> selbst ist eine Scriptsprache, wie z.B. auch PHP eine Scriptsprache ist. Ruby wurde jedoch von Grund auf mit dem Ziel entwickelt, leicht verständlich zu sein und eine schnelle Entwicklung damit zu ermöglichen.</p>
<h3>Ubuntu für Rails vorbereiten</h3>
<p>Damit wir das Rails Framework unter <strong>Ubuntu 11.10</strong> verwenden können, müssen wir zuerst <strong>Ruby</strong> installieren. Von Haus aus ist Ubuntu noch nicht mit Ruby ausgestattet, jedoch läßt sich dieses (und auch andere Programmiersprachen) sehr leicht nachträglich installieren.</p>
<p>Hierzu muss man wissen, dass es verschiedene Versionen von Ruby gibt. Ältere Versionen von Ruby on Rails haben hauptsächlich auf die <strong>Ruby Version 1.8.7</strong> gesetzt. Die neusten <strong>Ruby on Rails Versionen ab 3.0</strong> verwenden jedoch bevorzugt <strong>Ruby Version 1.9.2</strong>. Um unser System also für die Zukunft vorzubereiten, werden wir auf den <a title="Ruby Version Manager Homepage" href="http://beginrescueend.com/">Ruby Versions Manager</a> (RVM) setzen, mit dem es möglich ist jede beliebige Ruby Version zu installieren und auch bequem zwischen diesen zu wechseln.</p>
<p><span id="more-689"></span>Damit wir <strong>RVM</strong> installieren können, müssen wir zuerst ein paar Abhängigkeiten installieren:</p>
<pre>sudo apt-get install git
sudo apt-get install curl</pre>
<p>Git benötigen wir, weil die meisten <strong>Ruby on Rails</strong> Projekte und Erweiterungen ihre Sourcen mit <a title="Git SCM Homepage" href="http://git-scm.com/">Git</a> verwalten. Und curl brauchen wir, um mit dem folgenden Befehl <strong>RVM</strong> zu installieren:</p>
<pre>bash &lt; &lt;(curl -s https://rvm.beginrescueend.com/install/rvm)</pre>
<p>Nachdem dies ausgeführt wurde, bekommen wir noch ein paar Hinweise vom <strong>RVM</strong> Entwickler, wie wir damit umgehen können. Unter anderem wird auch noch darauf hingewiesen, dass folgende Abhängigkeiten installiert werden sollten, bevor man damit beginnen kann, ein oder mehrere Ruby Versionen zu installieren:</p>
<pre>sudo apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion</pre>
<p>Nun sollte man das Terminal einmal schließen und wieder ein neues Terminal öffnen und mit folgenden Befehl überprüfen, ob <strong>RVM</strong> richtig installiert wurde:</p>
<pre>type rvm | head -1</pre>
<p>Wird hier jetzt '<strong>rvm is a function</strong>' zurückgegeben, ist alles in Ordnung und wir können damit beginnen, unsere benötigte Ruby Version zu installieren.</p>
<h3>Ruby 1.9.2 auf Ubuntu installieren</h3>
<p>Abhängig davon, welche Ruby on Rails Version wir nutzen wollen, können wir nun die entsprechende Ruby Version installieren. Dies ist mit dem <strong>RVM</strong> Befehlt mehr als einfach. Gehen wir davon aus, dass wir <strong>Ruby on Rails 3.1</strong> (also die aktuelle Version) installieren wollen, können wir so <strong>Ruby 1.9.2</strong> installieren:</p>
<pre>rvm install 1.9.2</pre>
<p>Nach ein paar Minuten ist dann Ruby installieret. Beachten sollte man hierbei jedoch unbedingt, dass alles was man mit <strong>RVM</strong> macht ohne den <strong>sudo</strong> Befehlt ausgefürt werden muss! Warum dies so ist und weitere wichtige Nutzungshinweise erhaltet ihr in der <a title="RVM Dokumentation" href="http://beginrescueend.com/rvm/basics/"><strong>RVM</strong> Dokumentation</a>.</p>
<p>Um nun die installierte Ruby Version nutzen zu können, muss man sie mit dem folgenden Befehl aktivieren:</p>
<pre>rvm use 1.9.2</pre>
<p>Jetzt kann man überprüfen, welche Ruby Version installiert ist:</p>
<pre>ruby -v</pre>
<h3>Ruby on Rails auf Ubuntu installieren</h3>
<p>Nachdem nun alle notwendigen Vorbereitungen abgeschlossen sind, können wir damit beginnen die aktuelle Rails Version zu installieren. Rails und andere benötigte Packete werden mit dem <a title="RubyGems Package Manager" href="http://en.wikipedia.org/wiki/RubyGems">RubyGems Package Manager</a> installiert. Dieser wurde zum Glück auch schon automatisch von <strong>RVM</strong> mit installiert. Wir brauchen also nur noch folgendes auszuführen:</p>
<pre>gem install rails</pre>
<p>und schon wurde <strong>Ruby on Rails</strong> erfolgreich installiert. Auch hier ist wieder zu beachten, dass alle <strong>RubyGems</strong> ohne den <strong>sudo</strong> Befehl installiert werden.</p>
<h3>JavaScript Runtime installieren</h3>
<p>In der aktuellen <strong>Rails Version 3.1.1</strong> gibt es noch eine weitere Abhängigkeit, welche man beachten muss. Rails benötigt hier nämlich eine im System installierte <strong>JavaScript Runtime</strong> um bestimmte Funktionen ausführen zu können. Am einfachsten und problemlosesten konnte ich dieses Problem bei mir beheben, indem ich <a title="Node.js Homepage" href="http://nodejs.org/">Node.js</a> installiert habe:</p>
<pre>sudo apt-get install nodejs</pre>
<h3>Ruby on Rails testen</h3>
<p>Jetzt wo alles installiert ist, können wir schnell noch ein Testprojekt mit Rails erstellen:</p>
<pre>rails new test_app
cd test_app
rails server</pre>
<p>und uns dies im Browser aufrufen:</p>
<pre>http://localhost:3000</pre>
<p>Fertig ist unsere <strong>Ruby on Rails installation auf Ubuntu</strong>.</p>
<p>Die hier genannten Installationsschritte mögen sich mit denen auf anderen Ubuntu Versionen oder anderen Linux System unterscheiden.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://webmatze.de/ruby-on-rails-auf-ubuntu-11-10-installieren/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>IE 6 für Mac OS X</title>
		<link>https://webmatze.de/ie-6-fur-mac-os-x/</link>
					<comments>https://webmatze.de/ie-6-fur-mac-os-x/#comments</comments>
		
		<dc:creator><![CDATA[Mathias Karstädt]]></dc:creator>
		<pubDate>Fri, 06 Feb 2009 20:41:48 +0000</pubDate>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<guid isPermaLink="false">http://webmatze.de/?p=382</guid>

					<description><![CDATA[Wenn man wie ich als Ruby on Rails Entwickler unter Mac OS X arbeitet, dann kommt man früher oder später an den Punkt, wo man die Seite an der man arbeitet auch auf dem Internet Explorer testen möchte. Leider hat sich Microsoft nicht dazu hinreißen lassen, seine neusten Browser auch für Mac OS X zu [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Wenn man wie ich als <strong>Ruby on Rails</strong> Entwickler unter <strong>Mac OS X</strong> arbeitet, dann kommt man früher oder später an den Punkt, wo man die Seite an der man arbeitet auch auf dem <strong>Internet Explorer</strong> testen möchte.</p>
<p>Leider hat sich Microsoft nicht dazu hinreißen lassen, seine neusten Browser auch für Mac OS X zu veröffentlichen, so dass man auf andere Wege und Mittel zurückgreifen muss.</p>
<h3>Dual Boot mit BootCamp oder Virtual Machine?</h3>
<p>Sicher, <strong>Apple</strong> bietet uns über <a href="http://www.apple.com/de/macosx/features/bootcamp.html">BootCamp</a> an, ein anderes Betriebsystem wie <strong>Windows XP</strong> auf einer zweiten Partition zu installieren. Hat man dies getan, kann man natürlich auch den Internet Explorer unter Windows verwenden.</p>
<p>Allerdings haben wir dadurch auch einige Nachteile, die natürlich nicht verschwiegen werden können. Zum einen müssen wir extra Festplattenplatz für die zweite Partition bereitstellen - Windows ist hier natürlich nicht besonders sparsam -, zum anderen können wir so immer nur ein Betriebssystem gleichzeitig laufen lassen. Was natürlich unpraktisch ist, wenn unsere Entwicklungsumgebung auf Mac OS X läuft.</p>
<p>Bleibt als weitere Möglichkeit noch, Windows in einer <a href="http://de.wikipedia.org/wiki/Virtuelle_Maschine">virtuellen Maschine</a> zu installieren. Mit <a href="http://www.parallels.com/de/">Parallels</a> oder <a href="http://www.vmware.com/products/fusion/">VMWare Fusion</a> gibt es hier sehr gute Programme, die es uns sehr leicht machen, ein oder mehrere Betriebssysteme zu installieren und gleichzeitig mit Mac OS X laufen zu lassen.</p>
<p>Doch auch diese Möglichkeit fällt ins Wasser, wenn wir gar keine eigene (offizielle) Installations CD von Windows besitzen und uns auch nicht extra eine zulegen wollen, nur um etwas im Internet Explorer zu testen. Doch was bleibt uns nun noch übrig?</p>
<h3>ies4osx - Der Internet Explorer für OS X</h3>
<p>Ich weiß, ich weiß. Warum bin habe ich nicht gleich am Anfang erwähnt, das es doch einen <strong>Internet Explorer für Mac OS X</strong> gibt? Aber ich liebe es, ein wenig Spannung aufzubauen - und seien wir doch mal ehrlich, die Ungeduldigen unter euch haben die vorhergehenden Abschnitte sowieso übersprungen. (Was? Das stimmt wirklich? Dann schnell zurück und noch einmal von vorne lesen!)</p>
<p><a href="http://mike.kronenberg.org/">Mike Kronenberg</a> schien sich mal die gleichen Fragen gestellt zu haben. Warum kann ich keine Windows Anwendungen unter OS X laufen lassen? Also hat er sich hingesetzt und das Linux <a href="http://www.winehq.org/">Wine</a> Projekt - mit dem viele <strong>Windows Anwendungen unter Linux</strong> laufen können - auf Mac OS X portiert und als <a href="http://www.kronenberg.org/darwine/">Darwine</a> zur Verfügung gestellt. Dann ist er anscheinend auf das <a href="http://www.tatanka.com.br/ies4linux">ies4linux</a> Projekt gestoßen, mit dem es möglich war den <strong>Internet Explorer 6</strong> mit Hilfe von Wine auf Linux zum Laufen zu bekommen. Dies hat er ebenfalls portiert und herausgekommen ist <a href="http://www.kronenberg.org/ies4osx/">ies4osx</a>! &lt;tröte&gt;TATAAA!&lt;/tröte&gt;</p>
<p>Die Installation von <strong>ies4osx</strong> ist wirklich sehr einfach. Zuerst die aktuellen Versionen von <strong>Darwine</strong> und <strong>ies4osx</strong> herunterladen, <strong>Darwine</strong> in den Applications Ordner von OS X verschieben, den Installer von <strong>ies4osx</strong> ausführen und fertig. Der Installer lädt sich die benötigten Dateien herunter und legt eine lauffähige Version vom "Internet Explorer 6" auf dem Desktop ab.</p>
<p>Es ist sogar möglich, <strong>Flash</strong>, <strong>Java</strong> und den <strong>Mediaplayer 6.4</strong> von Microsoft auf diesem IE 6 zu installieren.</p>
<h3>Mein Fazit</h3>
<p>Seit ich vom <strong>ies4osx</strong> Projekt erfahren habe, habe ich immer einen Internet Explorer bei mir auf meinem <strong>MacBook</strong> laufen und kann so jederzeit meine Seiten auch dort überprüfen. Sicherlich, der Internet Explorer für Mac OS X reagiert oft etwas träge und vor allem wenn Flash im Spiel ist, wird es richtig langsam, aber für den Zweck, meine Seiten im IE 6 zu testen, ist dies vollkommen ausreichend.</p>
<p>Leider gibt es momentan noch keine Version vom <strong>IE 7</strong> oder <strong>IE 8</strong> für Mac OS X, aber schauen wir mal, was die Zukunft so bringt.</p>
<p><em>Wie läuft es bei euch? Entwickelt ihr auch unter Mac OS X? Wenn ja, welche Lösungen habt ihr gefunden, um eure Seiten auch auf dem Internet Explorer zu testen?</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://webmatze.de/ie-6-fur-mac-os-x/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Google Sitemaps mit Ruby on Rails erstellen</title>
		<link>https://webmatze.de/google-sitemaps-mit-ruby-on-rails-erstellen/</link>
					<comments>https://webmatze.de/google-sitemaps-mit-ruby-on-rails-erstellen/#comments</comments>
		
		<dc:creator><![CDATA[Mathias Karstädt]]></dc:creator>
		<pubDate>Mon, 24 Nov 2008 10:09:26 +0000</pubDate>
				<category><![CDATA[google]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Web 2.0]]></category>
		<category><![CDATA[Webseiten erstellen]]></category>
		<guid isPermaLink="false">http://webmatze.de/?p=380</guid>

					<description><![CDATA[Wer sich bereits eingehender mit Ruby on Rails beschäftigt hat, der weiß dass dieses beliebte Framework einem viele Aufgaben von Haus aus abnimmt und diese vereinfacht. In den Tagen des Social Webs gehört es unter anderem zu den häufigen Aufgaben eines Entwicklers, XML Dokumente zu generieren, oder APIs auf Basis von XML bereitzustellen. News wollen [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Wer sich bereits eingehender mit <a href="http://webmatze.de/rubyonrails-framework-auf-schienen/">Ruby on Rails</a> beschäftigt hat, der weiß dass dieses beliebte Framework einem viele Aufgaben von Haus aus abnimmt und diese vereinfacht.</p>
<p>In den Tagen des Social Webs gehört es unter anderem zu den häufigen Aufgaben eines Entwicklers, <abbr>XML</abbr> Dokumente zu generieren, oder <abbr title="Application Programing Interface">API</abbr>s auf Basis von <abbr>XML</abbr> bereitzustellen. News wollen in Form von <abbr title="Really Simple Syndication">RSS</abbr> oder <abbr title="Atom Syndication Format">Atom</abbr> abonniert werden, Inhalte aus anderen Webangeboten über <abbr>XML</abbr> in die eigenen Seiten integriert werden.</p>
<p><abbr>XML</abbr> ist also ziemlich wichtig und daher sollte das Erstellen und die Verarbeitung von <abbr>XML</abbr> mit einem Framework wie <a href="http://www.rubyonrails.org/">Ruby on Rails</a> auch so einfach und unkompliziert wie möglich erfolgen.</p>
<h3>Was ist Google Sitemaps?</h3>
<p>Wie dies funktioniert und welche Schritte dafür notwendig sind, werde ich am Beispiel einer Google Sitemap für ein Blog zeigen. Google stellt mit <a href="https://www.google.de/webmasters/sitemaps">Google Sitemaps</a> eine Methode zur Verfügung, um neue Inhalte aus dynamischen Webseiten noch schneller in den Google Suchindex aufnehmen zu lassen. Dazu können Webseiten eine <strong>sitemap.xml</strong> Datei zur Verfügung stellen, welche in Form von <abbr>XML</abbr> Daten wie URL, Erstell- bzw. Updatedatum und eine Indizierungspriorität zu allen verfügbaren Seiten - in unserem Fall sind dies die Blogeinträge - enthalten kann.</p>
<h3>Rails Generator hilft uns</h3>
<p>Bei großen dynamischen Seiten ist es natürlich aufwendig, diese <abbr>XML</abbr> Datei immer von Hand zu pflegen, darum wollen wir diese mit den Mitteln von Ruby on Rails automatisch generieren lassen.<br />
Überlegen wir doch erstmal, was wir alles für die geforderte Aufgabe benötigen. Wir brauchen einen Sitemap Controller mit einer <strong>index</strong> Action, welche wir aufrufen können und die dann schließlich das <abbr>XML</abbr> generiert. Also sollten wir zuerst diesen neuen Controller generieren lassen. Dies ist in Ruby on Rails mehr als einfach:</p>
<pre>ruby script/generate controller Sitemap index</pre>
<p>Dieser Komandozeilenaufruf nimmt uns diese Aufgabe ab. Der Rails Generator legt daraufhin mehrere Dateien an. Unter anderem den Controller <strong>sitemap_controller.rb</strong> mit der Action <strong>index</strong> und den View <strong>index.html.erb</strong>.</p>
<pre>     exists  app/controllers/
exists  app/helpers/
create  app/views/sitemap
exists  test/functional/
create  app/controllers/sitemap_controller.rb
create  test/functional/sitemap_controller_test.rb
create  app/helpers/sitemap_helper.rb
create  app/views/sitemap/index.html.erb</pre>
<p><span id="more-380"></span></p>
<h3>Der Controller</h3>
<p>Im nächsten Schritt holen wir uns in der bereits für uns angelegten <strong>index</strong> Action eine Liste mit allen vorhandenen Blogeinträgen und sagen Rails, dass das Ergebnis als XML gerendert werden soll.</p>
<pre lang="rails">class SitemapController &lt; ApplicationController

def index
@articles = BlogArticle.find(:all, :order =&gt; 'created_on DESC, updated_on DESC')
respond_to do |format|
format.xml { }
end
end

end</pre>
<p>Wie man sehen kann, sortieren wir die gefundenen Blogeinträge absteigend nach Erstellungs- und Bearbeitungsdatum. So ist sichergestellt, dass die aktuellsten Einträge in der <abbr>XML</abbr> Datei später immer am Anfang stehen.</p>
<h3>Mit Rails XMLBuilder ist XML so einfach wie noch nie</h3>
<p>Wie im ersten Schritt zu sehen, hat Rails für uns mit der <strong>index.hmtl.erb</strong> auch schon die Viewdatei für die <strong>index</strong> Action erstellt. Da wir jedoch kein <abbr title="Hypertext Markup Language">HTML</abbr> sondern <abbr>XML</abbr> ausgeben wollen, benennen wir diese Datei in <strong>index.xml.builder</strong> um.</p>
<p>Diese Umbenennung hat zwei Effekte. Rails wird auf diese Datei automatisch zurückgreifen, wenn <abbr>XML</abbr> gerendert werden soll und die Endung <strong>.builder</strong> teilt Rails mit, dass der Inhalt dieser Datei Anweisungen für den Rails eigenen <abbr>XML</abbr> Builder enthält. Mit diesem Builder lassen sich schnell komplexe <abbr>XML</abbr> Dateien erstellen, wie wir am folgenden Beispiel sehen werden.</p>
<pre lang="rails">xml.instruct!

xml.urlset "xmlns" =&gt; "http://www.google.com/schemas/sitemap/0.84" do
xml.url do
xml.loc         "http://www.name-der-seite.de/"
xml.lastmod     w3c_date(Time.now)
xml.changefreq  "always"
end

@articles.each do |article|
xml.url do
xml.loc         url_for(:only_path =&gt; false, :controller =&gt; 'blog', :action =&gt; 'show', :id =&gt; article)
xml.lastmod     w3c_date(article.created_on)
xml.changefreq  "weekly"
xml.priority    0.8
end
end

end</pre>
<p>Dieser Code ist so ziemlich selbsterklärend. Es wird über verschiedene <strong>xml</strong> Anweisungen die Struktur der <strong>sitemap.xml</strong> erzeugt und über alle BlogArticles iteriert.</p>
<h3>Eine Hilfe für das Datumsformat</h3>
<p>Zur Ausgabe des Datums im richtigen Format haben wir die Methode <strong>w3c_date()</strong> im <strong>sitemap_helper.rb</strong> definiert.</p>
<pre lang="rails">module SitemapHelper

def w3c_date(date)
date.utc.strftime("%Y-%m-%dT%H:%M:%S+00:00")
end

end</pre>
<h3>Fast fertig</h3>
<p>Damit wir diese Action nun auch über die <abbr title="Uniform Resource Locator">URL</abbr> http://www.name-der-seite.de/sitemap.xml aufrufen können, werden wir in der Datei <strong>routes.rb</strong> noch ein entsprechendes Mapping anlegen.</p>
<pre lang="rails">map.connect "sitemap.xml", :controller =&gt; "sitemap", :action =&gt; "index"</pre>
<p>Nun steht dem Aufruf durch Google und der anschließenden erfolgreichen Indizierung unserer gesamten Blogbeiträge nichts mehr im Weg.</p>
<p>Abschließend kann man sagen, dass <abbr>XML</abbr> mit Ruby on Rails wirklich nicht schwer ist. Wenn man den gesamten Aufwand betrachtet, so konnten wir die geforderte Funktionalität in 5 bis 10 Minuten umsetzen. Wenn das nicht effektiv ist, was denn dann? :o)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://webmatze.de/google-sitemaps-mit-ruby-on-rails-erstellen/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>RubyOnRails &#8211; Framework auf Schienen</title>
		<link>https://webmatze.de/rubyonrails-framework-auf-schienen/</link>
					<comments>https://webmatze.de/rubyonrails-framework-auf-schienen/#comments</comments>
		
		<dc:creator><![CDATA[Mathias Karstädt]]></dc:creator>
		<pubDate>Thu, 18 Aug 2005 18:00:00 +0000</pubDate>
				<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<guid isPermaLink="false">http://version3.webmatze.de/rubyonrails-framework-auf-schienen/</guid>

					<description><![CDATA[Vor kurzem bin ich auf die Seite RubyOnRails.com gestoßen, auf der ein Open Source Framework zur schnellen und unkomplizierten Erstellung von Web-Anwendungen in Ruby angeboten oder vielmehr angepriesen wird. Zuerst dachte ich mir: "Okay, wieder so ein Hype der irgendwann wieder verschwinden wird." Schon zu oft wurde versprochen, dass dieses oder jendes Framework das einzig [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Vor kurzem bin ich auf die Seite <a href="http://www.rubyonrails.com/">RubyOnRails.com</a> gestoßen, auf der ein Open Source Framework zur schnellen und unkomplizierten Erstellung von Web-Anwendungen in <a href="http://www.loudthinking.com/arc/000199.html">Ruby </a>angeboten oder vielmehr angepriesen wird.<br />
Zuerst dachte ich mir: <span style="font-style: italic;">"Okay, wieder so ein Hype der irgendwann wieder verschwinden wird."</span> Schon zu oft wurde versprochen, dass dieses oder jendes Framework das einzig Wahre sei und es einem all die komplizierten Dinge abnehmen kann. Doch je mehr Frameworks ich mir angesehen und damit herumspielt habe, um so überzeugter bin ich, dass es nicht die Frameworks sind die einem Entwickler gute Anwendungen schreiben lassen, sondern das es die Fähigkeiten des Entwicklers selbst sind!<br />
Doch <span style="font-weight: bold;">RubyOnRails</span> hat einen entscheidenen Unterschied zu all den anderen Frameworks. In einem <a href="http://www.rubyonrails.com/media/video/rails_take2_with_sound.mov">Video auf der Webseite</a> wird anhand eines Live Beispiels gezeigt, wie man innerhalb weniger Minuten ein lauffähiges Blog programmieren kann. Und schon allein das Zuschauen macht bei diesem Video Spaß! Keine trockenen Aussagen wie: <span style="font-style: italic;">"Klicke hier! Klicke da!"</span>, sondern: <span style="font-style: italic;">"Knack, Knack - Bums!"</span> und fertig ist das Blog!<br />
Allein dieses Video hat mich überzeugt, mir das Framework herunterzuladen und damit herumzuspielen. Und wirklich - innerhalb weniger Minuten habe ich mir eine kleine Web-Anwendung programmiert. Nichts Großes, aber gut genug um mir zu zeigen, welches Potenziel in diesem Framework steckt. Ohne sich um die komplizierten Programmteile einer Web-Anwendung kümmern zu müssen, gelingt es einem schnell zu funktionierenden Ergebnissen zu kommen.<br />
Da ich in den letzen Monaten an meinem <a href="http://www.eventicus.de/">Online Veranstaltungs Kalender - Eventicus.de</a> programmiert habe wurde mir klar, wie viel schneller ich die ganze Anwendung mit diesem Framework hätte schreiben können. Dinge wie Formular Handling, Datenbankabfragen und Workflow - alles wird einem abgenommen.<br />
In der Zwischenzeit habe ich noch einige weitere Anwendungen geschrieben. Jedoch benutze ich nun nicht RubyOnRails dafür, sondern eine PHP Variante mit Namen <a href="http://cakephp.org/">Cake</a>!<br />
Demnächst werde ich an dieser Stelle auch ein paar der Anwendungen vorstellen. Ich hoffe sie gefallen euch genauso gut wie mir.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://webmatze.de/rubyonrails-framework-auf-schienen/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
