
Ruby on Rails 5アプリケーションプログラミング
- 作者: 山田祥寛
- 出版社/メーカー: 技術評論社
- 発売日: 2017/04/14
- メディア: 大型本
- この商品を含むブログを見る
序文
「Ruby on Rails 5 アプリケーションプログラミング」学習16日目。
並行してやってる趣味全開のアプリの開発が楽しい。
よろしくお願いします。
github.com
GitHub
進捗
- 第5章 モデル開発
- 5.2 より複雑な条件での検索を行う - クエリメソッド
(学習時間:3時間)
- 5.2 より複雑な条件での検索を行う - クエリメソッド
コード実装部分
↓config/routes.rb
# 省略 get 'record/where' get 'record/keyword' post 'record/ph1' get 'record/not(/:id)', to: 'record#not' get 'record/where_or' get 'record/order' get 'record/reorder' get 'record/select' get 'record/select2' get 'record/offset' get 'record/page(/:id)', to: 'record#page' get 'record/last' get 'record/groupby' get 'record/havingby' get 'record/where2' get 'record/unscope' get 'record/unscope2' get 'record/none(/:id)', to: 'record#none' end
↓app/controllers/record_controller.rb
class RecordController < ApplicationController # 省略 def where @cds = Cd.where(label: 'サザナミレーベル') # ↓SQL # SELECT "cds".* # FROM "cds" # WHERE "cds"."label" = ? # [["label", "サザナミレーベル"]] # @cds = Cd.where(label: 'サザナミレーベル', is_major: true) # ↓SQL # SELECT "cds".* # FROM "cds" # WHERE "cds"."label" = ? # AND "cds"."is_major" = ? # [["label", "サザナミレーベル"], # ["is_major", "t"]] # @cds = Cd.where(released: '2016-06-01'..'2016-12-31') # ↓SQL # SELECT "cds".* # FROM "cds" # WHERE ("cds"."released" BETWEEN ? AND ?) # [["released", "2016-06-01"], # ["released", "2016-12-31"]] # @cds = Cd.where(label: ['ビクターエンタテインメント', 'エピックレコードジャパン']) # ↓SQL # SELECT "cds".* # FROM "cds" # WHERE "cds"."label" # IN ('ビクターエンタテインメント', 'エピックレコ # ードジャパン') render 'yahoo/list' end def ph1 # keyword.html.erbのフォームからpostでパラメータを渡している # 必ずプレースホルダーを利用すること # 文字列連結ではSQLインジェクションの原因となる可能性がある @cds = Cd.where('label = ? AND price >= ?', params[:label], params[:price]) # ↓SQL # SELECT "cds".* # FROM "cds" # WHERE # (label = 'サザナミレーベル' AND price >= '1980') # プレースホルダーを利用しない書き方もできる # @cds = Cd.where('label = :label AND price >= :price', # label: params[:label], # price: params[:price]) # SELECT "cds".* # FROM "cds" # WHERE # (label = 'ビクターエンタテインメント' AND price >= '3000') render 'yahoo/list' end def not # URLからGETでパラメータを取得している @cds = Cd.where.not(jan: params[:id]) # SELECT "cds".* # FROM "cds" # WHERE ("cds"."jan" != ?) # [["jan", "978-4-7741-7568-3"]] render 'cds/index' end def where_or @cds = Cd.where(label: 'サザナミレーベル').or(Cd.where('price > 2000')) # ↓SQL # SELECT "cds".* # FROM "cds" # WHERE ("cds"."label" = ? OR (price > 2000)) # [["label", "サザナミレーベル"]] # 以下は、互換性エラーとなる #@cds = Cd.where(label: 'サザナミレーベル').or(Cd.where('price > 2000').limit(1)) render 'yahoo/list' end def order @cds = Cd.where(label: 'サザナミレーベル').order(released: :desc) # SELECT "cds".* # FROM "cds" # WHERE "cds"."label" = ? # ORDER BY "cds"."released" DESC # [["label", "サザナミレーベル"]] # @cds = Cd.where(label: 'サザナミレーベル').order(released: :desc, price: :asc) # SELECT "cds".* # FROM "cds" # WHERE "cds"."label" = ? # ORDER BY # "cds"."released" DESC, "cds"."price" ASC # [["label", "サザナミレーベル"]] render 'yahoo/list' end def reorder # @cds = Cd.order(:label).order(:price) # SELECT "cds".* # FROM "cds" # ORDER BY # "cds"."label" ASC, # "cds"."price" ASC # ORDERやり直し(使いみちがわからん) @cds = Cd.order(:label).reorder(:price) # SELECT "cds".* # FROM "cds" # ORDER BY "cds"."price" ASC # ORDER取り消し # @cds = Cd.order(:label).reorder(nil) # SELECT "cds".* FROM "cds" render 'cds/index' end def select @cds = Cd.where('price >= 2000').select(:title, :price) # SELECT # "cds"."title", # "cds"."price" # FROM "cds" # WHERE (price >= 2000) # ↓一部のフィールドが取得できないためエラーが出る render 'yahoo/list' end def select2 @labs = Cd.select(:label).distinct.order(:label) # SELECT DISTINCT "cds"."label" # FROM "cds" # ORDER BY "cds"."label" ASC # DISTINCT取り消し # @labs = Cd.select(:label).distinct.distinct(false) # SELECT "cds"."label" FROM "cds" end def offset # 5~7件目を取得 @cds = Cd.order(released: :desc).limit(3).offset(4) # SELECT "cds".* # FROM "cds" # ORDER BY "cds"."released" DESC # LIMIT ? # OFFSET ? # [["LIMIT", 3], ["OFFSET", 4]] render 'yahoo/list' end def page page_size = 3 page_num = params[:id] == nil ? 0 : params[:id].to_i - 1 @cds = Cd.order(released: :desc).limit(page_size).offset(page_size * page_num) # SELECT "cds".* # FROM "cds" # ORDER BY "cds"."released" DESC # LIMIT ? OFFSET ? # [["LIMIT", 3], ["OFFSET", 3]] render 'yahoo/list' end def last # lastはクエリメソッドではないので、 # メソッドチェーンの途中に記述することはできない @cd = Cd.order(released: :desc).last # SELECT "cds".* # FROM "cds" # ORDER BY "cds"."released" ASC # LIMIT ? # [["LIMIT", 1]] render 'cds/show' end def groupby @cds = Cd.select('label, AVG(price) AS avg_price').group(:label) # SELECT # label, # AVG(price) AS avg_price # FROM "cds" # GROUP BY "cds"."label" end def havingby @cds = Cd.select('label, AVG(price) AS avg_price').group(:label). having('AVG(price) >= ?', 2500) # SELECT # label, # AVG(price) AS avg_price # FROM "cds" # GROUP BY "cds"."label" # HAVING (AVG(price) >= 2500) render 'record/groupby' end def where2 # メソッドチェーンを使わない方法 @cds = Cd.all @cds.where!(label: 'サザナミレーベル') @cds.order!(:released) # SELECT "cds".* # FROM "cds" # WHERE "cds"."label" = ? # ORDER BY "cds"."released" ASC # [["label", "サザナミレーベル"]] render 'cds/index' end def unscope # クエリメソッドの取り消し @cds = Cd.where(label: 'サザナミレーベル').order(:price) .select(:jan, :title).unscope(:where, :select) # SELECT "cds".* # FROM "cds" # ORDER BY "cds"."price" ASC render 'cds/index' end def unscope2 @cds = Cd.where(label: 'サザナミレーベル', is_major: true).order(:price) .unscope(where: :is_major) # SELECT "cds".* # FROM "cds" # WHERE "cds"."label" = ? # ORDER BY "cds"."price" ASC # [["label", "サザナミレーベル"]] render 'cds/index' end def none case params[:id] when 'all' @cds = Cd.all when 'new' @cds = Cd.order('released DESC').limit(5) when 'cheap' @cds = Cd.order(:price).limit(5) else # 空の結果セットを返すことで # 予期しないパラメータを与えられてもエラーにならない @cds = Cd.none end render 'cds/index' end end
↓/app/views/record/keyword.html.erb
<%# POST検索サンプル %> <%= form_tag action: :ph1 do %> <div class="field"> <%= label_tag :label, 'レーベル:' %> <%= text_field_tag :label %> </div> <div class="field"> <%= label_tag :price, '最低価格:' %> <%= text_field_tag :price %> </div> <%= submit_tag '検索' %> <% end %>
↓/app/views/record/groupby.html.erb
<table> <tr> <th>レーベル</th><th>価格</th> </tr> <% @cds.each do |cd| %> <tr> <td><%= cd.label %></td> <td><%= cd.avg_price.round %>円</td> </tr> <% end %> </table>
↓/app/views/record/select2.html.erb
<ul> <% @labs.each do |lab| %> <li><%= lab.label %></li> <% end %> </ul>
実行結果
感想
コードが長くてごめんなさい。
今日はクエリメソッド総ざらい。
私は一応SQLの基本的な部分はわかるから、ただめんどくさいだけで済むけど、SQL知らない人はまったく理解できないと思う。
やっぱRailsって最初にやる教材じゃないよね。
カロリーメイトください。
BGM
健康ランド / 青い果実 www.youtube.com