Active Record
Query Interface

박유진

parkeugene7676@gmail.com

- RORLab Biweekly Lecture -

 목차

  • 소개
  • 훑어보기
  • 레일스 4에서 달라진 점
  • 레퍼런스와 유용한 링크

소개

  • Active Record  Query Interface 번역자료
    http://guides.rorlab.org/active_record_querying.html
     
  • RORLab. 강의동영상 모음 Youtube Channel
    http://rorlab.org
     
  • 레일스 가이드 시즌4
    https://www.youtube.com/playlist?list=PLfFG7L-h1FSrotpAplTzHMKh_LnuT5pGX

훑어보기

  • 질의 (1~5장)

  • 집계 (6,7,19장)
  • 릴레이션, 객체, 트랜잭션(8~11,16,18장)
  • 조인, Eager Loading (12,13장)

  • 스코프, 동적 파인더(14,15장)

  • sql, explain (17,20장)

Rails4에서 달라진 점

  • Null Object
    none 메소드는 연쇄가 가능한 관계(ActiveRecord::Relation)를 돌려줍니다(레코드를 돌려주지 않습니다). 이 메소드에게 받은 관계에 어떤 조건을 연결하더라도, 항상 빈 관계가 생성됩니다. 이는 메소드나 스코프에 연쇄(chain) 가능한 응답이 필요하고, 결과를 돌려주고 싶지 않은 경우에 편리합니다.

# 아래의 visible_posts 메소드는 관계를 하나만 돌려줄 것이라고 기대됩니다.
@posts = current_user.visible_posts.where(name: params[:name])
 
def visible_posts
  case role
  when 'Country Manager'
    Post.where(country: country)
  when 'Reviewer'
    Post.published
  when 'Bad User'
    Post.none # => 이 경우 []나 nil을 반환하여 호출된 쪽의 코드 실행을 중지한다
  end
end

Rails4에서 달라진 점

  • Scopes require a callable object
    (like Proc or lambda)

#Rails3

scope :recent, where(published_at: Time.now - 2.weeks)
#Rails 4

class Post < ActiveRecord::Base
  scope :published, -> { where(published: true) }
end
  • Model.all
    Relation 객체가 반환됨

Rails4에서 달라진 점

  • update_columns


@team.update_columns(name: 'X-Men', universe: 'Marvel')
  • #first 
    기본키의 정렬이 포함됨

Team.first
Rails 3: SELECT "teams".* FROM "teams" LIMIT 1
Rails 4: SELECT "teams".* FROM "teams" ORDER BY "teams"."id" ASC LIMIT 1

Rails4에서 달라진 점

  • Deprecated Finders
    Scope를 사용

# find_all_by_
Rails 3: Team.find_all_by_name('Justice League')
Rails 4: Team.where(name: 'Justice League')

# find_last_by_
Rails 3: Team.find_last_by_name('Justice League')
Rails 4: Team.where(name: 'Justice League').last

# find_or_create_by_
Rails 3: Team.find_or_create_by_name('Justice League')
Rails 4: Team.where(name: 'Justice League').first_or_create

# find_or_create_by_...!
Rails 3: Team.find_or_create_by_name!('Justice League')
Rails 4: Team.where(name: 'Justice League').first_or_create!

# find_or_initialize_by_
Rails 3: Team.find_or_initialize_by_name('Justice League')
Rails 4: Team.where(name: 'Justice League').first_or_initialize

# scoped_by_
Rails 3: Team.scoped_by_name('Justice League')
Rails 4: Team.where(name: 'Justice League')

Rails4에서 달라진 점

  • find_by and find_by!
    Model.find_by는 주어진 조건에 맞는 레코드 중 첫번째를 반환합니다.

Client.find_by first_name: 'Lifo'
# => #<Client id: 1, first_name: "Lifo">
 
Client.find_by first_name: 'Jon'
# => nil
Client.find_by! first_name: 'Lifo'
# => #<Client id: 1, first_name: "Lifo">
 
Client.find_by! first_name: 'Jon'
# => ActiveRecord::RecordNotFound
Client.where(first_name: 'Lifo').first
# => #<Client id: 1, first_name: "Lifo">
 

Rails4에서 달라진 점

  • #pluck ( 레일스 가이드에 문서화됨 )

published_book_titles = Book.published.select(:title).map(&:title)
published_book_titles = Book.published.map(&:title)
published_book_titles = Book.published.pluck(:title)
  • where.not

names = %w(John James)

# Rails 3.2
User.where("name NOT IN (?)", names) # Database-dependent

# Rails 4.0
User.where.not(name: names) # We don't need to take care of type of 'names'

Rails4에서 달라진 점

  • References

Team.includes(:members).where('members.name = ?', 'Batman')

# Rails 3
SQL (0.7ms)  SELECT "teams"."id" AS t0_r0, 
                    "teams"."name" AS t0_r1, 
                    "teams"."created_at" AS t0_r2, 
                    "teams"."updated_at" AS t0_r3, 
                    "members"."id" AS t1_r0, 
                    "members"."name" AS t1_r1, 
                    "members"."bio" AS t1_r2, 
                    "members"."team_id" AS t1_r3, 
                    "members"."created_at" AS t1_r4, 
                    "members"."updated_at" AS t1_r5 
             FROM "teams" LEFT OUTER JOIN "members" 
             ON "members"."team_id" = "teams"."id" 
             WHERE (members.name = 'Batman')

# Rails 4
DEPRECATION WARNING: It looks like you are eager loading table(s) 
(one of: teams, members) that are referenced in a string SQL snippet.
...
Team.includes(:members)
    .where("members.name = ?", 'Batman')
    .references(:members)

Rails4에서 달라진 점

  •  Default Scopes
     

#before
 
User.all
# SELECT "users".* FROM "users" 
  WHERE "users"."state" = 'pending'
 
User.active
# SELECT "users".* FROM "users" 
  WHERE "users"."state" = 'active'
 
User.where(state: 'inactive')
# SELECT "users".* FROM "users" 
  WHERE "users"."state" = 'inactive'
#After
 
User.all
# SELECT "users".* FROM "users" 
WHERE "users"."state" = 'pending'
 
User.active
# SELECT "users".* FROM "users" 
  WHERE "users"."state" = 'pending' 
  AND "users"."state" = 'active'
 
User.where(state: 'inactive')
# SELECT "users".* FROM "users" 
  WHERE "users"."state" = 'pending' 
  AND "users"."state" = 'inactive'
class User < ActiveRecord::Base
  default_scope { where state: 'pending' }
  scope :active, -> { where state: 'active' }
  scope :inactive, -> { where state: 'inactive' }
end

레퍼런스 및 유용한 링크

 

  • http://blog.remarkablelabs.com/2012/12/what-s-new-in-active-record-rails-4-countdown-to-2013
  • http://blog.mitchcrowe.com/blog/2012/04/14/10-most-underused-activerecord-relation-methods/
  • http://railscasts.com/episodes/239-activerecord-relation-walkthrough
  • http://railscasts.com/episodes/355-hacking-with-arel​
    (pro)

Active Record Query Interface

By Eugene Park

Active Record Query Interface

  • 395