Denken in Ruby

8

Ich bin gerade damit beschäftigt, Ruby and Rails zu lernen, und da ich einen Hintergrund in C-basierten Sprachen habe, sind einige Konzepte von Ruby neu und etwas fremdartig. Besonders herausfordernd für mich ist die Anpassung an den "Ruby-Way" der Annäherung an allgemeine Probleme, daher finde ich oft, dass ich C in Ruby codiere, was ich nicht erreichen will.

Stellen Sie sich vor, Sie hätten ein Schema wie folgt:

%Vor%

Die Datenbank enthält bereits mehrere verschiedene Fahrräder. Mein Ziel ist es, eine Reihe aller Marken in der Datenbank darzustellen.

Hier ist mein Code:

%Vor%

Wie würde ein Ruby-Guru Code schreiben, um dies zu erreichen?

    
KernelPanic 23.10.2012, 16:48
quelle

1 Antwort

26

tl; dr: Ihre gesamte Methode kann durch Bike.uniq.pluck(:brand) ersetzt werden.

Diese Funktionalität ist bereits vorhanden (siehe das Ende meiner Antwort), aber zuerst sollten wir Ihren Code durchgehen und ihn idiomatischer machen:

Verwenden Sie in erster Linie zwei Leerzeichen pro Ebene der Einrückung, nicht vier, nicht acht und nicht . Verwenden Sie zwei Leerzeichen . Dies sind keine persönlichen Vorlieben, dies ist eine extrem starke Konvention innerhalb der Ruby-Community und wird sehr oft benötigt, wenn Sie teilnehmen möchten.

Als nächstes gibt es fast nie einen guten Grund, dieses Muster in Ruby zu verwenden:

%Vor%

Wenn Sie ein Array in ein anderes Array (wirklich, ein Enumerable in ein anderes Enumerable) umwandeln wollen, indem Sie einen Code auf jeden der Werte im Input-Array anwenden, verwenden Sie map oder collect (welche Synonyme sind):

%Vor%

Als nächstes können Sie symbol#to_proc nutzen, um den obigen Code ein wenig zu verbessern klarer:

%Vor%

Dies wird für Uneingeweihte seltsam aussehen, aber ist klarer, wenn Sie einmal mit map und &:field gearbeitet haben. Ein bisschen Erfahrung macht die Absicht dieser Codezeile sehr offensichtlich: Es wird die Methode brand auf jedes Element im Array angewendet, und es entspricht genau der vorherigen { |item| item.brand } Version.

Nun kann Ihre gesamte Methode zu einem ziemlich einfachen Einzeiler werden:

%Vor%

Das inline select / distinct SQL ist etwas hässlich, besonders da ActiveRecord uns schon bestimmte Felder mit select , und machen Sie die Ergebnisse unter Verwendung von uniq :

%Vor%

Als letzte Iteration können wir pluck anstelle von map verwenden, um nur die Felder herauszuziehen von den Ergebnissen, an denen wir interessiert sind. Aber weil pluck tatsächlich die erzeugte SQL so ändert, dass nur die zu pflückenden Felder enthalten sind, können wir den select(:brand) -Teil weglassen, und unser Code läuft auf eine unglaublich kurze einzelne Zeile hinaus enthält zwei verkettete Methoden:

%Vor%

Beachten Sie, dass die Reihenfolge wichtig ist, da pluck immer ein Array und keine ActiveRecord-Beziehung zurückgibt, die für eine zusätzliche Methodenverkettung bereit ist. Bike.pluck(:brand).uniq würde die Marke aus jedem Datensatz auswählen ( select brand from bikes ) und dann, in Ruby , das Array auf die eindeutigen Elemente reduzieren. Möglicherweise eine sehr teure Operation.

Und das ist es, Bike.uniq.pluck(:brand) . Als C-Programmierer werden Sie feststellen, dass viele sich wiederholende Aufgaben, die Sie normalerweise mit kleinen Schleifen ausführen, bereits von der Sprache selbst oder durch die Unterstützung von Bibliotheken für Sie gelöst werden. Die Menge an Code, den Sie nicht schreiben, kann sehr überraschend sein, sobald Sie gelernt haben, idiomatischen Ruby- und Rails-Code zu schreiben.

    
meagar 23.10.2012, 16:49
quelle