Zoeken…


Invoering

ActiveRecord is de M in MVC, de laag van het systeem die verantwoordelijk is voor het weergeven van bedrijfsgegevens en logica. De techniek die de rijke objecten van een toepassing verbindt met tabellen in een relationeel databasebeheersysteem is O bject R elational M apper ( ORM ).

ActiveRecord voert voor u zoekopdrachten uit in de database en is compatibel met de meeste databasesystemen. Ongeacht het databasesysteem dat u gebruikt, de indeling van de ActiveRecord-methode is altijd hetzelfde.

.waar

De where methode is beschikbaar op een ActiveRecord model en maakt het mogelijk het opvragen van de database voor een set records die overeenkomen met de opgegeven criteria.

De where Werkwijze accepteert een hash waarbij de toetsen komen overeen met de kolom namen op de tafel dat het model vertegenwoordigt.

Als een eenvoudig voorbeeld gebruiken we het volgende model:

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

Om alle mensen met de voornaam Sven :

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

Om alle mensen met de voornaam Sven en achternaam van Schrodinger :

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

In het bovenstaande voorbeeld toont de sql-uitvoer dat records alleen worden geretourneerd als zowel de first_name als de last_name overeenkomen.

zoekopdracht met OF-voorwaarde

Records zoeken met first_name == 'Bruce' OF last_name == 'Wayne'

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

.waar met een array

De where Werkwijze Elk ActiveRecord model kan worden gebruikt om de vorm van SQL genereren WHERE column_name IN (a, b, c, ...) . Dit wordt bereikt door een array als argument door te geven.

Als een eenvoudig voorbeeld gebruiken we het volgende model:

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

Als de array een nil bevat, wordt de SQL gewijzigd om te controleren of de kolom 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

Scopes fungeren als vooraf gedefinieerde filters op ActiveRecord modellen.

Een scope wordt gedefinieerd met behulp van de scope class-methode.

Als een eenvoudig voorbeeld gebruiken we het volgende model:

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

Scopes kunnen direct uit de modelklasse worden opgeroepen:

minors = Person.minors

Scopes kunnen worden geketend:

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

De where Werkwijze en andere type query werkwijzen kunnen ook worden gekoppeld:

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

Achter de schermen zijn scopen gewoon syntactische suiker voor een standaardklasse methode. Deze methoden zijn bijvoorbeeld functioneel identiek:

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

# This ^ is the same as this:

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

Standaard bereik

in uw model om een standaardbereik in te stellen voor alle bewerkingen op het model.

Er is een opmerkelijk verschil tussen de scope methode en een class-methode: scope gedefinieerde scopes retourneren altijd een ActiveRecord::Relation , zelfs als de logica binnen nul teruggeeft. Klasse-methoden hebben echter niet zo'n vangnet en kunnen de kettingbaarheid verbreken als ze iets anders teruggeven.

waar niet

where clausules kunnen worden ontkend met behulp van de where.not syntaxis:

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

Ondersteund door ActiveRecord 4.0 en hoger.

Bestellen

U kunt ActiveRecord- queryresultaten bestellen met .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">]

Indien niet gespecificeerd, wordt de bestelling in oplopende volgorde uitgevoerd. U kunt het opgeven door het volgende te doen:

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 accepteert ook een string, dus dat kan ook

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

Omdat de tekenreeks onbewerkte SQL is, kunt u ook een tabel opgeven en niet alleen een kenmerk. Ervan uitgaande dat u wilt bestellen users op basis van hun role naam, kunt u dit doen:

Class User < ActiveRecord::Base
    belongs_to :role
end

Class Role < ActiveRecord::Base
  has_many :users
end

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

De order scope kan aanvaarden Arel knooppunt:

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

ActiveRecord Bang (!) -Methoden

Als u een ActiveRecord- methode nodig hebt om een uitzondering te genereren in plaats van een false waarde in geval van een storing, kunt u toevoegen ! naar hen. Dit is erg belangrijk. Omdat sommige uitzonderingen / storingen moeilijk te vangen zijn als u deze niet gebruikt! op hen. Ik raad aan dit in je ontwikkelingscyclus te doen om al je ActiveRecord-code op deze manier te schrijven om je tijd en moeite te besparen.

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

De ActiveRecord- methoden die een knal accepteren ( ! ) Zijn:

  • .create!
  • .take!
  • .first!
  • .last!
  • .find_by!
  • .find_or_create_by!
  • #save!
  • #update!
  • alle AR dynamische vinders

.find_by

U kunt records zoeken op elk veld in uw tabel met behulp van find_by .

Dus als u een User met het kenmerk first_name kunt u het volgende doen:

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

Let wel dat find_by standaard geen uitzondering find_by . Als het resultaat een lege set is, retourneert deze nil plaats van te find .

Als de uitzondering nodig is, kunt u find_by! dat een ActiveRecord::RecordNotFound fout veroorzaakt, zoals find .

.Verwijder alles

Als u veel platen snel wilt verwijderen, ActiveRecord geeft .delete_all methode. om rechtstreeks op een model te worden opgeroepen, om alle records in die tabel of een verzameling te verwijderen. Maar let op, aangezien .delete_all geen object instantieert en dus geen callback biedt ( before_* en after_destroy worden niet geactiveerd).

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

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

ActiveRecord hoofdletterongevoelig zoeken

Als u in een ActiveRecord-model naar vergelijkbare waarden moet zoeken, kunt u in de verleiding komen om LIKE of ILIKE maar dit is niet draagbaar tussen database-engines. Evenzo kan het gebruik van altijd downcasing of upcasing prestatieproblemen veroorzaken.

U kunt de onderliggende methode van Arel- matches ActiveRecord gebruiken om dit op een veilige manier te doen:

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

Arel past het juiste LIKE- of ILIKE-construct toe voor de geconfigureerde database-engine.

Ontvang eerste en laatste record

Rails hebben een zeer eenvoudige manier om het first en last record uit de database te krijgen.

Om het first record van de users te krijgen, moeten we het volgende commando typen:

User.first

Het zal de volgende sql query genereren:

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

En zal volgend record terugkeren:

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

Om het last record van de users te krijgen, moeten we het volgende commando typen:

User.last

Het zal de volgende sql query genereren:

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

En zal volgend record terugkeren:

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

Als u een geheel getal doorgeeft aan de eerste en laatste methode, wordt een LIMIT- query gemaakt en wordt een array met objecten geretourneerd.

User.first(5)

Het zal de volgende sql query genereren.

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

En

User.last(5)

Het zal de volgende sql query genereren.

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

.groep en .count

We hebben een Product en we willen ze groeperen op category .

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

Dit zal de database als volgt doorzoeken:

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

Zorg ervoor dat het gegroepeerde veld ook is geselecteerd. Groeperen is met name handig voor het tellen van het voorkomen - in dit geval - van categories .

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

Zoals de query laat zien, zal het de database gebruiken om te tellen, wat veel efficiënter is, dan eerst alle records op te halen en de code te tellen:

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

.distinct (of .uniq)

Als u duplicaten uit een resultaat wilt verwijderen, kunt u .distinct() :

Customers.select(:country).distinct

Hiermee wordt de database als volgt opgevraagd:

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

.uniq() heeft hetzelfde effect. Met Rails 5.0 werd het verouderd en wordt het met versie 5.1 van Rails verwijderd. De reden is dat het woord unique niet dezelfde betekenis heeft als verschillend en het kan misleidend zijn. Verder distinct is dichter bij de SQL-syntaxis.

Doet mee

joins() kunt u tabellen koppelen aan uw huidige model. Voor ex.

User.joins(:posts)

zal de volgende SQL-query produceren:

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

Als u aan tafel zit, heeft u toegang tot:

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

Let op meervoudsvorm. Als uw relatie is :has_many , dan moet het argument joins() meervoudig zijn. Gebruik anders enkelvoud.

Geneste joins :

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

die zal produceren:

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

Inclusief

ActiveRecord met includes zorgt ervoor dat alle opgegeven koppelingen worden geladen met behulp van het minimaal mogelijke aantal query's. Dus wanneer u een tabel opvraagt naar gegevens met een bijbehorende tabel, worden beide tabellen in het geheugen 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 } ) laadt alleen auteurs met voorwaarden in het geheugen zonder boeken te laden . Gebruik joins wanneer aanvullende informatie over geneste koppelingen niet vereist is.

@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

Limiet en offset

U kunt limit gebruiken om het aantal op te halen records te vertellen, en offset gebruiken om het aantal records te vertellen dat moet worden overgeslagen voordat u begint met het retourneren van de records.

Bijvoorbeeld

User.limit(3) #returns first three records

Het zal de volgende sql-query genereren.

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

Omdat offset niet wordt vermeld in de bovenstaande query, retourneert het de eerste drie records.

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

Het zal de volgende sql-query genereren.

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


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow