<?xml version="1.0" encoding="UTF-8"?><feed
	xmlns="http://www.w3.org/2005/Atom"
	xmlns:thr="http://purl.org/syndication/thread/1.0"
	xml:lang="de-DE"
	>
	<title type="text">RubyOnRails</title>
	<subtitle type="text">Ruby On Rails</subtitle>

	<updated>2012-10-09T08:10:48Z</updated>

	<link rel="alternate" type="text/html" href="https://rubyonrails.de" />
	<id>https://rubyonrails.de/feed/atom/</id>
	<link rel="self" type="application/atom+xml" href="https://rubyonrails.de/feed/atom/" />

	<generator uri="https://wordpress.org/" version="5.9.3">WordPress</generator>
	<entry>
		<author>
			<name>derkaan</name>
					</author>

		<title type="html"><![CDATA[Ruby on Rails Volltextsuche mit ElasticSearch und Tire]]></title>
		<link rel="alternate" type="text/html" href="https://rubyonrails.de/2012/10/ruby-on-rails-volltextsuche-mit-elasticsearch-und-tire/" />

		<id>http://www.rubyonrails.de/?p=3641</id>
		<updated>2012-10-09T08:10:48Z</updated>
		<published>2012-10-09T08:10:48Z</published>
		<category scheme="https://rubyonrails.de" term="Tutorials" />
		<summary type="html"><![CDATA[ElasticSearch ist ein OpenSource Java Suchserver auf Basis des Apache Lucene Projekts, jedoch ohne dessen vergleichsweise hohe Komplexität und Konfigurationsaufwand. Autor von ElasticSearch ist Shay Banon aus Israel. Die Hauptgründe ElasticSearch einzusetzen liegen in der Einfachheit, der Skalierbarkeit und der JSON/HTTP Schnittstelle bei der schemalos, dokumentenorientiert (JSON-Dokumente, NoSQL-mäßig) indiziert und gesucht werden kann. ElasticSearch ist extrem schnell, quasi Echtzeit und kann seine Daten auf mehrere Clusterknoten (Nodes) horizontal verteilen.

In diesem Artikel möchte ich ElasticSearch vorstellen, sowie eine Rails Blog-Anwendung mit Hilfe des Gems Tire an die ElasticSearch anbinden.]]></summary>

					<content type="html" xml:base="https://rubyonrails.de/2012/10/ruby-on-rails-volltextsuche-mit-elasticsearch-und-tire/"><![CDATA[<h2>Installation</h2>
<p><b>OS X </b><br />
<br />
Unter OS X kann man sich die aktuelle Version via homebrew [tooltip title=&#8220;Help&#8220; content=&#8220;Homebrew ist ein OpenSource Paketmanager für OS X&#8220; type=&#8220;info&#8220;](?)[/tooltip] installieren:<br />
<a href="https://rubyonrails.de/wp-content/uploads/2012/10/OSX-Installation.png"><img class="size-full wp-image-3645 " title="OSX-Installation" src="https://rubyonrails.de/wp-content/uploads/2012/10/OSX-Installation.png" alt="Bash Screenshot von der Installation auf OSX" width="616" height="728" /></a><br />
<b>Debian / Ubuntu</b><br />
Eine Installationsanleitung für Debian basierte Systeme befindet sich direkt auf elasticsearch.org: <a href="http://www.elasticsearch.org/tutorials/2010/07/02/setting-up-elasticsearch-on-debian.html" target="_blank">http://www.elasticsearch.org/tutorials/2010/07/02/setting-up-elasticsearch-on-debian.html</a></p>
<p><b>RedHat / CentOS &#8230;</b><br />
Für RedHat basierte Systeme hat Tavisto (<a href="https://github.com/tavisto/elasticsearch-rpms" title="https://github.com/tavisto/elasticsearch-rpms" target="_blank">https://github.com/tavisto/elasticsearch-rpms</a>) entsprechende SPEC-Files für die ElasticSearch RPM Erstellung bereitgestellt.</p>
<p><b>andere Systeme</b><br />
Alternativ kann die aktuelle Version hier heruntergeladen und installiert werden: <a href="http://www.elasticsearch.org/download/" target="_blank">http://www.elasticsearch.org/download/</a></p>
<p>Nach der Installation und dem Start des Services sollte der ElasticSearch Server erreichbar sein. Der ElasticSearch Server liefert den Status, seine Versionsnummer und weitere Zusatzinformationen als JSON zurück:<br />
<a href="https://rubyonrails.de/wp-content/uploads/2012/10/browser-screenshot.png"><img loading="lazy" class="size-full wp-image-3644 " title="browser-screenshot" src="https://rubyonrails.de/wp-content/uploads/2012/10/browser-screenshot.png" alt="JSON-Dokument mit Installationsdetails" width="589" height="394" /></a><br />
</p>
<h2>Zustand der ElasticSearch überwachen</h2>
<p>Für einen späteren produktiven Einsatz der ElasticSearch sollte das Monitoring nicht außer Acht gelassen werden. Hierbei haben sich verschiedene Monitoring-Tools bewährt:  </p>
<ul>
<li><b>Elasticsearch-head</b> <a href="http://mobz.github.com/elasticsearch-head/" target="_blank">mobz.github.com/elasticsearch-head</a><br />
Elasticsearch-head ist eine statische Webseite mit JavaScript. Hilft die Performance der einzelnen Shards [tooltip title=&#8220;Help&#8220; content=&#8220;engl. für Scherben&#8220; type=&#8220;info&#8220;](?)[/tooltip] zu überwachen. Man kann sich direkt ähnlich wie bei PHPMyAdmin oder Futon(CouchDB) direkt die Daten anzeigen lassen.
</li>
<li><b>Kibana</b> <a href="https://github.com/rashidkpc/Kibana" target="_blank">github.com/rashidkpc/Kibana</a><br />
Kibana ist eine eigene Rails-Anwendung und sehr benutzerfreundlich. Manuelles Suchen, komplette Visualisierungen und Analysen z.B. auf Basis der Logs können konfiguriert und dargestellt werden.
</li>
<li>Bigdesk <a href="https://github.com/lukas-vlcek/bigdesk">github.com/lukas-vlcek/bigdesk</a><br />
Bigdesk eignet sich gut für das Monitoring der Hauptparameter des ElasticSearch Servers (Speicher, CPU, &#8230;).
</li>
</ul>
<p></p>
<h2>ElasticSearch Funktionsweise / Daten speichern</h2>
<p>Angenommen wir möchten eine Suche für einen Blog anlegen. Der Blog besteht aus mehreren Artikeln. Jeder Artikel enthält einen Text, eine Überschrift, ein Datum, sowie einen User.  Da ElasticSearch eine RESTful-HTTP Schnittstelle bereitstellt, können wir mit Hilfe von z.B. curl [tooltip title=&#8220;Help&#8220; content=&#8220;Curl ist ein Kommandozeilen-Programm zum Übertragen von Dateien im Netzwerk&#8220; type=&#8220;info&#8220;](?)[/tooltip] alle Artikeldatensätze im JSON-Format an die ElasticSearch übergeben. Im nachfolgenden Beispiel übermitteln wir zwei Artikel, samt Inhalt an die ElasticSearch.<br />
[ruby]<br />
curl -XPUT &#8218;http://localhost:9200/artikel/text/1&#8216; -d &#8218;{<br />
    &quot;user&quot; : &quot;Alex&quot;,<br />
    &quot;post_date&quot; : &quot;2012-10-05T14:12:12&quot;,<br />
    &quot;ueberschrift&quot; : &quot;Alles wird schlechter&quot;,<br />
    &quot;text&quot; : &quot;Hamburg &#8211; Immer mehr Arbeitnehmer in Deutschland haben zwei Jobs&#8230;&quot;}&#8216;<br />
curl -XPUT &#8218;http://localhost:9200/artikel/text/2&#8216; -d &#8218;{<br />
    &quot;user&quot; : &quot;Alex&quot;,<br />
    &quot;post_date&quot; : &quot;2012-10-04T14:12:12&quot;,<br />
    &quot;ueberschrift&quot; : &quot;96 gewinnt&quot;,<br />
    &quot;text&quot; : &quot;Hannover 96 &#8211; Der neue große HSV von 1896 schlägt Levante daheim in Unterzahl 2:1&quot;}&#8216;<br />
[/ruby]<br />
</p>
<p>Jeder einzelne Request wird bestätigt:<br />
[ruby]<br />
{&quot;ok&quot;:true,&quot;_index&quot;:&quot;artikel&quot;,&quot;_type&quot;:&quot;text&quot;,&quot;_id&quot;:&quot;1&quot;,&quot;_version&quot;:1}<br />
[/ruby]<br />
</p>
<p>Wir sehen, dass der Index automatisch von der ElasticSearch erstellt wird, falls dieser noch nicht existiert. In unserem Fall heißt der Index &#8222;artikel&#8220;. Jeder Index besteht aus mehreren sogenannten Shards[tooltip title=&#8220;Help&#8220; content=&#8220;engl. für Scherbe&#8220; type=&#8220;info&#8220;](?)[/tooltip]. Diese wiederum werden automatisch über die einzelnen Nodes (Server), falls vorhanden, verteilt. Standardmäßig hat jeder Index  fünf primäre Shards (0-4). Die Anzahl der primären Shards können nach Erstellung des Index nicht mehr geändert werden.<br />
Jede Shard kann null oder mehr Replica-Shards haben. Ein Replica-Shard ist eine Kopie einer primären Shard. Die Anzahl der Replica-Shards kann zur Laufzeit dynamisch geändert werden.<br />
Die Hauptaufgabe der Replica-Shards sind das Failover Verhalten zu verbessern, falls die primäre Shard nicht mehr zur Verfügung steht und die Performance der Elasticsearch bei Get- und Search-Requests zu verbessern.</p>
<p><a href="https://rubyonrails.de/wp-content/uploads/2012/10/architectur-elastic-search-cluster.png"><img loading="lazy" class="size-full wp-image-3642 " title="architectur-elastic-search-cluster" src="https://rubyonrails.de/wp-content/uploads/2012/10/architectur-elastic-search-cluster.png" alt="Architektur im Clusterverbund" width="446" height="500" /></a><br />
<br />
Möchte man andere Parameter bei der Indexerstellung setzen, hilft einem die Reference Guide weiter (<a href="http://www.elasticsearch.org/guide/reference/api/admin-indices-create-index.html" target="_blank">elasticsearch.org/guide/reference/api/admin-indices-create-index.html</a>). Die ElasticSearch arbeitet mit Versionierung. D.h. laden wir unseren ersten Artikel erneut, z.B. mit korrigiertem Text hoch, so erhalten wir nachfolgende Artwort:<br />
[ruby]<br />
{&quot;ok&quot;:true,&quot;_index&quot;:&quot;artikel&quot;,&quot;_type&quot;:&quot;text&quot;,&quot;_id&quot;:&quot;1&quot;,&quot;_version&quot;:2}<br />
[/ruby]<br />
Anders als z.B. bei CouchDB oder anderen NoSQL-Datenbanken hat man bei ElasticSearch keinen Zugriff mehr auf eine ältere Version eines Dokuments.  </p>
<h2>ElasticSearch gespeicherte Daten ausgeben</h2>
<p>
Wir können uns, wie bei einer RESTful NoSQL-Datenbank zum Beispiel CouchDB, einen Eintrag zurückgeben lassen:<br />
[ruby]<br />
curl -XGET &#8218;http://localhost:9200/artikel/text/1&#8216;<br />
{<br />
  &quot;_index&quot; : &quot;artikel&quot;,<br />
  &quot;_type&quot; : &quot;text&quot;,<br />
  &quot;_id&quot; : &quot;1&quot;,<br />
  &quot;_version&quot; : 1,<br />
  &quot;exists&quot; : true, &quot;_source&quot; : {<br />
    &quot;user&quot; : &quot;Alex&quot;,<br />
    &quot;post_date&quot; : &quot;2012-10-05T14:12:12&quot;,<br />
    &quot;ueberschrift&quot; : &quot;Alles wird schlechter&quot;,<br />
    &quot;text&quot; : &quot;Hamburg &#8211; Immer mehr Arbeitnehmer in Deutschland haben zwei Jobs&#8230;&quot;}<br />
}<br />
[/ruby]</p>
<p></p>
<h2>Datensätze suchen</h2>
<p>Ausführliche Informationen findet man unter dem Stichwort <a href="http://www.elasticsearch.org/guide/reference/query-dsl/" target="_blank">Query-DSL</a> sowie <a href="http://www.elasticsearch.org/guide/reference/api/search/" target="_blank">Search-API</a> der Reference Guide. An dieser Stelle möchte ich lediglich beispielhaft alle Datensätze des Users Alex finden:<br />
[ruby]<br />
curl -XGET &#8218;http://localhost:9200/artikel/_search?q=user:Alex&#8216;<br />
{<br />
  &quot;took&quot; : 1,<br />
  &quot;timed_out&quot; : false,<br />
  &quot;_shards&quot; : {<br />
    &quot;total&quot; : 5,<br />
    &quot;successful&quot; : 5,<br />
    &quot;failed&quot; : 0<br />
  },<br />
  &quot;hits&quot; : {<br />
    &quot;total&quot; : 2,<br />
    &quot;max_score&quot; : 1.0,<br />
    &quot;hits&quot; : [ {<br />
      &quot;_index&quot; : &quot;artikel&quot;,<br />
      &quot;_type&quot; : &quot;text&quot;,<br />
      &quot;_id&quot; : &quot;1&quot;,<br />
      &quot;_score&quot; : 1.0, &quot;_source&quot; : {<br />
    &quot;user&quot; : &quot;Alex&quot;,<br />
    &quot;post_date&quot; : &quot;2012-10-05T14:12:12&quot;,<br />
    &quot;ueberschrift&quot; : &quot;Alles wird schlechter&quot;,<br />
    &quot;text&quot; : &quot;Hamburg &#8211; Immer mehr Arbeitnehmer in Deutschland haben zwei Jobs&#8230;&quot;}<br />
    }, {<br />
      &quot;_index&quot; : &quot;artikel&quot;,<br />
      &quot;_type&quot; : &quot;text&quot;,<br />
      &quot;_id&quot; : &quot;2&quot;,<br />
      &quot;_score&quot; : 1.0, &quot;_source&quot; : {<br />
    &quot;user&quot; : &quot;Alex&quot;,<br />
    &quot;post_date&quot; : &quot;2012-10-04T14:12:12&quot;,<br />
    &quot;ueberschrift&quot; : &quot;96 gewinnt&quot;,<br />
    &quot;text&quot; : &quot;Hannover 96 &#8211; Der neue große HSV von 1896 schlägt Levante daheim in Unterzahl 2:1&quot;}<br />
    } ]<br />
  }<br />
}<br />
[/ruby]<br />
</p>
<h2>ElasticSearch in Ruby on Rails Anwendungen mit dem Gem Tire einbinden</h2>
<p>Wir clonen uns nachfolgende Rails-Anwendung und initialisieren diese:<br />
[ruby]<br />
git clone https://github.com/agilastic/blog-search-with-tire-and-elasticsearch<br />
[/ruby]<br />
[ruby]<br />
cd blog-search-with-tire-and-elasticsearch<br />
bundle install<br />
bundle exec rake db:setup<br />
[/ruby]<br />
Die &#8222;blog-search-with-tire-and-elasticsearch&#8220;-Railsanwendung ist sehr überschaubar gehalten. Via Scaffolding haben wir &#8222;Article&#8220; erzeugt.<br />
[ruby]<br />
rails generate scaffold Article author:string, content:text, tag:string, published_at:date, title:string<br />
[/ruby]</p>
<p>
Durchsucht werden sollen die Inhalte unseres Models &#8222;Article&#8220;. Hierzu muss das Model &#8222;Article&#8220; angepasst werden. Um Tire einzubinden müssen im &#8222;Article&#8220;-Model zwei Module eingebunden werden. Das erste Modul dient zur Einstellung der Suche und der Indizierung. Das zweite Modul kümmert sich um die Callbacks und führt die automatische Updates des Index bei jede Änderung des Artikels aus. Außerdem muss ein Block für das Mapping definiert werden. Des Weiteren passen wir die search-Methode etwas an.<br />
[ruby]<br />
class Article &lt; ActiveRecord::Base<br />
  include Tire::Model::Search<br />
  include Tire::Model::Callbacks<br />
  attr_accessible :author, :tag, :content, :published_at, :title</p>
<p>  mapping do<br />
    indexes :id,           :index    =&gt; :not_analyzed<br />
    indexes :title,        :analyzer =&gt; &#8217;snowball&#8216;, :boost =&gt; 100<br />
    indexes :content,      :analyzer =&gt; &#8217;snowball&#8216;<br />
    indexes :author,       :analyzer =&gt; &#8218;keyword&#8216;<br />
    indexes :tag,       	 :analyzer =&gt; &#8218;keyword&#8216;<br />
    indexes :published_at, :type =&gt; &#8218;date&#8216;, :include_in_all =&gt; false<br />
  end</p>
<p>  def self.search(params)<br />
    tire.search(load: true) do<br />
      query {string params[:query]} if params[:query].present?<br />
    end<br />
  end<br />
end<br />
[/ruby]<br />
</p>
<p>Wer sich wundert was der &#8222;Snowball-Analyzer&#8220; ist, kann sich auf der Projekt-Webseite genauer informieren <a href="http://snowball.tartarus.org/texts/introduction.html" target="_blank">snowball.tartarus.org/texts/introduction.html</a><br />
Der Schneeball Analyzer kommt von Lucene und wurde ursprünglich in einem Projekt von snowball.tartarus.org entwickelt.</p>
<p>Das Suchformular in der articles#index-View wird angelegt:<br />
[ruby]<br />
&lt;div class=&quot;search&quot;&gt;<br />
  &lt;%= form_tag articles_path, method: :get do %&gt;<br />
    &lt;%= text_field_tag :query, params[:query] %&gt;<br />
    &lt;%= submit_tag &quot;Suchen&quot;, name: nil %&gt;<br />
  &lt;% end %&gt;<br />
&lt;/div&gt;<br />
[/ruby]<br />
Abschließend können Suchanfragen im Google-Stil durchgeführt werden:<br />
<a href="https://rubyonrails.de/wp-content/uploads/2012/10/browser-screenshot-article-listing.png"><img loading="lazy" class="size-full wp-image-3643 " title="browser-screenshot-article-listing" src="https://rubyonrails.de/wp-content/uploads/2012/10/browser-screenshot-article-listing.png" alt="Browserscreenshot mit Auflistung der Artikel" width="589" height="531" /></a></p>
<p>Sollten bereits mehrere Artikel vor der Integration von Tire im Blog vorhanden sein oder der ElasticSearch-&#8222;Artikel&#8220;-Index korrupt sein, so kann dieser neu angelegt und reindeziert werden. Dazu kann beispielsweise der nachfolgende Raketask genutzt werden:<br />
[ruby]<br />
rake elasticsearch:recreate_index<br />
[/ruby]</p>
<p>[ruby]<br />
namespace :elasticsearch do<br />
  task :recreate_index =&gt; :environment do<br />
    @data_tables = ActiveRecord::Base.connection.tables<br />
    @data_tables.delete(&quot;schema_migrations&quot;)<br />
    @data_tables.each do |single_table|<br />
      model = single_table.capitalize.singularize.constantize<br />
      model.all.each do |a|<br />
        a.tire.update_index<br />
      end<br />
    end<br />
  end<br />
[/ruby]</p>
<p>Viel Spaß beim Ausprobieren <img src="https://s.w.org/images/core/emoji/13.1.0/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p></p>
<div style="margin-top:10px">
<b>Gastbeitrag von: Alexander Ebeling-Hoppe</b><br />
Alexander Ebeling-Hoppe arbeitet bei der Zentralen Polizeidirektion Niedersachsen als Ruby on Rails, sowie als freiberuflicher Webentwickler (<a href="http://agilastic.de">agilastic.de</a>) und Lehrbeauftragter.
</div>
<div style="margin-top:10px">
Werbung in eigener Sache:</p>
<p>Ich bieten Ihnen eine viertägige <b>Ruby on Rails Grundlagenschulung</b> bei der VHS Hannover (Büssingweg 9, 30165 Hannover) an:</p>
<p>27./28.10.2012, 09:00 Uhr – 16:00 Uhr (Sa/So)<br />
03./04.11.2012, 09:00 Uhr – 16:00 Uhr (Sa/So)<br />
Kursnummer: 54079D8<br />
Gebühr: 156,40 € (regulär)<br />
Schüler, Studenten, Azubis etc. 113,20 €
</p></div>
<p>Weitere Details: <a href="http://www.rubyonrails.de/2012/10/vhs-on-rails/">VHS on RAILS</a></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://rubyonrails.de/2012/10/ruby-on-rails-volltextsuche-mit-elasticsearch-und-tire/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://rubyonrails.de/2012/10/ruby-on-rails-volltextsuche-mit-elasticsearch-und-tire/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>derkaan</name>
					</author>

		<title type="html"><![CDATA[VHS on Rails]]></title>
		<link rel="alternate" type="text/html" href="https://rubyonrails.de/2012/10/vhs-on-rails/" />

		<id>http://www.rubyonrails.de/?p=3637</id>
		<updated>2012-10-08T08:00:06Z</updated>
		<published>2012-10-08T08:00:06Z</published>
		<category scheme="https://rubyonrails.de" term="Events" />
		<summary type="html"><![CDATA[Die VHS Hannover bietet im Oktober einen Kurs für Rails-Neulinge an. Der Kurs findet am Wochenende statt und beinhaltet neben Rails auch eine Einführung in Ruby.]]></summary>

					<content type="html" xml:base="https://rubyonrails.de/2012/10/vhs-on-rails/"><![CDATA[<p>Gebühr: 156,40 €</p>
<p>Dozent(en):<a href="https://www.vhs-hannover.de/dozent.profil?dozent=1014677">Alexander Ebeling-Hoppe</a></p>
<p>Veranstaltungsort:<a title="Veranstaltungsort in Google Maps anzeigen" href="http://maps.google.de/?f=q&amp;hl=de&amp;geocode=&amp;q=B%C3%BCssingweg%209,%2030165%20Hannover&amp;ie=UTF8&amp;t=h&amp;z=16&amp;om=1" target="_blank">Volkshochschule Büssingweg, Büssingweg 9</a><br />
Ruby on RailsTermin(e):</p>
<ul id="kurstage">
<li>27.10.2012, 09:00 Uhr &#8211; 16:00 Uhr (Samstag)</li>
<li>28.10.2012, 09:00 Uhr &#8211; 16:00 Uhr (Sonntag)</li>
<li>03.11.2012, 09:00 Uhr &#8211; 16:00 Uhr (Samstag)</li>
<li>04.11.2012, 09:00 Uhr &#8211; 16:00 Uhr (Sonntag)</li>
</ul>
<p>Beschreibung:Sie lernen in diesem Kurs die Skriptsprache Ruby und darauf aufbauend das Web-Framework Ruby on Rails kennen. Anhand einfacher Beispiele erarbeiten wir gemeinsam die grundlegende Web-Anwendungsentwicklung vom Datenbankzugriff über das Design der Oberfläche bis hin zum Zugriff auf Web Services.<br />
Inhalt:<br />
&#8211; Schritt für Schritt Installation von Ruby und Ruby on Rails (RoR) unter OS X (eigene Notebooks mit eigener 3G Verbindung können mitgebracht werden)<br />
&#8211; Vorstellung der Arbeitsumgebung<br />
&#8211; Grundlagen von Ruby: Module, Klassen, Methoden und Attribute, etc.<br />
&#8211; Rails Grundlagen: MVC-Prinzip, ActiveRecord, Routing, Ajax (asynchrone Kommunikations), CRUD-Zugriffe (Create, Read, Update, Delete), DRY Prinzip, Relationen, Validierung, Installation eines Ruby-fähigen Web Servers, Ausblick Testen (Cucumber, RSpec)<br />
Empfohlene Vorkenntnisse: Grundlagen MAC OS X, Grundlagen HTML, keine Scheu vor dem Terminal (Eingabeaufforderung)</p>
<p>Weitere Details und Anmeldung: <a title="VHS Hannover" href="https://www.vhs-hannover.de/themen/kurs/details/webapplikationen-entwickeln-mit-ruby-on-rails-54079d8" target="_blank">https://www.vhs-hannover.de/themen/kurs/details/webapplikationen-entwickeln-mit-ruby-on-rails-54079d8</a></p>
]]></content>
		
					<link rel="replies" type="text/html" href="https://rubyonrails.de/2012/10/vhs-on-rails/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://rubyonrails.de/2012/10/vhs-on-rails/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>derkaan</name>
					</author>

		<title type="html"><![CDATA[Screencast: Bildbearbeitung mit RMagick]]></title>
		<link rel="alternate" type="text/html" href="https://rubyonrails.de/2012/08/screencast-bildbearbeitung-mit-rmagick/" />

		<id>http://www.rubyonrails.de/?p=3628</id>
		<updated>2012-08-17T06:26:09Z</updated>
		<published>2012-08-17T06:26:09Z</published>
		<category scheme="https://rubyonrails.de" term="Tutorials" /><category scheme="https://rubyonrails.de" term="CarrierWave" /><category scheme="https://rubyonrails.de" term="ImageMagick" /><category scheme="https://rubyonrails.de" term="RMagick" /><category scheme="https://rubyonrails.de" term="Ryan Bates" /><category scheme="https://rubyonrails.de" term="Screencast" /><category scheme="https://rubyonrails.de" term="Tools" />
		<summary type="html"><![CDATA[In diesem Screencast zeigt Ryan wie Bilder mit RMagick verändert und/oder verarbeitet werden. Teil des Screencastes widmet er auch CarrierWave das in Kombination mit RMagick für die Verarbeitung von hochgeladenen Bildern eingesetzt werden kann.]]></summary>

					<content type="html" xml:base="https://rubyonrails.de/2012/08/screencast-bildbearbeitung-mit-rmagick/"><![CDATA[<h4>Downloads in verschiedenen Formaten:</h4>
<p><a href="http://media.railscasts.com/assets/episodes/videos/374-image-manipulation.mp4">mp4</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/374-image-manipulation.m4v">m4v</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/374-image-manipulation.webm">webm</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/374-image-manipulation.ogv">ogg</a></p>
<div>&nbsp;</div>
<h4>Resourcen:</h4>
<ul>
<li><a href="http://www.imagemagick.org/script/index.php">ImageMagick</a></li>
<li><a href="http://www.imagemagick.org/Usage/">ImageMagick Usage Guide</a></li>
<li><a href="http://rmagick.rubyforge.org/">RMagick</a></li>
<li><a href="https://github.com/EricR/image_sorcery">Image Sorcery</a></li>
<li><a href="https://github.com/probablycorey/mini_magick/">Mini Magick</a></li>
<li><a href="http://railscasts.com/episodes/253-carrierwave-file-uploads">Episode 253: CarrierWave File Uploads</a></li>
</ul>
<p>
          terminal
        </p>
<p>[bash]<br />
brew install imagemagick<br />
convert -version<br />
convert octocat.png -resize &#8217;70&#215;70^&#8216; -gravity center -crop &#8217;70&#215;70+0+0&#8242; -quantize GRAY -colors 256 -contrast source.png<br />
composite stamp_overlay.png source.png source.png<br />
convert -size 70&#215;70 canvas:red ( octocat.png -resize &#8217;70&#215;70^&#8216; -gravity center -crop &#8217;70&#215;70+0+0&#8242; -quantize GRAY -colors 256 -contrast stamp_overlay.png -composite -negate ) -compose copy-opacity -composite stamp.png<br />
gem install rmagick<br />
mate stamp.rb<br />
ruby stamp.rb<br />
[/bash]</p>
<p>
          stamp.rb
        </p>
<p>[ruby]</p>
<p>require &quot;rmagick&quot;</p>
<p>source = Magick::Image.read(&quot;octocat.png&quot;).first<br />
source = source.resize_to_fill(70, 70).quantize(256, Magick::GRAYColorspace).contrast(true)<br />
overlay = Magick::Image.read(&quot;stamp_overlay.png&quot;).first<br />
source.composite!(overlay, 0, 0, Magick::OverCompositeOp)<br />
colored = Magick::Image.new(70, 70) { self.background_color = &quot;red&quot; }<br />
colored.composite!(source.negate, 0, 0, Magick::CopyOpacityCompositeOp)<br />
colored.write(&quot;stamp.png&quot;)</p>
<p># Or through the command line:<br />
# system &lt;&lt;-COMMAND<br />
# convert -size 70&#215;70 canvas:red \( octocat.png<br />
#   -resize &#8217;70&#215;70^&#8216; -gravity center -crop &#8217;70&#215;70+0+0&#8242;<br />
#   -quantize GRAY -colors 256 -contrast stamp_overlay.png<br />
#   -composite -negate<br />
# \) -compose copy-opacity -composite stamp.png<br />
# COMMAND<br />
[/ruby]</p>
<p>
          Gemfile
        </p>
<p>[ruby]<br />
gem &#8218;rmagick&#8216;<br />
gem &#8218;carrierwave&#8216;<br />
[/ruby]</p>
<p>
          models/stamp.rb
        </p>
<p>[ruby]</p>
<p>mount_uploader :image, StampUploader<br />
[/ruby]</p>
<p>
          app/uploaders/stamp_uploader.rb
        </p>
<p>[ruby]</p>
<p>class StampUploader &lt; CarrierWave::Uploader::Base<br />
  include CarrierWave::RMagick</p>
<p>  # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:<br />
  include Sprockets::Helpers::RailsHelper<br />
  include Sprockets::Helpers::IsolatedHelper</p>
<p>  # Choose what kind of storage to use for this uploader:<br />
  storage :file</p>
<p>  # Override the directory where uploaded files will be stored.<br />
  # This is a sensible default for uploaders that are meant to be mounted:<br />
  def store_dir<br />
    &quot;uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}&quot;<br />
  end</p>
<p>  # Add a white list of extensions which are allowed to be uploaded.<br />
  # For images you might use something like this:<br />
  def extension_white_list<br />
    %w(jpg jpeg gif png)<br />
  end</p>
<p>  %w[red green blue purple black].each do |color|<br />
    version(color) { process stamp: color }<br />
  end</p>
<p>  def stamp(color)<br />
    manipulate! format: &quot;png&quot; do |source|<br />
      overlay_path = Rails.root.join(&quot;app/assets/images/stamp_overlay.png&quot;)<br />
      overlay = Magick::Image.read(overlay_path).first<br />
      source = source.resize_to_fill(70, 70).quantize(256, Magick::GRAYColorspace).contrast(true)<br />
      source.composite!(overlay, 0, 0, Magick::OverCompositeOp)<br />
      colored = Magick::Image.new(70, 70) { self.background_color = color }<br />
      colored.composite(source.negate, 0, 0, Magick::CopyOpacityCompositeOp)<br />
    end<br />
  end<br />
end<br />
[/ruby]</p>
<p>
          stamps/index.html
        </p>
<p>[html]<br />
&lt;%= image_tag stamp.image_url(:blue) %&gt;<br />
[/html]</p>
]]></content>
		
		<link href="http://media.railscasts.com/assets/episodes/videos/374-image-manipulation.mp4" rel="enclosure" length="31908276" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/374-image-manipulation.m4v" rel="enclosure" length="15197733" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/374-image-manipulation.webm" rel="enclosure" length="16074271" type="application/wordperfect" />
<link href="http://media.railscasts.com/assets/episodes/videos/374-image-manipulation.ogv" rel="enclosure" length="31721424" type="video/ogg" />
			<link rel="replies" type="text/html" href="https://rubyonrails.de/2012/08/screencast-bildbearbeitung-mit-rmagick/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://rubyonrails.de/2012/08/screencast-bildbearbeitung-mit-rmagick/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>derkaan</name>
					</author>

		<title type="html"><![CDATA[Screencast: Bullet]]></title>
		<link rel="alternate" type="text/html" href="https://rubyonrails.de/2012/08/screencast-bullet/" />

		<id>http://www.rubyonrails.de/?p=3624</id>
		<updated>2012-08-17T06:24:34Z</updated>
		<published>2012-08-17T06:24:34Z</published>
		<category scheme="https://rubyonrails.de" term="Tutorials" /><category scheme="https://rubyonrails.de" term="Performance" /><category scheme="https://rubyonrails.de" term="Plugin" /><category scheme="https://rubyonrails.de" term="Ryan Bates" /><category scheme="https://rubyonrails.de" term="Screencast" />
		<summary type="html"><![CDATA[Bullet ist ein Ruby gem das die abgesetzten SQL Befehle analysiert und beim Endecken von Verbesserungspotial den Anwender auf diese hinweist.
Es unterstützt dabei eine Vielzahl an Benachrichtigungsmöglichkeiten.]]></summary>

					<content type="html" xml:base="https://rubyonrails.de/2012/08/screencast-bullet/"><![CDATA[<div>&nbsp;</div>
<h4>Downloads in verschiedenen Formaten:</h4>
<p><a href="http://media.railscasts.com/assets/episodes/videos/372-bullet.mp4">mp4</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/372-bullet.m4v">m4v</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/372-bullet.webm">webm</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/372-bullet.ogv">ogg</a></p>
<div>&nbsp;</div>
<h4>Resourcen:</h4>
<ul>
<li><a href="https://github.com/flyerhzm/bullet">Bullet</a></li>
</ul>
<p>
          terminal
        </p>
<p>[bash]<br />
rails g migration add_products_count_to_categories products_count:integer<br />
rails g migration cache_products_count<br />
rake db:migrate<br />
[/bash]</p>
<p>
          Gemfile
        </p>
<p>[ruby]</p>
<p>gem &#8218;bullet&#8216;, group: :development<br />
[/ruby]</p>
<p>
          config/initializers/bullet.rb
        </p>
<p>[ruby]</p>
<p>if defined? Bullet<br />
  Bullet.enable = true<br />
  # Bullet.alert = true<br />
  Bullet.bullet_logger = true<br />
end<br />
[/ruby]</p>
<p>
          categories_controller.rb
        </p>
<p>[ruby]</p>
<p>def index<br />
  @categories = Category.order(:name).includes(:products)<br />
end<br />
[/ruby]</p>
<p>
          db/migrate/cache_products_count.rb
        </p>
<p>[ruby]</p>
<p>class CacheProductsCount &lt; ActiveRecord::Migration<br />
  def up<br />
    execute &quot;update categories set products_count=(select count(*) from products where category_id=categories.id)&quot;<br />
  end</p>
<p>  def down<br />
  end<br />
end<br />
[/ruby]</p>
]]></content>
		
		<link href="http://media.railscasts.com/assets/episodes/videos/372-bullet.mp4" rel="enclosure" length="18270262" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/372-bullet.m4v" rel="enclosure" length="8123244" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/372-bullet.webm" rel="enclosure" length="10503003" type="application/wordperfect" />
<link href="http://media.railscasts.com/assets/episodes/videos/372-bullet.ogv" rel="enclosure" length="17360337" type="video/ogg" />
			<link rel="replies" type="text/html" href="https://rubyonrails.de/2012/08/screencast-bullet/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://rubyonrails.de/2012/08/screencast-bullet/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>derkaan</name>
					</author>

		<title type="html"><![CDATA[Screencast: Ransack]]></title>
		<link rel="alternate" type="text/html" href="https://rubyonrails.de/2012/08/screencast-ransack/" />

		<id>http://www.rubyonrails.de/?p=3619</id>
		<updated>2012-08-09T14:45:40Z</updated>
		<published>2012-08-09T14:45:40Z</published>
		<category scheme="https://rubyonrails.de" term="Tutorials" /><category scheme="https://rubyonrails.de" term="Plugin" /><category scheme="https://rubyonrails.de" term="Ryan Bates" /><category scheme="https://rubyonrails.de" term="Screencast" /><category scheme="https://rubyonrails.de" term="Search" />
		<summary type="html"><![CDATA[Mit Ransack können auf eine Weise komplexe und anspruchsvolle Suchformulare erstellt werden. Es unterstützt auch bei der Darstellung der Suchergebnisse, indem es sortierbare Listen und dynamische Suchseiten erstellt.]]></summary>

					<content type="html" xml:base="https://rubyonrails.de/2012/08/screencast-ransack/"><![CDATA[<div>&nbsp;</div>
<h4>Downloads in verschiedenen Formaten:</h4>
<p><a href="http://media.railscasts.com/assets/episodes/videos/370-ransack.mp4">mp4</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/370-ransack.m4v">m4v</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/370-ransack.webm">webm</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/370-ransack.ogv">ogg</a></p>
<div>&nbsp;</div>
<h4>Resourcen:</h4>
<ul>
<li><a href="https://github.com/ernie/ransack/">Ransack</a></li>
<li><a href="http://ransack-demo.herokuapp.com/">Ransack Demo</a></li>
<li><a href="http://railscasts.com/episodes/196-nested-model-form-revised">Episode 196: Nested Model Form (revised)</a></li>
<li><a href="http://railscasts.com/episodes/111-advanced-search-form-revised">Episode 111: Advanced Search Form (revised)</a></li>
</ul>
<p>
          Gemfile
        </p>
<p>[ruby]</p>
<p>gem &#8218;ransack&#8216;<br />
[/ruby]</p>
<p>
          products_controller.rb
        </p>
<p>[ruby]</p>
<p>def index<br />
  @search = Product.search(params[:q])<br />
  @products = @search.result<br />
end<br />
[/ruby]</p>
<p>
          products/index.html.erb
        </p>
<p>[html]</p>
<p>&lt;%= search_form_for @search, url: search_products_path, method: :post do |f| %&gt;<br />
  &lt;%= f.condition_fields do |c| %&gt;<br />
    &lt;%= render &quot;condition_fields&quot;, f: c %&gt;<br />
  &lt;% end %&gt;<br />
  &lt;p&gt;&lt;%= link_to_add_fields &quot;Add Conditions&quot;, f, :condition %&gt;&lt;/p&gt;<br />
  &lt;div class=&quot;field&quot;&gt;<br />
    Sort:<br />
    &lt;%= f.sort_fields do |s| %&gt;<br />
      &lt;%= s.sort_select %&gt;<br />
    &lt;% end %&gt;<br />
  &lt;/div&gt;<br />
  &lt;div class=&quot;actions&quot;&gt;&lt;%= f.submit &quot;Search&quot; %&gt;&lt;/div&gt;<br />
&lt;% end %&gt;</p>
<p>&lt;table id=&quot;products&quot;&gt;<br />
  &lt;tr&gt;<br />
    &lt;th&gt;&lt;%= sort_link @search, :name, &quot;Product Name&quot; %&gt;&lt;/th&gt;<br />
    &lt;th&gt;&lt;%= sort_link @search, :released_on, &quot;Release Date&quot; %&gt;&lt;/th&gt;<br />
    &lt;th&gt;&lt;%= sort_link @search, :price, &quot;Price&quot; %&gt;&lt;/th&gt;<br />
  &lt;/tr&gt;<br />
&lt;% @products.each do |product| %&gt;<br />
  &lt;tr&gt;<br />
    &lt;td&gt;&lt;%= link_to(product.name, product) %&gt;&lt;/td&gt;<br />
    &lt;td&gt;&lt;%= product.released_on.strftime(&quot;%B %e, %Y&quot;) %&gt;&lt;/td&gt;<br />
    &lt;td&gt;&lt;%= number_to_currency(product.price) %&gt;&lt;/td&gt;<br />
  &lt;/tr&gt;<br />
&lt;% end %&gt;<br />
&lt;/table&gt;<br />
[/html]</p>
<p>
          config/routes.rb
        </p>
<p>[ruby]</p>
<p>resources :products do<br />
  collection { post :search, to: &#8218;products#index&#8216; }<br />
end<br />
[/ruby]</p>
<p>
          products_controller.rb
        </p>
<p>[ruby]<br />
def index<br />
  @search = Product.search(params[:q])<br />
  @products = @search.result<br />
  @search.build_condition if @search.conditions.empty?<br />
  @search.build_sort if @search.sorts.empty?<br />
end<br />
[/ruby]</p>
<p>
          products/index.html.erb
        </p>
<p>[html]<br />
&lt;%= search_form_for @search, url: search_products_path, method: :post do |f| %&gt;<br />
  &lt;%= f.condition_fields do |c| %&gt;<br />
    &lt;%= render &quot;condition_fields&quot;, f: c %&gt;<br />
  &lt;% end %&gt;<br />
  &lt;p&gt;&lt;%= link_to_add_fields &quot;Add Conditions&quot;, f, :condition %&gt;&lt;/p&gt;<br />
  &lt;div class=&quot;field&quot;&gt;<br />
    Sort:<br />
    &lt;%= f.sort_fields do |s| %&gt;<br />
      &lt;%= s.sort_select %&gt;<br />
    &lt;% end %&gt;<br />
  &lt;/div&gt;<br />
  &lt;div class=&quot;actions&quot;&gt;&lt;%= f.submit &quot;Search&quot; %&gt;&lt;/div&gt;<br />
&lt;% end %&gt;<br />
[/html]</p>
<p>
          products/_condition_fields.html.erb
        </p>
<p>[html]</p>
<p>&lt;div class=&quot;field&quot;&gt;<br />
  &lt;%= f.attribute_fields do |a| %&gt;<br />
    &lt;%= a.attribute_select associations: [:category] %&gt;<br />
  &lt;% end %&gt;<br />
  &lt;%= f.predicate_select %&gt;<br />
  &lt;%= f.value_fields do |v| %&gt;<br />
    &lt;%= v.text_field :value %&gt;<br />
  &lt;% end %&gt;<br />
  &lt;%= link_to &quot;remove&quot;, &#8218;#&#8216;, class: &quot;remove_fields&quot; %&gt;<br />
&lt;/div&gt;<br />
[/html]</p>
<p>
          application_helper.rb
        </p>
<p>[ruby]</p>
<p>def link_to_add_fields(name, f, type)<br />
  new_object = f.object.send &quot;build_#{type}&quot;<br />
  id = &quot;new_#{type}&quot;<br />
  fields = f.send(&quot;#{type}_fields&quot;, new_object, child_index: id) do |builder|<br />
    render(type.to_s + &quot;_fields&quot;, f: builder)<br />
  end<br />
  link_to(name, &#8218;#&#8216;, class: &quot;add_fields&quot;, data: {id: id, fields: fields.gsub(&quot;n&quot;, &quot;&quot;)})<br />
end<br />
[/ruby]</p>
<p>
          products.js.coffee
        </p>
<p>[javascript]<br />
jQuery -&gt;<br />
  $(&#8218;form&#8216;).on &#8218;click&#8216;, &#8218;.remove_fields&#8216;, (event) -&gt;<br />
    $(this).closest(&#8218;.field&#8216;).remove()<br />
    event.preventDefault()</p>
<p>  $(&#8218;form&#8216;).on &#8218;click&#8216;, &#8218;.add_fields&#8216;, (event) -&gt;<br />
    time = new Date().getTime()<br />
    regexp = new RegExp($(this).data(&#8218;id&#8216;), &#8218;g&#8216;)<br />
    $(this).before($(this).data(&#8218;fields&#8216;).replace(regexp, time))<br />
    event.preventDefault()<br />
[/javascript]</p>
]]></content>
		
		<link href="http://media.railscasts.com/assets/episodes/videos/370-ransack.mp4" rel="enclosure" length="30362608" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/370-ransack.m4v" rel="enclosure" length="13368095" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/370-ransack.webm" rel="enclosure" length="15744776" type="application/wordperfect" />
<link href="http://media.railscasts.com/assets/episodes/videos/370-ransack.ogv" rel="enclosure" length="32210636" type="video/ogg" />
			<link rel="replies" type="text/html" href="https://rubyonrails.de/2012/08/screencast-ransack/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://rubyonrails.de/2012/08/screencast-ransack/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>derkaan</name>
					</author>

		<title type="html"><![CDATA[Screencast: MiniProfiler]]></title>
		<link rel="alternate" type="text/html" href="https://rubyonrails.de/2012/08/screencast-miniprofiler/" />

		<id>http://www.rubyonrails.de/?p=3616</id>
		<updated>2012-08-08T14:42:08Z</updated>
		<published>2012-08-08T14:42:08Z</published>
		<category scheme="https://rubyonrails.de" term="Tutorials" /><category scheme="https://rubyonrails.de" term="Performance" /><category scheme="https://rubyonrails.de" term="Plugin" /><category scheme="https://rubyonrails.de" term="Ryan Bates" /><category scheme="https://rubyonrails.de" term="Screencast" /><category scheme="https://rubyonrails.de" term="Tools" />
		<summary type="html"><![CDATA[MiniProfiler erlaubt es sich Geschwindigkeitsmessungen direkt auf der aufgerufenen Seite anzuschauen. Dabei werden auch die aufgerufenen SQL Befehle und wenn gewünscht Messungen für ausgesuchte Code-Blöcke.
]]></summary>

					<content type="html" xml:base="https://rubyonrails.de/2012/08/screencast-miniprofiler/"><![CDATA[<div>&nbsp;</div>
<h4>Downloads in verschiedenen Formaten:</h4>
<p><a href="http://media.railscasts.com/assets/episodes/videos/368-miniprofiler.mp4">mp4</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/368-miniprofiler.m4v">m4v</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/368-miniprofiler.webm">webm</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/368-miniprofiler.ogv">ogg</a></p>
<div>&nbsp;</div>
<h4>Resourcen:</h4>
<ul>
<li><a href="http://miniprofiler.com/">MiniProfiler</a></li>
<li><a href="http://samsaffron.com/archive/2012/07/12/miniprofiler-ruby-edition">MiniProfiler Ruby Edition</a></li>
<li><a href="http://railscasts.com/episodes/23-counter-cache-column">Episode 23: Counter Cache Column</a></li>
<li><a href="http://railscasts.com/episodes/72-adding-an-environment-revised">Episode 72: Adding an Environment (revised)</a></li>
</ul>
<p>
          Gemfile
        </p>
<p>[ruby]</p>
<p>  gem &#8218;rack-mini-profiler&#8216;<br />
[/ruby]</p>
<p>
          products/index.html.erb
        </p>
<p>[html]<br />
&lt;%= pluralize project.tasks.size, &quot;task&quot; %&gt;<br />
[/html]</p>
<p>
          projects_controller.rb
        </p>
<p>[ruby]</p>
<p>@projects = Project.order(:created_at).select(&quot;projects.*, count(tasks.id) as tasks_count&quot;).joins(&quot;left outer join tasks on project_id=projects.id&quot;).group(&quot;projects.id&quot;)<br />
Rack::MiniProfiler.step(&quot;fetch projects&quot;) do<br />
  @projects.all<br />
end<br />
[/ruby]</p>
<p>
          config/environments/production.rb
        </p>
<p>[ruby]</p>
<p>config.serve_static_assets = true<br />
[/ruby]</p>
<p>
          terminal
        </p>
<p>[bash]<br />
rake assets:precompile<br />
rake db:setup RAILS_ENV=production<br />
rails s -e production<br />
[/bash]</p>
<p>
          application_controller.rb
        </p>
<p>[ruby]</p>
<p>before_filter :miniprofiler</p>
<p>private</p>
<p>def miniprofiler<br />
  Rack::MiniProfiler.authorize_request # if user.admin?<br />
end<br />
[/ruby]</p>
]]></content>
		
		<link href="http://media.railscasts.com/assets/episodes/videos/368-miniprofiler.mp4" rel="enclosure" length="34567501" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/368-miniprofiler.m4v" rel="enclosure" length="13973085" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/368-miniprofiler.webm" rel="enclosure" length="13891652" type="application/wordperfect" />
<link href="http://media.railscasts.com/assets/episodes/videos/368-miniprofiler.ogv" rel="enclosure" length="35476980" type="video/ogg" />
			<link rel="replies" type="text/html" href="https://rubyonrails.de/2012/08/screencast-miniprofiler/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://rubyonrails.de/2012/08/screencast-miniprofiler/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>derkaan</name>
					</author>

		<title type="html"><![CDATA[Screencast: Sidekiq]]></title>
		<link rel="alternate" type="text/html" href="https://rubyonrails.de/2012/08/screencast-sidekiq/" />

		<id>http://www.rubyonrails.de/?p=3613</id>
		<updated>2012-08-07T14:26:24Z</updated>
		<published>2012-08-07T14:26:24Z</published>
		<category scheme="https://rubyonrails.de" term="Tutorials" /><category scheme="https://rubyonrails.de" term="Background-Jobs" /><category scheme="https://rubyonrails.de" term="Plugin" /><category scheme="https://rubyonrails.de" term="Ryan Bates" /><category scheme="https://rubyonrails.de" term="Screencast" /><category scheme="https://rubyonrails.de" term="Sidekiq" />
		<summary type="html"><![CDATA[Sidekiq erlaubt es Prozesse im Hintergrund asynchron weiter zu verarbeiten während die Applikation bereits neue Anfragen entgegen nehmen kann. Es verwendet dabei Threads anstatt Forks und geht dadurch effizienter mit Resourcen um als vergleichsweise Resque. ]]></summary>

					<content type="html" xml:base="https://rubyonrails.de/2012/08/screencast-sidekiq/"><![CDATA[<div>&nbsp;</div>
<h4>Downloads in verschiedenen Formaten:</h4>
<p><a href="http://media.railscasts.com/assets/episodes/videos/366-sidekiq.mp4">mp4</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/366-sidekiq.m4v">m4v</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/366-sidekiq.webm">webm</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/366-sidekiq.ogv">ogg</a></p>
<div>&nbsp;</div>
<h4>Resourcen:</h4>
<ul>
<li><a href="http://mperham.github.com/sidekiq/">Sidekiq</a></li>
<li><a href="https://github.com/mperham/sidekiq/wiki">Sidekiq Wiki</a></li>
<li><a href="https://github.com/mperham/sidekiq">Sidekiq on GitHub</a></li>
<li><a href="http://celluloid.io">Celluloid</a></li>
<li><a href="http://railscasts.com/episodes/271-resque">Episode 271: Resque</a></li>
<li><a href="http://railscasts.com/episodes/365-thread-safety">Episode 365: Thread-Safety (pro)</a></li>
</ul>
<p>
          terminal
        </p>
<p>[bash]</p>
<p>  brew install redis<br />
redis-server /usr/local/etc/redis.conf<br />
bundle exec sidekiq<br />
bundle exec sidekiq -q high,5 default<br />
[/bash]</p>
<p>
          Gemfile
        </p>
<p>[ruby]<br />
gem &#8217;sidekiq&#8216;<br />
gem &#8217;sinatra&#8216;, require: false<br />
gem &#8217;slim&#8216;<br />
[/ruby]</p>
<p>
          snippets_controller.rb
        </p>
<p>[ruby]<br />
PygmentsWorker.perform_async(@snippet.id)<br />
# PygmentsWorker.perform_in(1.hour, @snippet.id)<br />
[/ruby]</p>
<p>
          app/workers/pygments_worker.rb
        </p>
<p>[ruby]</p>
<p>class PygmentsWorker<br />
  include Sidekiq::Worker<br />
  sidekiq_options queue: &quot;high&quot;<br />
  # sidekiq_options retry: false</p>
<p>  def perform(snippet_id)<br />
    snippet = Snippet.find(snippet_id)<br />
    uri = URI.parse(&quot;http://pygments.appspot.com/&quot;)<br />
    request = Net::HTTP.post_form(uri, lang: snippet.language, code: snippet.plain_code)<br />
    snippet.update_attribute(:highlighted_code, request.body)<br />
  end<br />
end<br />
[/ruby]</p>
<p>
          routes.rb
        </p>
<p>[ruby]</p>
<p>require &#8217;sidekiq/web&#8216;<br />
# &#8230;<br />
mount Sidekiq::Web, at: &#8218;/sidekiq&#8216;<br />
[/ruby]</p>
]]></content>
		
		<link href="http://media.railscasts.com/assets/episodes/videos/366-sidekiq.mp4" rel="enclosure" length="32110609" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/366-sidekiq.m4v" rel="enclosure" length="14092623" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/366-sidekiq.webm" rel="enclosure" length="15195058" type="application/wordperfect" />
<link href="http://media.railscasts.com/assets/episodes/videos/366-sidekiq.ogv" rel="enclosure" length="30870944" type="video/ogg" />
			<link rel="replies" type="text/html" href="https://rubyonrails.de/2012/08/screencast-sidekiq/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://rubyonrails.de/2012/08/screencast-sidekiq/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>derkaan</name>
					</author>

		<title type="html"><![CDATA[Screencast: Active Records Reputation System]]></title>
		<link rel="alternate" type="text/html" href="https://rubyonrails.de/2012/08/screencast-active-records-reputation-system/" />

		<id>http://www.rubyonrails.de/?p=3610</id>
		<updated>2012-08-06T14:19:48Z</updated>
		<published>2012-08-06T14:19:48Z</published>
		<category scheme="https://rubyonrails.de" term="Tutorials" /><category scheme="https://rubyonrails.de" term="ActiveRecord" /><category scheme="https://rubyonrails.de" term="Plugin" /><category scheme="https://rubyonrails.de" term="Ryan Bates" /><category scheme="https://rubyonrails.de" term="Screencast" />
		<summary type="html"><![CDATA[Wenn der Durchschnittswert für ein Bewertungssystem oder die Summe von abgegebenen Stimmen berechnet werden müssen, dann lohnt sich ein Blick auf das activerecord-reputation-system gem. Ryan zeigt in diesem Screencast wie es verwendet wird und wie eine selbsterstellte Basis-Version gebaut werden kann.]]></summary>

					<content type="html" xml:base="https://rubyonrails.de/2012/08/screencast-active-records-reputation-system/"><![CDATA[<div>&nbsp;</div>
<h4>Downloads in verschiedenen Formaten:</h4>
<p><a href="http://media.railscasts.com/assets/episodes/videos/364-active-record-reputation-system.mp4">mp4</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/364-active-record-reputation-system.m4v">m4v</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/364-active-record-reputation-system.webm">webm</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/364-active-record-reputation-system.ogv">ogg</a></p>
<div>&nbsp;</div>
<h4>Resourcen:</h4>
<ul>
<li><a href="https://github.com/twitter/activerecord-reputation-system/">Active Record Reputation System</a></li>
</ul>
<p>
          terminal
        </p>
<p>[bash]</p>
<p>  rails g reputation_system<br />
rake db:migrate<br />
[/bash]</p>
<p>
          Gemfile
        </p>
<p>[ruby]</p>
<p>  gem &#8218;activerecord-reputation-system&#8216;, require: &#8218;reputation_system&#8216;<br />
[/ruby]</p>
<p>
          models/haiku.rb
        </p>
<p>[ruby]</p>
<p>  has_reputation :votes, source: :user, aggregated_by: :sum<br />
[/ruby]</p>
<p>
          models/user.rb
        </p>
<p>[ruby]</p>
<p>  has_many :evaluations, class_name: &quot;RSEvaluation&quot;, as: :source</p>
<p>has_reputation :votes, source: {reputation: :votes, of: :haikus}, aggregated_by: :sum</p>
<p>def voted_for?(haiku)<br />
  evaluations.where(target_type: haiku.class, target_id: haiku.id).present?<br />
end<br />
[/ruby]</p>
<p>
          config/routes.rb
        </p>
<p>[ruby]</p>
<p>  resources :haikus do<br />
  member { post :vote }<br />
end<br />
[/ruby]</p>
<p>
          haikus_controller.rb
        </p>
<p>[ruby]</p>
<p>  def index<br />
  @haikus = Haiku.find_with_reputation(:votes, :all, order: &quot;votes desc&quot;)<br />
end</p>
<p>def vote<br />
  value = params[:type] == &quot;up&quot; ? 1 : -1<br />
  @haiku = Haiku.find(params[:id])<br />
  @haiku.add_or_update_evaluation(:votes, value, current_user)<br />
  redirect_to :back, notice: &quot;Thank you for voting&quot;<br />
end<br />
[/ruby]</p>
<p>
          _haiku.html.erb
        </p>
<p>[html]</p>
<p>  | &lt;%= pluralize haiku.reputation_value_for(:votes).to_i, &quot;vote&quot; %&gt;<br />
&lt;% if current_user &amp;&amp; !current_user.voted_for?(haiku) %&gt;<br />
  | &lt;%= link_to &quot;up&quot;, vote_haiku_path(haiku, type: &quot;up&quot;), method: &quot;post&quot; %&gt;<br />
  | &lt;%= link_to &quot;down&quot;, vote_haiku_path(haiku, type: &quot;down&quot;), method: &quot;post&quot; %&gt;<br />
&lt;% end %&gt;<br />
[/html]</p>
<p>
          application.html.erb
        </p>
<p>[html]</p>
<p>  &lt;%= current_user.reputation_value_for(:votes).to_i %&gt;<br />
[/html]</p>
<p>
          models/haiku_vote.rb
        </p>
<p>[ruby]</p>
<p>  validates_uniqueness_of :haiku_id, scope: :user_id<br />
validates_inclusion_of :value, in: [1, -1]<br />
validate :ensure_not_author</p>
<p>def ensure_not_author<br />
  errors.add :user_id, &quot;is the author of the haiku&quot; if haiku.user_id == user_id<br />
end<br />
[/ruby]</p>
<p>
          models/haiku.rb
        </p>
<p>[ruby]</p>
<p>  def self.by_votes<br />
  select(&#8218;haikus.*, coalesce(value, 0) as votes&#8216;).<br />
  joins(&#8218;left join haiku_votes on haiku_id=haikus.id&#8216;).<br />
  order(&#8218;votes desc&#8216;)<br />
end</p>
<p>def votes<br />
  read_attribute(:votes) || haiku_votes.sum(:value)<br />
end<br />
[/ruby]</p>
<p>
          models/user.rb
        </p>
<p>[ruby]</p>
<p>  def total_votes<br />
  HaikuVote.joins(:haiku).where(haikus: {user_id: self.id}).sum(&#8218;value&#8216;)<br />
end</p>
<p>def can_vote_for?(haiku)<br />
  haiku_votes.build(value: 1, haiku: haiku).valid?<br />
end<br />
[/ruby]</p>
<p>
          haikus_controller.rb
        </p>
<p>[ruby]</p>
<p>  def index<br />
  @haikus = Haiku.by_votes<br />
end</p>
<p>def vote<br />
  vote = current_user.haiku_votes.new(value: params[:value], haiku_id: params[:id])<br />
  if vote.save<br />
    redirect_to :back, notice: &quot;Thank you for voting.&quot;<br />
  else<br />
    redirect_to :back, alert: &quot;Unable to vote, perhaps you already did.&quot;<br />
  end<br />
end<br />
[/ruby]</p>
<p>
          _haiku.html.erb
        </p>
<p>[html]</p>
<p>  | &lt;%= pluralize haiku.votes, &quot;vote&quot; %&gt;<br />
&lt;% if current_user &amp;&amp; current_user.can_vote_for?(haiku) %&gt;<br />
  | &lt;%= link_to &quot;up&quot;, vote_haiku_path(haiku, value: 1), method: &quot;post&quot; %&gt;<br />
  | &lt;%= link_to &quot;down&quot;, vote_haiku_path(haiku, value: -1), method: &quot;post&quot; %&gt;<br />
&lt;% end %&gt;<br />
[/html]</p>
<p>
          application.html.erb
        </p>
<p>[html]</p>
<p>  &lt;%= current_user.total_votes %&gt;<br />
[/html]</p>
]]></content>
		
		<link href="http://media.railscasts.com/assets/episodes/videos/364-active-record-reputation-system.mp4" rel="enclosure" length="25678960" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/364-active-record-reputation-system.m4v" rel="enclosure" length="12594627" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/364-active-record-reputation-system.webm" rel="enclosure" length="14987004" type="application/wordperfect" />
<link href="http://media.railscasts.com/assets/episodes/videos/364-active-record-reputation-system.ogv" rel="enclosure" length="28718246" type="video/ogg" />
			<link rel="replies" type="text/html" href="https://rubyonrails.de/2012/08/screencast-active-records-reputation-system/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://rubyonrails.de/2012/08/screencast-active-records-reputation-system/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>derkaan</name>
					</author>

		<title type="html"><![CDATA[Screencast: Datenexport nach Excel oder CSV]]></title>
		<link rel="alternate" type="text/html" href="https://rubyonrails.de/2012/07/screencast-datenexport-nach-excel-oder-csv/" />

		<id>http://www.rubyonrails.de/?p=3607</id>
		<updated>2012-07-05T06:17:51Z</updated>
		<published>2012-07-05T06:17:51Z</published>
		<category scheme="https://rubyonrails.de" term="Tutorials" /><category scheme="https://rubyonrails.de" term="CSV" /><category scheme="https://rubyonrails.de" term="Excel" /><category scheme="https://rubyonrails.de" term="Export" /><category scheme="https://rubyonrails.de" term="Screencast" /><category scheme="https://rubyonrails.de" term="Views" />
		<summary type="html"><![CDATA[Für Datenexporte wird häufig CSV und/oder Excel eingesetzt. In Rails ist es relativ einfach diese Formate zur Verfügung zu stellen. Wie dies funktioniert, welche Optionen zur Verfügung stehen und wie ein Excel-Export in verschiedenen Formaten aussehen kann, zeigt Ryan in diesem Screencast.
]]></summary>

					<content type="html" xml:base="https://rubyonrails.de/2012/07/screencast-datenexport-nach-excel-oder-csv/"><![CDATA[<div>&nbsp;</div>
<h4>Downloads in verschiedenen Formaten:</h4>
<p><a href="http://media.railscasts.com/assets/episodes/videos/362-exporting-csv-and-excel.mp4">mp4</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/362-exporting-csv-and-excel.m4v">m4v</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/362-exporting-csv-and-excel.webm">webm</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/362-exporting-csv-and-excel.ogv">ogg</a></p>
<div>&nbsp;</div>
<h4>Resourcen:</h4>
<ul>
<li><a href="http://ruby-doc.org/stdlib-1.9.3/libdoc/csv/rdoc/CSV.html">CSV</a></li>
</ul>
<p>config/application.rb</p>
<p>[ruby]<br />
require &#8218;csv&#8216;<br />
[/ruby]</p>
<p>products_controller.rb</p>
<p>[ruby]<br />
def index<br />
  @products = Product.order(:name)<br />
  respond_to do |format|<br />
    format.html<br />
    format.csv { send_data @products.to_csv }<br />
    format.xls # { send_data @products.to_csv(col_sep: &quot;t&quot;) }<br />
  end<br />
end<br />
[/ruby]</p>
<p>models/product.rb</p>
<p>[ruby]<br />
def self.to_csv(options = {})<br />
  CSV.generate(options) do |csv|<br />
    csv &lt;&lt; column_names<br />
    all.each do |product|<br />
      csv &lt;&lt; product.attributes.values_at(*column_names)<br />
    end<br />
  end<br />
end<br />
[/ruby]</p>
<p>config/initializers/mime_types.rb</p>
<p>[ruby]<br />
Mime::Type.register &quot;application/xls&quot;, :xls<br />
[/ruby]</p>
<p>views/products/index.xls.erb</p>
<p>[html]<br />
&lt;?xml version=&quot;1.0&quot;?&gt;<br />
&lt;Workbook xmlns=&quot;urn:schemas-microsoft-com:office:spreadsheet&quot;<br />
  xmlns:o=&quot;urn:schemas-microsoft-com:office:office&quot;<br />
  xmlns:x=&quot;urn:schemas-microsoft-com:office:excel&quot;<br />
  xmlns:ss=&quot;urn:schemas-microsoft-com:office:spreadsheet&quot;<br />
  xmlns:html=&quot;http://www.w3.org/TR/REC-html40&quot;&gt;<br />
  &lt;Worksheet ss:Name=&quot;Sheet1&quot;&gt;<br />
    &lt;Table&gt;<br />
      &lt;Row&gt;<br />
        &lt;Cell&gt;&lt;Data ss:Type=&quot;String&quot;&gt;ID&lt;/Data&gt;&lt;/Cell&gt;<br />
        &lt;Cell&gt;&lt;Data ss:Type=&quot;String&quot;&gt;Name&lt;/Data&gt;&lt;/Cell&gt;<br />
        &lt;Cell&gt;&lt;Data ss:Type=&quot;String&quot;&gt;Release Date&lt;/Data&gt;&lt;/Cell&gt;<br />
        &lt;Cell&gt;&lt;Data ss:Type=&quot;String&quot;&gt;Price&lt;/Data&gt;&lt;/Cell&gt;<br />
      &lt;/Row&gt;<br />
    &lt;% @products.each do |product| %&gt;<br />
      &lt;Row&gt;<br />
        &lt;Cell&gt;&lt;Data ss:Type=&quot;Number&quot;&gt;&lt;%= product.id %&gt;&lt;/Data&gt;&lt;/Cell&gt;<br />
        &lt;Cell&gt;&lt;Data ss:Type=&quot;String&quot;&gt;&lt;%= product.name %&gt;&lt;/Data&gt;&lt;/Cell&gt;<br />
        &lt;Cell&gt;&lt;Data ss:Type=&quot;String&quot;&gt;&lt;%= product.released_on %&gt;&lt;/Data&gt;&lt;/Cell&gt;<br />
        &lt;Cell&gt;&lt;Data ss:Type=&quot;Number&quot;&gt;&lt;%= product.price %&gt;&lt;/Data&gt;&lt;/Cell&gt;<br />
      &lt;/Row&gt;<br />
    &lt;% end %&gt;<br />
    &lt;/Table&gt;<br />
  &lt;/Worksheet&gt;<br />
&lt;/Workbook&gt;<br />
[/html]</p>
]]></content>
		
		<link href="http://media.railscasts.com/assets/episodes/videos/362-exporting-csv-and-excel.mp4" rel="enclosure" length="22044872" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/362-exporting-csv-and-excel.m4v" rel="enclosure" length="9373305" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/362-exporting-csv-and-excel.webm" rel="enclosure" length="10115871" type="video/webm" />
<link href="http://media.railscasts.com/assets/episodes/videos/362-exporting-csv-and-excel.ogv" rel="enclosure" length="23181929" type="video/ogg" />
			<link rel="replies" type="text/html" href="https://rubyonrails.de/2012/07/screencast-datenexport-nach-excel-oder-csv/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://rubyonrails.de/2012/07/screencast-datenexport-nach-excel-oder-csv/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
		<entry>
		<author>
			<name>derkaan</name>
					</author>

		<title type="html"><![CDATA[Screencast: Authentifizierung über Facebook]]></title>
		<link rel="alternate" type="text/html" href="https://rubyonrails.de/2012/07/screencast-authentifizierung-uber-facebook/" />

		<id>http://www.rubyonrails.de/?p=3605</id>
		<updated>2012-07-05T06:13:26Z</updated>
		<published>2012-07-05T06:13:26Z</published>
		<category scheme="https://rubyonrails.de" term="Tutorials" /><category scheme="https://rubyonrails.de" term="Authentication" /><category scheme="https://rubyonrails.de" term="Facebook" /><category scheme="https://rubyonrails.de" term="Plugin" /><category scheme="https://rubyonrails.de" term="Screencast" />
		<summary type="html"><![CDATA[In diesem Screencast zeigt Ryan wie eine neue Facebook erstellt und konfiguriert werden kann. Zusätzlich zeigt er wie das omniauth-facebook gem eingesetzt wird.
]]></summary>

					<content type="html" xml:base="https://rubyonrails.de/2012/07/screencast-authentifizierung-uber-facebook/"><![CDATA[<div>&nbsp;</div>
<h4>Downloads in verschiedenen Formaten:</h4>
<p><a href="http://media.railscasts.com/assets/episodes/videos/360-facebook-authentication.mp4">mp4</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/360-facebook-authentication.m4v">m4v</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/360-facebook-authentication.webm">webm</a><br />
<a href="http://media.railscasts.com/assets/episodes/videos/360-facebook-authentication.ogv">ogg</a></p>
<div>&nbsp;</div>
<h4>Resourcen:</h4>
<ul>
<li><a href="https://developers.facebook.com/">Facebook Developers</a></li>
<li><a href="https://developers.facebook.com/docs/plugins/">Facebook Social Plugins</a></li>
<li><a href="https://github.com/mkdynamic/omniauth-facebook">omniauth-facebook</a></li>
<li><a href="https://developers.facebook.com/docs/authentication/client-side/">Facebook Client-Side Authentication</a></li>
<li><a href="https://github.com/arsduo/koala/">Koala</a></li>
</ul>
<p>Gemfile</p>
<p>[ruby]<br />
gem &#8218;omniauth-facebook&#8216;<br />
[/ruby]</p>
<p>config/initializers/omniauth.rb</p>
<p>[ruby]<br />
OmniAuth.config.logger = Rails.logger</p>
<p>Rails.application.config.middleware.use OmniAuth::Builder do<br />
  provider :facebook, ENV[&#8218;FACEBOOK_APP_ID&#8216;], ENV[&#8218;FACEBOOK_SECRET&#8216;]<br />
end<br />
[/ruby]</p>
<p>terminal</p>
<p>[bash]<br />
rails g model user provider uid name oauth_token oauth_expires_at:datetime<br />
rake db:migrate<br />
[/bash]</p>
<p>models/user.rb</p>
<p>[ruby]<br />
def self.from_omniauth(auth)<br />
  where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|<br />
    user.provider = auth.provider<br />
    user.uid = auth.uid<br />
    user.name = auth.info.name<br />
    user.oauth_token = auth.credentials.token<br />
    user.oauth_expires_at = Time.at(auth.credentials.expires_at)<br />
    user.save!<br />
  end<br />
end<br />
[/ruby]</p>
<p>config/routes.rb</p>
<p>[ruby]<br />
match &#8218;auth/:provider/callback&#8216;, to: &#8217;sessions#create&#8216;<br />
match &#8218;auth/failure&#8216;, to: redirect(&#8218;/&#8216;)<br />
match &#8217;signout&#8216;, to: &#8217;sessions#destroy&#8216;, as: &#8217;signout&#8216;<br />
[/ruby]</p>
<p>sessions_controller.rb</p>
<p>[ruby]<br />
class SessionsController &lt; ApplicationController<br />
  def create<br />
    user = User.from_omniauth(env[&quot;omniauth.auth&quot;])<br />
    session[:user_id] = user.id<br />
    redirect_to root_url<br />
  end</p>
<p>  def destroy<br />
    session[:user_id] = nil<br />
    redirect_to root_url<br />
  end<br />
end<br />
[/ruby]</p>
<p>application_controller.rb</p>
<p>[ruby]<br />
private</p>
<p>def current_user<br />
  @current_user ||= User.find(session[:user_id]) if session[:user_id]<br />
end<br />
helper_method :current_user<br />
[/ruby]</p>
<p>layouts/application.html.erb</p>
<p>[html]<br />
&lt;div id=&quot;user_nav&quot;&gt;<br />
  &lt;% if current_user %&gt;<br />
    Signed in as &lt;strong&gt;&lt;%= current_user.name %&gt;&lt;/strong&gt;!<br />
    &lt;%= link_to &quot;Sign out&quot;, signout_path, id: &quot;sign_out&quot; %&gt;<br />
  &lt;% else %&gt;<br />
    &lt;%= link_to &quot;Sign in with Facebook&quot;, &quot;/auth/facebook&quot;, id: &quot;sign_in&quot; %&gt;<br />
  &lt;% end %&gt;<br />
&lt;/div&gt;<br />
[/html]</p>
<p>app/assets/javascripts/facebook.js.coffee.erb</p>
<p>[javascript]</p>
<p>jQuery -&gt;<br />
  $(&#8218;body&#8216;).prepend(&#8218;&lt;div id=&quot;fb-root&quot;&gt;&lt;/div&gt;&#8216;)</p>
<p>  $.ajax<br />
    url: &quot;#{window.location.protocol}//connect.facebook.net/en_US/all.js&quot;<br />
    dataType: &#8217;script&#8216;<br />
    cache: true</p>
<p>window.fbAsyncInit = -&gt;<br />
  FB.init(appId: &#8218;&lt;%= ENV[&quot;FACEBOOK_APP_ID&quot;] %&gt;&#8216;, cookie: true)</p>
<p>  $(&#8218;#sign_in&#8216;).click (e) -&gt;<br />
    e.preventDefault()<br />
    FB.login (response) -&gt;<br />
      window.location = &#8218;/auth/facebook/callback&#8216; if response.authResponse</p>
<p>  $(&#8218;#sign_out&#8216;).click (e) -&gt;<br />
    FB.getLoginStatus (response) -&gt;<br />
      FB.logout() if response.authResponse<br />
    true<br />
[/javascript]</p>
]]></content>
		
		<link href="http://media.railscasts.com/assets/episodes/videos/360-facebook-authentication.mp4" rel="enclosure" length="31286861" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/360-facebook-authentication.m4v" rel="enclosure" length="16681130" type="video/mp4" />
<link href="http://media.railscasts.com/assets/episodes/videos/360-facebook-authentication.webm" rel="enclosure" length="18473909" type="video/webm" />
<link href="http://media.railscasts.com/assets/episodes/videos/360-facebook-authentication.ogv" rel="enclosure" length="41993424" type="video/ogg" />
			<link rel="replies" type="text/html" href="https://rubyonrails.de/2012/07/screencast-authentifizierung-uber-facebook/#comments" thr:count="0" />
			<link rel="replies" type="application/atom+xml" href="https://rubyonrails.de/2012/07/screencast-authentifizierung-uber-facebook/feed/atom/" thr:count="0" />
			<thr:total>0</thr:total>
			</entry>
	</feed>
