Ricerca…


introduzione

ActiveRecord è la M in MVC, che è il livello del sistema responsabile della rappresentazione dei dati e della logica aziendale. La tecnica che collega gli oggetti ricchi di un'applicazione alle tabelle in un sistema di gestione di database relazionali è O bject R elational M apper ( ORM ).

ActiveRecord eseguirà query sul database per te ed è compatibile con la maggior parte dei sistemi di database. Indipendentemente dal sistema di database che stai utilizzando, il formato del metodo ActiveRecord sarà sempre lo stesso.

.dove

Il metodo where è disponibile su qualsiasi modello ActiveRecord e consente di eseguire query sul database per un set di record che soddisfano i criteri specificati.

Il metodo where accetta un hash in cui le chiavi corrispondono ai nomi delle colonne sulla tabella rappresentata dal modello.

Come semplice esempio, utilizzeremo il seguente modello:

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

Per trovare tutte le persone con il nome di Sven :

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

Per trovare tutte le persone con il nome di Sven e il cognome di Schrodinger :

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

Nell'esempio sopra, l'output sql mostra che i record verranno restituiti solo se sia il first_name che il last_name coincidono.

interrogare con la condizione OR

Per trovare i record con first_name == 'Bruce' OR last_name == 'Wayne'

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

.where con un array

Il metodo where su qualsiasi modello di ActiveRecord può essere utilizzato per generare SQL del modulo WHERE column_name IN (a, b, c, ...) . Questo risultato è ottenuto passando un array come argomento.

Come semplice esempio, utilizzeremo il seguente modello:

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')"

Se la matrice contiene un valore nil , lo SQL verrà modificato per verificare se la colonna è 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"

Scopes

Gli ambiti agiscono come filtri predefiniti sui modelli ActiveRecord .

Un ambito viene definito utilizzando il metodo della classe scope .

Come semplice esempio, utilizzeremo il seguente modello:

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

Gli ambiti possono essere chiamati direttamente dalla classe del modello:

minors = Person.minors

Gli ambiti possono essere concatenati:

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

Il metodo where e altri metodi di tipo query possono anche essere concatenati:

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

Dietro le quinte, gli ambiti sono semplicemente zucchero sintattico per un metodo di classe standard. Ad esempio, questi metodi sono funzionalmente identici:

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

# This ^ is the same as this:

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

Ambito di validità

nel modello per impostare un ambito predefinito per tutte le operazioni sul modello.

C'è una differenza notevole tra il metodo scope e un metodo di classe: gli scope definiti da scope restituiranno sempre un ActiveRecord::Relation , anche se la logica all'interno restituisce nil. I metodi di classe, tuttavia, non hanno una simile rete di sicurezza e possono interrompere la chainability se restituiscono qualcos'altro.

where.not

where clausole possono essere negate usando la sintassi where.not :

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')

Supportato da ActiveRecord 4.0 e versioni successive.

ordinazione

È possibile ordinare i risultati delle query di ActiveRecord utilizzando .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">]

Se non specificato, l'ordine verrà eseguito in ordine crescente. Puoi specificarlo facendo:

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 accetta anche una stringa, quindi puoi anche fare

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">]

Poiché la stringa è SQL raw, puoi anche specificare una tabella e non solo un attributo. Supponendo che tu voglia ordinare gli users base al loro nome di role , puoi farlo:

Class User < ActiveRecord::Base
    belongs_to :role
end

Class Role < ActiveRecord::Base
  has_many :users
end

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

L'ambito order può accettare anche un nodo Arel:

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

ActiveRecord Bang (!) Metodi

Se è necessario un metodo ActiveRecord per generare un'eccezione anziché un valore false in caso di errore, è possibile aggiungere ! a loro. Questo è molto importante. Dato che alcune eccezioni / fallimenti sono difficili da catturare se non le usi! su di essi. Ho raccomandato di farlo nel tuo ciclo di sviluppo per scrivere tutto il tuo codice ActiveRecord in questo modo per farti risparmiare tempo e fatica.

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

I metodi ActiveRecord che accettano un botto ( ! ) Sono:

  • .create!
  • .take!
  • .first!
  • .last!
  • .find_by!
  • .find_or_create_by!
  • #save!
  • #update!
  • tutti i cercatori dinamici AR

.find_by

Puoi trovare i record di qualsiasi campo nella tua tabella usando find_by .

Quindi, se hai un modello User con un first_name puoi fare:

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

find_by che find_by non genera eccezioni per impostazione predefinita. Se il risultato è un set vuoto, restituisce nil invece di find .

Se è necessaria l'eccezione, puoi utilizzare find_by! che solleva un errore ActiveRecord::RecordNotFound come find .

.cancella tutto

Se è necessario eliminare rapidamente molti record, ActiveRecord fornisce il metodo .delete_all . per essere chiamato direttamente su un modello, per cancellare tutti i record in quella tabella o una raccolta. Attenzione però, dato che .delete_all non istanzia nessun oggetto, quindi non fornisce alcuna callback ( before_* e after_destroy non vengono attivati).

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

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

ActiveRecord ricerca tra maiuscole e minuscole

Se è necessario cercare un modello di ActiveRecord per valori simili, si potrebbe essere tentati di utilizzare LIKE o ILIKE ma questo non è portabile tra i motori di database. Allo stesso modo, il ricorso a downcasing o upcasing sempre in grado di creare problemi di prestazioni.

È possibile utilizzare il metodo di matches Arel sottostante di ActiveRecord per farlo in modo sicuro:

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

Arel applicherà il costrutto LIKE o ILIKE appropriato per il motore di database configurato.

Ricevi il primo e l'ultimo record

Le rotaie hanno un modo molto semplice per ottenere il first e l' last record dal database.

Per ottenere il first record dalla tabella degli users , dobbiamo digitare il seguente comando:

User.first

sql seguente query sql :

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

E restituirà il seguente record:

#<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 >

Per ottenere l' last record dalla tabella degli users , dobbiamo digitare il seguente comando:

User.last

sql seguente query sql :

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

E restituirà il seguente record:

#<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 >

Il passaggio di un intero al primo e all'ultimo metodo crea una query LIMIT e restituisce una matrice di oggetti.

User.first(5)

sql seguente query sql .

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

E

User.last(5)

sql seguente query sql .

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

.group e .count

Abbiamo un modello di Product e vogliamo raggrupparli per category .

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

Questo interrogherà il database come segue:

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

Assicurati che anche il campo raggruppato sia selezionato. Il raggruppamento è particolarmente utile per il conteggio dell'occorrenza - in questo caso - delle categories .

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

Come mostra la query, userà il database per il conteggio, che è molto più efficiente, rispetto al recupero di tutti i record e al conteggio nel codice:

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

.distinct (o .uniq)

Se vuoi rimuovere i duplicati da un risultato, puoi usare .distinct() :

Customers.select(:country).distinct

Questa query il database come segue:

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

.uniq() ha lo stesso effetto. Con Rails 5.0 è stato deprecato e verrà rimosso da Rails con la versione 5.1. Il motivo è che la parola unique non ha lo stesso significato di distinta e può essere fuorviante. Inoltre distinct è più vicino alla sintassi SQL.

Si unisce

joins() ti permette di unire le tabelle al tuo modello attuale. Per es.

User.joins(:posts)

produrrà la seguente query SQL:

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

Avendo unito la tabella, avrai accesso ad essa:

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

Fai attenzione alla forma plurale. Se la tua relazione è :has_many , allora l'argomento :has_many joins() dovrebbe essere pluralizzato. Altrimenti, usa il singolare.

Nidificati joins :

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

che produrrà:

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

include

ActiveRecord with includes assicura che tutte le associazioni specificate vengano caricate utilizzando il numero minimo possibile di query. Pertanto, quando si esegue una query su una tabella per i dati con una tabella associata, entrambe le tabelle vengono caricate in memoria.

@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 } ) caricherà solo gli autori con condizioni in memoria senza caricare libri . Utilizza i joins quando non sono richieste informazioni aggiuntive sulle associazioni nidificate.

@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

Limite e offset

È possibile utilizzare il limit per indicare il numero di record da recuperare e utilizzare l' offset per indicare il numero di record da saltare prima di iniziare a restituire i record.

Per esempio

User.limit(3) #returns first three records

Genererà la seguente query sql.

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

Poiché l'offset non è menzionato nella query precedente, restituirà i primi tre record.

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

Genererà la seguente query sql.

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


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow