수색…


소개

ActiveRecord는 비즈니스 데이터 및 논리를 나타내는 시스템의 계층 인 MVC의 M입니다. 관계형 데이터베이스 관리 시스템의 테이블에 애플리케이션의 다양한 객체를 연결하는 기술은 O bject R하여 관계형 M의 apper (ORM)이다.

ActiveRecord는 데이터베이스에 대한 쿼리를 수행하며 대부분의 데이터베이스 시스템과 호환됩니다. 사용중인 데이터베이스 시스템에 관계없이 ActiveRecord 메서드 형식은 항상 동일합니다.

.어디에

where 메서드는 모든 ActiveRecord 모델에서 사용할 수 있으며 주어진 조건과 일치하는 레코드 집합에 대해 데이터베이스를 쿼리 할 수 ​​있습니다.

where 메서드는 모델에서 나타내는 테이블의 열 이름에 해당하는 키가있는 해시를 허용합니다.

간단한 예제로 다음 모델을 사용합니다.

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

Sven 이름을 가진 모든 사람들을 찾으려면

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

Sven 이름과 Schrodinger 성을 가진 모든 사람들을 찾으려면 :

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

위의 예제에서 sql 출력은 first_namelast_name 모두 일치하는 경우에만 레코드가 반환됨을 보여줍니다.

OR 조건을 가진 쿼리

first_name == 'Bruce' 또는 last_name == 'Wayne' 레코드를 찾으려면,

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

배열이있는 곳

모든 ActiveRecord 모델의 where 메소드는 WHERE column_name IN (a, b, c, ...) 형식의 SQL을 생성하는 데 사용될 수 있습니다. 배열을 인수로 전달하면됩니다.

간단한 예제로 다음 모델을 사용합니다.

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

배열에 nil 포함되어 있으면 SQL이 열이 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"

범위

범위는 ActiveRecord 모델에서 미리 정의 된 필터 역할을합니다.

범위는 scope 클래스 메서드를 사용하여 정의됩니다.

간단한 예제로 다음 모델을 사용합니다.

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

스코프는 모델 클래스에서 직접 호출 할 수 있습니다.

minors = Person.minors

범위는 연결될 수 있습니다.

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

where 메소드와 다른 질의 유형 메소드도 연결될 수 있습니다.

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

비하면 스코프는 표준 클래스 방법에 대한 단순한 구문 설탕입니다. 예를 들어, 이러한 메소드는 기능적으로 동일합니다.

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

# This ^ is the same as this:

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

기본 범위

모델에서 모든 작업에 대한 기본 범위를 설정합니다.

scope 메소드와 클래스 메소드에는 주목할만한 차이가 있습니다. scope 정의 된 스코프는 논리가 nil을 반환하더라도 항상 ActiveRecord::Relation 반환합니다. 그러나 클래스 메소드는 그러한 안전망이 없으므로 다른 메소드가 반환되면 연쇄성을 깨뜨릴 수 있습니다.

어디 있지.

where 절은 부정 사용 가능 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')

ActiveRecord 4.0 이상에서 지원됩니다.

주문

.order 를 사용하여 ActiveRecord 쿼리 결과를 정렬 할 수 있습니다.

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

지정하지 않으면 오름차순으로 정렬됩니다. 다음을 수행하여 지정할 수 있습니다.

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 는 또한 문자열을 받아 들일 수 있으므로

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

문자열은 원시 SQL이기 때문에 속성뿐만 아니라 테이블도 지정할 수 있습니다. role 이름에 따라 users 를 주문하려는 경우 다음과 같이 할 수 있습니다.

Class User < ActiveRecord::Base
    belongs_to :role
end

Class Role < ActiveRecord::Base
  has_many :users
end

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

order 범위는 Arel 노드를 받아 들일 수 있습니다 :

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

ActiveRecord Bang (!) 메소드

실패한 경우 false 값 대신 예외를 발생시키는 ActiveRecord 메서드가 필요한 경우 추가 할 수 있습니다 ! 그들에게. 이건 매우 중요합니다. 당신이 사용하지 않으면 몇 가지 예외 / 실패를 잡기가 어렵습니다! 그 (것)들에. 모든 ActiveRecord 코드를이 방법으로 작성하면 개발주기에서이 작업을 수행하여 시간과 노력을 절약 할 것을 권장합니다.

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

강타 ( ! )를 받아들이는 ActiveRecord 메소드는 다음과 같습니다.

  • .create!
  • .take!
  • .first!
  • .last!
  • .find_by!
  • .find_or_create_by!
  • #save!
  • #update!
  • 모든 AR 다이내믹 파인더

.find_by

find_by 사용하여 테이블의 모든 필드로 레코드를 찾을 수 있습니다.

따라서 first_name 속성을 가진 User 모델을 사용하면 다음을 수행 할 수 있습니다.

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

find_by 가 기본적으로 예외를 throw하지 않는다는 사실을 find_by . 결과가 빈 세트이면, find 대신 nil 을 리턴합니다.

예외가 필요한 경우 find_by! find 와 같은 ActiveRecord::RecordNotFound 오류가 발생 ActiveRecord::RecordNotFound .

.모두 삭제

많은 레코드를 빠르게 삭제해야하는 경우 ActiveRecord.delete_all 메소드를 제공합니다. 모델에서 직접 호출하거나, 해당 테이블의 모든 레코드를 삭제하거나, 콜렉션을 삭제할 수 있습니다. 그래도 .delete_all 은 어떤 객체를 인스턴스화하지 않으므로 어떤 콜백도 제공하지 않습니다 ( before_*after_destroy 가 트리거되지 않음).

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

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

ActiveRecord 대소 문자를 구분하지 않는 검색

ActiveRecord 모델에서 유사한 값을 검색해야하는 경우 LIKE 또는 ILIKE 를 사용하려는 유혹을받을 수 있지만 데이터베이스 엔진 간에는 이식 할 수 없습니다. 마찬가지로 항상 다운 케 이스 또는 업 케이싱을 사용하면 성능 문제가 발생할 수 있습니다.

ActiveRecord의 기본 Arel matches 메소드를 사용하면 안전한 방식으로이 작업을 수행 할 수 있습니다.

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

Arel은 구성된 데이터베이스 엔진에 대해 적절한 LIKE 또는 ILIKE 구문을 적용합니다.

첫 번째와 마지막 레코드 가져 오기

레일스는 데이터베이스에서 first 이자 last 레코드를 얻는 아주 쉬운 방법을 가지고 있습니다.

users 테이블에서 first 레코드를 가져 오려면 다음 명령을 입력해야합니다.

User.first

그것은 다음과 같은 sql 쿼리를 생성합니다 :

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

그리고 다음 기록을 반환합니다 :

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

users 테이블에서 last 레코드를 얻으려면 다음 명령을 입력해야합니다.

User.last

그것은 다음과 같은 sql 쿼리를 생성합니다 :

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

그리고 다음 기록을 반환합니다 :

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

첫 번째마지막 메서드에 정수를 전달하면 LIMIT 쿼리가 만들어지고 개체 배열이 반환됩니다.

User.first(5)

그것은 다음과 같은 sql 쿼리를 생성합니다.

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

User.last(5)

그것은 다음과 같은 sql 쿼리를 생성합니다.

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

.group 및 .count

우리는 Product 모델을 가지고 있고 그것들을 category 별로 그룹화하고자합니다.

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

그러면 다음과 같이 데이터베이스가 쿼리됩니다.

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

그룹화 된 필드도 선택되어 있는지 확인하십시오. 그룹화는 categories 의 발생 (이 경우)을 계산할 때 특히 유용합니다.

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

쿼리가 보여 주듯이 모든 레코드를 먼저 검색하고 코드에서 계산하는 것보다 더 효율적 인 계산을 위해 데이터베이스를 사용합니다.

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

.distinct (또는 .uniq)

결과에서 중복을 제거하려면 .distinct() 사용할 수 있습니다.

Customers.select(:country).distinct

다음과 같이 데이터베이스를 쿼리합니다.

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

.uniq() 도 같은 효과가 있습니다. Rails 5.0에서는 더 이상 사용되지 않으며 버전 5.1에서는 Rails에서 제거 될 것입니다. 이유는 unique 단어가 unique 단어와 다른 의미를 가지지 않고 오도 할 수 있기 때문입니다. 또한 distinct 는 SQL 구문에 더 가깝습니다.

조인

joins() 사용하면 테이블을 현재 모델과 조인 할 수 있습니다. 예를 들어.

User.joins(:posts)

다음 SQL 쿼리를 생성합니다.

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

테이블에 가입하면 액세스 할 수 있습니다.

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

복수형에주의하십시오. 관계가 :has_many 인 경우, joins() 인수는 복수 화되어야합니다. 그렇지 않으면 단수를 사용하십시오.

중첩 된 joins :

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

이는 다음을 산출합니다 :

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

포함

ActiveRecord with includes 는 지정된 모든 연관이 가능한 최소 수의 쿼리를 사용하여로드되도록합니다. 따라서 연결된 테이블이있는 데이터에 대해 테이블을 쿼리 할 때 두 테이블 모두 메모리로로드됩니다.

@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 } )책을로드하지 않고 조건을 가진 작성자 만 메모리 에로드합니다 . 중첩 된 연결에 대한 추가 정보가 필요하지 않은 경우 joins 사용하십시오.

@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 을 사용하여 반입 할 레코드 수를 알려주고 offset 을 사용하여 레코드를 반환하기 전에 건너 뛸 레코드 수를 알릴 수 있습니다.

예를 들어

User.limit(3) #returns first three records

그것은 다음과 같은 SQL 쿼리를 생성합니다.

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

위의 쿼리에서 오프셋이 언급되지 않았으므로 처음 세 레코드가 반환됩니다.

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

그것은 다음과 같은 SQL 쿼리를 생성합니다.

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


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow