ActiveRecord’s queries tricks小記


ActiveRecord’s queries tricks小記
原文https://medium.com/rubyinside...
関連テーブルjoinの使用条件
# User model
scope :activated, ->{
  joins(:profile).where(profiles: { activated: true })
}

より良い方法
# Profile model
scope :activated, ->{ where(activated: true) }
# User model
scope :activated, ->{ joins(:profile).merge(Profile.activated) }

merge https://apidock.com/rails/Act... https://api.rubyonrails.org/c...について
ネストjoinの違い
  • User has_one Profile
  • Profile has_many Skills
  • User.joins(:profiles).merge(Profile.joins(:skills))
    => SELECT users.* FROM users 
       INNER JOIN profiles    ON profiles.user_id  = users.id
       LEFT OUTER JOIN skills ON skills.profile_id = profiles.id
    # So you'd rather use:
    User.joins(profiles: :skills)
    => SELECT users.* FROM users 
       INNER JOIN profiles ON profiles.user_id  = users.id
       INNER JOIN skills   ON skills.profile_id = profiles.id
       

    内部リンクと外部接続
    Exist query
    存在しない
    # Post
    scope :famous, ->{ where("view_count > ?", 1_000) }
    # User
    scope :without_famous_post, ->{
      where(_not_exists(Post.where("posts.user_id = users.id").famous))
    }
    def self._not_exists(scope)
      "NOT #{_exists(scope)}"
    end
    def self._exists(scope)
      "EXISTS(#{scope.to_sql})"
    end

    Subqueriesサブクエリ
    たとえば、一部のユーザー(user)の投稿をクエリーする(post)
    悪いやり方
    Post.where(user_id: User.created_last_month.pluck(:id))

    ここでの欠点は、2つのSQLクエリーを実行することです.1つはユーザーのIDを取得するために使用され、もう1つはこれらのuser_から使用されます.id投稿の取得
    これでクエリーを書けばいいです
    Post.where(user_id: User.created_last_month)

    きそ
    .to_sqlはSQL文文字列を生成する.explainクエリー分析の取得
    Booleans User.where.not(tall: true)に対してpgの下でSELECT users.* FROM users WHERE users.tall <> 't'が生成され、これはtallがfalseであるレコードを返し、nullを含まない
    nullも含めてこう書くべきだ
    User.where("users.tall IS NOT TRUE")

    or
    User.where(tall: [false, nil])