Suche…


Einführung

ActiveRecord ist das M in MVC, dh die Schicht des Systems, die für die Darstellung von Geschäftsdaten und -logik zuständig ist. Die Technik , die die reichen Objekte einer Anwendung Tabellen in einer relationalen Datenbank - Management - System verbindet , ist O bject R elational M apper (ORM).

ActiveRecord führt für Sie Abfragen in der Datenbank durch und ist mit den meisten Datenbanksystemen kompatibel. Unabhängig davon, welches Datenbanksystem Sie verwenden, das Format der ActiveRecord-Methode ist immer dasselbe.

.woher

Die where Methode ist für jedes ActiveRecord Modell verfügbar und ermöglicht das Abfragen der Datenbank nach einem Datensatz, der den angegebenen Kriterien entspricht.

Die where Methode akzeptiert einen Hash, bei dem die Schlüssel den Spaltennamen in der Tabelle entsprechen, die das Modell darstellt.

Als einfaches Beispiel verwenden wir folgendes Modell:

class Person < ActiveRecord::Base
  #attribute :first_name, :string
  #attribute :last_name, :string
end

Um alle Personen mit dem Vornamen von Sven :

people = Person.where(first_name: 'Sven')
people.to_sql # "SELECT * FROM people WHERE first_name='Sven'"

Um alle Personen mit dem Vornamen von Sven und dem Nachnamen von Schrodinger :

people = Person.where(first_name: 'Sven', last_name: 'Schrodinger')
people.to_sql # "SELECT * FROM people WHERE first_name='Sven' AND last_name='Schrodinger'"

Im obigen Beispiel zeigt die SQL-Ausgabe, dass Datensätze nur zurückgegeben werden, wenn sowohl der first_name als auch der last_name übereinstimmen.

Abfrage mit ODER-Bedingung

So suchen Sie Datensätze mit first_name == 'Bruce' ODER last_name == 'Wayne'

User.where('first_name = ? or last_name = ?', 'Bruce', 'Wayne')
# SELECT "users".* FROM "users" WHERE (first_name = 'Bruce' or last_name = 'Wayne')

.wo mit einem Array

Die where Methode für ein beliebiges ActiveRecord-Modell kann verwendet werden, um SQL der Form WHERE column_name IN (a, b, c, ...) zu generieren. Dies wird erreicht, indem ein Array als Argument übergeben wird.

Als einfaches Beispiel verwenden wir folgendes Modell:

class Person < ActiveRecord::Base
  #attribute :first_name, :string
  #attribute :last_name, :string
end

people = Person.where(first_name: ['Mark', 'Mary'])
people.to_sql # "SELECT * FROM people WHERE first_name IN ('Mark', 'Mary')"

Wenn das Array eine nil enthält, wird das SQL geändert, um zu überprüfen, ob die Spalte null :

people = Person.where(first_name: ['Mark', 'Mary', nil])
people.to_sql # "SELECT * FROM people WHERE first_name IN ('Mark', 'Mary') OR first_name IS NULL"

Bereiche

Bereiche dienen als vordefinierte Filter für ActiveRecord Modelle.

Ein Gültigkeitsbereich wird mithilfe der scope definiert.

Als einfaches Beispiel verwenden wir folgendes Modell:

class Person < ActiveRecord::Base
  #attribute :first_name, :string
  #attribute :last_name, :string
  #attribute :age, :integer

  # define a scope to get all people under 17
  scope :minors, -> { where(age: 0..17) }

  # define a scope to search a person by last name
  scope :with_last_name, ->(name) { where(last_name: name) }

end

Bereiche können direkt aus der Modellklasse abgerufen werden:

minors = Person.minors

Bereiche können verkettet werden:

peters_children = Person.minors.with_last_name('Peters')

Die where Methode und andere Abfragetypmethoden können auch verkettet werden:

mary_smith = Person.with_last_name('Smith').where(first_name: 'Mary')

Hinter den Kulissen sind Geltungsbereiche einfach syntaktischer Zucker für eine Standardklassenmethode. Zum Beispiel sind diese Methoden funktional identisch:

scope :with_last_name, ->(name) { where(name: name) }

# This ^ is the same as this:

def self.with_last_name(name)
  where(name: name)
end

Standardumfang

in Ihrem Modell, um einen Standardbereich für alle Vorgänge am Modell festzulegen.

Es gibt einen bemerkenswerten Unterschied zwischen der scope und einer Klassenmethode: scope -definierte scope geben immer ActiveRecord ActiveRecord::Relation , selbst wenn die Logik in nil zurückgibt. Klassenmethoden haben jedoch kein solches Sicherheitsnetz und können die Kettenfähigkeit brechen, wenn sie etwas anderes zurückgeben.

wo nicht

where Klauseln können mit der where.not Syntax negiert werden:

class Person < ApplicationRecord
  #attribute :first_name, :string
end

people = Person.where.not(first_name: ['Mark', 'Mary'])
# => SELECT "people".* FROM "people" WHERE "people"."first_name" NOT IN ('Mark', 'Mary')

Unterstützt von ActiveRecord 4.0 und höher.

Bestellung

Sie können mit Activeabfrageergebnisse bestellen .order :

User.order(:created_at)
#=> => [#<User id: 2, created_at: "2015-08-12 21:36:23">, #<User id: 11, created_at: "2015-08-15 10:21:48">]

Wenn nicht angegeben, erfolgt die Bestellung in aufsteigender Reihenfolge. Sie können es angeben, indem Sie Folgendes tun:

User.order(created_at: :asc)
#=> => [#<User id: 2, created_at: "2015-08-12 21:36:23">, #<User id: 11, created_at: "2015-08-15 10:21:48">]

User.order(created_at: :desc)
#=> [#<User id: 7585, created_at: "2016-07-13 17:15:27">, #<User id: 7583, created_at: "2016-07-13 16:51:18">]

.order akzeptiert auch eine Zeichenfolge, also können Sie dies auch tun

User.order("created_at DESC")
#=> [#<User id: 7585, created_at: "2016-07-13 17:15:27">, #<User id: 7583, created_at: "2016-07-13 16:51:18">]

Da es sich bei der Zeichenfolge um Raw-SQL handelt, können Sie auch eine Tabelle und nicht nur ein Attribut angeben. Angenommen , Sie bestellen möchten users entsprechend ihrer role Namen, können Sie dies tun:

Class User < ActiveRecord::Base
    belongs_to :role
end

Class Role < ActiveRecord::Base
  has_many :users
end

User.includes(:role).order("roles.name ASC")

Der order kann auch einen Arel-Knoten akzeptieren:

User.includes(:role).order(User.arel_table[:name].asc)

ActiveRecord Bang (!) -Methoden

Wenn Sie eine ActiveRecord- Methode benötigen, um im Fehlerfall eine Ausnahme anstelle eines false Werts auszulösen, können Sie hinzufügen ! zu ihnen. Dies ist sehr wichtig. Da einige Ausnahmen / Ausfälle schwer zu fassen sind, wenn Sie sie nicht verwenden! auf sie. Ich habe empfohlen, dies in Ihrem Entwicklungszyklus zu tun, um Ihren gesamten ActiveRecord-Code auf diese Weise zu schreiben, um Zeit und Ärger zu sparen.

Class User < ActiveRecord::Base
  validates :last_name, presence: true
end

User.create!(first_name: "John")
#=> ActiveRecord::RecordInvalid: Validation failed: Last name can't be blank

Die ActiveRecord- Methoden, die einen Knall ( ! ) Akzeptieren, sind:

  • .create!
  • .take!
  • .first!
  • .last!
  • .find_by!
  • .find_or_create_by!
  • #save!
  • #update!
  • alle AR dynamischen Sucher

.find_by

Mit find_by können Sie Datensätze nach beliebigen Feldern in Ihrer Tabelle find_by .

Wenn Sie ein User mit einem first_name Attribut haben, können Sie first_name tun:

User.find_by(first_name: "John")
#=> #<User id: 2005, first_name: "John", last_name: "Smith">

find_by dass find_by standardmäßig keine Ausnahme find_by . Wenn das Ergebnis ein leerer Satz ist, wird nil anstelle von find .

Wenn die Ausnahme benötigt wird, kann find_by! das verursacht einen ActiveRecord::RecordNotFound Fehler wie find .

.alles löschen

Wenn Sie eine Menge von Datensätzen schnell löschen müssen, gibt Active .delete_all Methode. um direkt in einem Modell aufgerufen zu werden, um alle Datensätze in dieser Tabelle oder eine Auflistung zu löschen. .delete_all Sie jedoch, da .delete_all kein Objekt instanziiert und daher keinen Rückruf before_* ( before_* und after_destroy nicht ausgelöst).

User.delete_all
#=> 39  <-- .delete_all return the number of rows deleted

User.where(name: "John").delete_all 

Bei ActiveRecord wird die Groß- / Kleinschreibung nicht berücksichtigt

Wenn Sie ein ActiveRecord-Modell nach ähnlichen Werten suchen müssen, werden Sie möglicherweise versucht, LIKE oder ILIKE , dies ist jedoch zwischen Datenbank-Engines nicht übertragbar. In ähnlicher Weise kann der Rückgriff auf immer Downcasing oder Upcasing zu Performance-Problemen führen.

Sie können die zugrunde liegende Arel- matches Methode von ActiveRecord verwenden, um dies auf eine sichere Weise durchzuführen:

addresses = Address.arel_table
Address.where(addresses[:address].matches("%street%"))

Arel wendet das entsprechende LIKE- oder ILIKE-Konstrukt für das konfigurierte Datenbankmodul an.

Holen Sie sich den ersten und letzten Datensatz

Rails haben eine sehr einfache Möglichkeit, den first und last Datensatz aus der Datenbank abzurufen.

Um den first Datensatz aus der users , müssen Sie den folgenden Befehl eingeben:

User.first

Es wird folgende sql Abfrage generiert:

SELECT  `users`.* FROM `users`  ORDER BY `users`.`id` ASC LIMIT 1

Und wird folgende Aufzeichnung zurückgeben:

#<User:0x007f8a6db09920 id: 1, first_name: foo, created_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00, updated_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00 >

Um den last Datensatz aus der users , müssen Sie den folgenden Befehl eingeben:

User.last

Es wird folgende sql Abfrage generiert:

SELECT  `users`.* FROM `users`  ORDER BY `users`.`id` DESC LIMIT 1

Und wird folgende Aufzeichnung zurückgeben:

#<User:0x007f8a6db09920 id: 10, first_name: bar, created_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00, updated_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00 >

Durch Übergeben einer Ganzzahl an die erste und letzte Methode wird eine LIMIT- Abfrage erstellt und ein Array von Objekten zurückgegeben.

User.first(5)

Es wird folgende sql Abfrage generiert.

SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 5

Und

User.last(5)

Es wird folgende sql Abfrage generiert.

SELECT  "users".* FROM "users"  ORDER BY "users"."id" DESC LIMIT 5

.group und .count

Wir haben ein Product und möchten sie nach ihrer category gruppieren.

Product.select(:category).group(:category)

Dadurch wird die Datenbank wie folgt abgefragt:

SELECT "product"."category" FROM "product" GROUP BY "product"."category"

Stellen Sie sicher, dass das gruppierte Feld ebenfalls ausgewählt ist. Die Gruppierung eignet sich besonders zum Zählen des Vorkommens - in diesem Fall - von categories .

Product.select(:category).group(:category).count

Wie die Abfrage zeigt, wird die Datenbank zum Zählen verwendet, was wesentlich effizienter ist, als zuerst alle Datensätze abzurufen und im Code zu zählen:

SELECT COUNT("products"."category") AS count_categories, "products"."category" AS products_category FROM "products" GROUP BY "products"."category"

.distinct (oder .uniq)

Wenn Sie Duplikate aus einem Ergebnis entfernen möchten, können Sie .distinct() :

Customers.select(:country).distinct

Dadurch wird die Datenbank wie folgt abgefragt:

SELECT DISTINCT "customers"."country" FROM "customers"

.uniq() hat den gleichen Effekt. Mit Rails 5.0 wurde es veraltet und mit Version 5.1 von Rails entfernt. Der Grund ist, dass das Wort " unique nicht die gleiche Bedeutung wie "different" hat und es kann irreführend sein. Weiterhin distinct ist näher an der SQL - Syntax.

Schließt sich an

joins() können Sie Tabellen mit Ihrem aktuellen Modell verknüpfen. Für ex.

User.joins(:posts)

erzeugt die folgende SQL-Abfrage:

"SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id""

Nachdem Sie den Tisch verbunden haben, können Sie darauf zugreifen:

User.joins(:posts).where(posts: { title: "Hello world" })

Achten Sie auf die Pluralform. Wenn Ihre Beziehung :has_many , sollte das Argument joins() pluralisiert werden. Ansonsten verwenden Sie Singular.

Verschachtelte joins :

User.joins(posts: :images).where(images: { caption: 'First post' })

was wird produzieren:

"SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" INNER JOIN "images" ON "images"."post_id" = "images"."id""

Enthält

ActiveRecord with includes stellt sicher, dass alle angegebenen Zuordnungen mit der minimal möglichen Anzahl von Abfragen geladen werden. Wenn Sie also eine Tabelle nach Daten mit einer zugeordneten Tabelle abfragen, werden beide Tabellen in den Speicher geladen.

@authors = Author.includes(:books).where(books: { bestseller: true } )

# this will print  results without additional db hitting
@authors.each do |author| 
  author.books.each do |book|
    puts book.title
  end
end

Author.joins(:books).where(books: { bestseller: true } ) lädt nur Autoren mit Bedingungen in den Speicher, ohne Bücher zu laden . Verwenden Sie joins wenn keine zusätzlichen Informationen zu verschachtelten Zuordnungen erforderlich sind.

@authors = Author.joins(:books).where(books: { bestseller: true } )

# this will print results without additional queries
@authors.each { |author| puts author.name }

# this will print results with additional db queries
@authors.each do |author| 
  author.books.each do |book|
    puts book.title
  end
end

Limit und Offset

Sie können mit limit die Anzahl der abzurufenden Datensätze angeben und mit offset die Anzahl der zu überspringenden Datensätze angeben, bevor Sie die Datensätze zurückgeben.

Zum Beispiel

User.limit(3) #returns first three records

Es wird folgende SQL-Abfrage generiert.

"SELECT  `users`.* FROM `users` LIMIT 3"

Da der Offset in der obigen Abfrage nicht erwähnt wird, werden die ersten drei Datensätze zurückgegeben.

User.limit(5).offset(30) #returns 5 records starting from 31th i.e from 31 to 35

Es wird folgende SQL-Abfrage generiert.

"SELECT  `users`.* FROM `users` LIMIT 5 OFFSET 30"


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow