Szukaj…


Wprowadzenie

ActiveRecord to M in MVC, który jest warstwą systemu odpowiedzialną za reprezentowanie danych biznesowych i logiki. Techniką łączenia obiektów bogatych aplikacji z tabelami w systemie zarządzania relacyjnymi bazami danych jest O rject R elational M apper ( ORM ).

ActiveRecord wykona dla ciebie zapytania w bazie danych i jest kompatybilny z większością systemów baz danych. Niezależnie od używanego systemu bazy danych format metody ActiveRecord zawsze będzie taki sam.

.gdzie

Metoda where jest dostępna w dowolnym modelu ActiveRecord i umożliwia odpytywanie bazy danych o zestaw rekordów pasujących do podanych kryteriów.

Metoda where akceptuje skrót, w którym klucze odpowiadają nazwom kolumn w tabeli reprezentowanej przez model.

Jako prosty przykład użyjemy następującego modelu:

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

Aby znaleźć wszystkie osoby o imieniu Sven :

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

Aby znaleźć wszystkie osoby o imieniu Sven i nazwisku Schrodinger :

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

W powyższym przykładzie dane wyjściowe sql pokazują, że rekordy zostaną zwrócone tylko wtedy, gdy zarówno first_name i last_name zgodne.

zapytanie z warunkiem LUB

Aby znaleźć rekordy za pomocą first_name == 'Bruce' LUB last_name == 'Wayne'

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

. gdzie z tablicą

Metodę where w dowolnym modelu ActiveRecord można użyć do wygenerowania kodu SQL w postaci WHERE column_name IN (a, b, c, ...) . Osiąga się to poprzez przekazanie tablicy jako argumentu.

Jako prosty przykład użyjemy następującego modelu:

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

Jeśli tablica zawiera nil , SQL zostanie zmodyfikowany, aby sprawdzić, czy kolumna ma 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"

Zakresy

Zakresy działają jak predefiniowane filtry w modelach ActiveRecord .

Zakres jest definiowany przy użyciu metody klasy scope .

Jako prosty przykład użyjemy następującego modelu:

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

Zakresy można wywoływać bezpośrednio z klasy modelu:

minors = Person.minors

Lunety mogą być powiązane:

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

Można również połączyć metodę where i inne metody typu zapytania:

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

Za kulisami zakresy są po prostu cukrem syntaktycznym dla standardowej metody klasowej. Na przykład te metody są funkcjonalnie identyczne:

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

# This ^ is the same as this:

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

Domyślny zakres

w swoim modelu, aby ustawić domyślny zakres dla wszystkich operacji na modelu.

Jest jeden zauważalną różnicą pomiędzy scope sposobu i metody klasy: scope -defined zakresy zawsze zwróci ActiveRecord::Relation , nawet jeśli logika wewnątrz zwrotów zerowe. Metody klasowe nie mają jednak takiej siatki bezpieczeństwa i mogą przerwać łańcuch, jeśli zwrócą coś innego.

gdzie nie

where klauzule można negować za pomocą składni 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')

Obsługiwane przez ActiveRecord 4.0 i nowsze wersje.

Zamawianie

Możesz zamówić wyniki zapytań ActiveRecord za pomocą .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">]

Jeśli nie zostanie określony, kolejność będzie wykonywana w kolejności rosnącej. Możesz to określić, wykonując:

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 akceptuje również ciąg znaków, więc możesz to zrobić

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

Ponieważ ciąg jest surowym SQL, możesz również określić tabelę, a nie tylko atrybut. Zakładając, że chcesz uporządkować users według nazwy role , możesz to zrobić:

Class User < ActiveRecord::Base
    belongs_to :role
end

Class Role < ActiveRecord::Base
  has_many :users
end

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

Zakres order może również akceptować węzeł Arel:

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

Metody ActiveRecord Bang (!)

Jeśli potrzebujesz metody ActiveRecord , aby zgłosić wyjątek zamiast false wartości w przypadku niepowodzenia, możesz dodać ! do nich. To jest bardzo ważne. Ponieważ niektóre wyjątki / awarie są trudne do złapania, jeśli nie używasz! na nich. Zaleciłem zrobienie tego w cyklu programowania, aby w ten sposób napisać cały kod ActiveRecord, aby zaoszczędzić czas i kłopoty.

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

Metody ActiveRecord , które akceptują huk ( ! ) To:

  • .create!
  • .take!
  • .first!
  • .last!
  • .find_by!
  • .find_or_create_by!
  • #save!
  • #update!
  • wszystkie dynamiczne wyszukiwarki AR

.find_by

Możesz znaleźć rekordy według dowolnego pola w tabeli za pomocą find_by .

Jeśli masz model User z atrybutem first_name , możesz:

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

Pamiętaj, że find_by nie find_by wyjątku. Jeśli wynik jest pustym zestawem, zwraca nil zamiast find .

Jeśli potrzebny jest wyjątek, można użyć find_by! , który wywołuje błąd ActiveRecord::RecordNotFound taki jak find .

.Usuń wszystko

Jeśli chcesz szybko usunąć wiele rekordów, ActiveRecord podaje metodę .delete_all . do wywołania bezpośrednio w modelu, w celu usunięcia wszystkich rekordów w tej tabeli lub kolekcji. Uważaj jednak, ponieważ .delete_all nie .delete_all instancji żadnego obiektu, dlatego nie zapewnia żadnego wywołania zwrotnego ( before_* i after_destroy nie są wywoływane).

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

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

Wyszukiwanie bez rozróżniania wielkości liter w ActiveRecord

Jeśli potrzebujesz wyszukać model ActiveRecord w celu znalezienia podobnych wartości, możesz ulec pokusie użycia LIKE lub ILIKE ale nie jest to przenośne między silnikami baz danych. Podobnie stosowanie zawsze zmniejszania lub zwiększania może powodować problemy z wydajnością.

Możesz użyć podstawowej metody Arel matches ActiveRecord, aby zrobić to w bezpieczny sposób:

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

Arel zastosuje odpowiednią konstrukcję LIKE lub ILIKE dla skonfigurowanego silnika bazy danych.

Zdobądź pierwszy i ostatni rekord

Szyny mają bardzo łatwy sposób na uzyskanie first i last rekordu z bazy danych.

Aby uzyskać first rekord z tabeli users , musimy wpisać następujące polecenie:

User.first

sql następujące zapytanie sql :

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

I zwróci następujący rekord:

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

Aby uzyskać last rekord z tabeli users , musimy wpisać następujące polecenie:

User.last

sql następujące zapytanie sql :

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

I zwróci następujący rekord:

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

Przekazanie liczby całkowitej do pierwszej i ostatniej metody tworzy zapytanie LIMIT i zwraca tablicę obiektów.

User.first(5)

sql następujące zapytanie sql .

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

I

User.last(5)

sql następujące zapytanie sql .

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

.group i .count

Mamy model Product i chcemy pogrupować je według category .

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

Spowoduje to wysłanie zapytania do bazy danych w następujący sposób:

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

Upewnij się, że pole zgrupowane jest również zaznaczone. Grupowanie jest szczególnie przydatne do zliczania występowania - w tym przypadku - categories .

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

Jak pokazuje zapytanie, użyje bazy danych do zliczania, co jest o wiele bardziej wydajne, niż pobieranie najpierw wszystkich rekordów i wykonywanie zliczania w kodzie:

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

.distinct (lub .uniq)

Jeśli chcesz usunąć duplikaty z wyniku, możesz użyć .distinct() :

Customers.select(:country).distinct

To wysyła zapytanie do bazy danych w następujący sposób:

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

.uniq() ma ten sam efekt. W przypadku Rails 5.0 stał się przestarzały i zostanie usunięty z Railsów w wersji 5.1. Powodem jest to, że słowo „ unique nie ma takiego samego znaczenia jak wyraz „odrębny” i może wprowadzać w błąd. Ponadto distinct jest bliższy składni SQL.

Łączy się

joins() pozwala łączyć tabele z bieżącym modelem. Np.

User.joins(:posts)

wygeneruje następujące zapytanie SQL:

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

Po dołączeniu do stołu będziesz mieć do niego dostęp:

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

Zwróć uwagę na liczbę mnogą. Jeśli twoja relacja to :has_many , to argument joins() powinien być pluralizowany. W przeciwnym razie użyj liczby pojedynczej.

Zagnieżdżone joins :

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

który wytworzy:

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

Obejmuje

ActiveRecord z includes zapewnia, że wszystkie określone powiązania są ładowane przy użyciu minimalnej możliwej liczby zapytań. Tak więc podczas zapytania do tabeli o dane z powiązaną tabelą obie tabele są ładowane do pamięci.

@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 } ) załaduje tylko autorów z warunkami do pamięci bez ładowania książek . Użyj joins gdy dodatkowe informacje o zagnieżdżonych powiązaniach nie są wymagane.

@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 i przesunięcie

Możesz użyć limit aby określić liczbę rekordów do pobrania, i offset aby określić liczbę rekordów, które należy pominąć przed rozpoczęciem zwracania rekordów.

Na przykład

User.limit(3) #returns first three records

Wygeneruje następujące zapytanie SQL.

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

Ponieważ przesunięcie nie jest wymienione w powyższym zapytaniu, zwróci pierwsze trzy rekordy.

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

Wygeneruje następujące zapytanie SQL.

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


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow