作って知ったMVCの住み分けかた
「モデルの役割がビミョーだよね」
なんて思っていたのですが、以下のスライドシェアのスライドを読んで、自分が未熟なことことが良くわかりました。ちゃちゃっとSQLを書く手軽さに比べると、O/Rマッパーを使ったコーディングは、データそのものが見えずらいので使いにくい…そう思っていましたが、餅は餅屋、プログラミングにおいてはO/Rマッパーを使う意味というのが良くわかりました。
で、これを読んでいると、モデルの中に"named_scope"とやら(メソッド?)を仕込んで、コントローラーで必要なネームドスコープを使うことで、データベースの値を動的に捉えるといった考え方が正しいらしい。(後記:スコープはスコープでメソッドとは違うみたいだ…そりゃそうだよね名前違うんだし。)
たしかに、ネームドスコープを使って基本的なデータセットをモデルに定義しておいて、コントローラーで必要なネームドスコープを呼んで、ビューが表示するという関係だとMVCっぽい気がする。
後は読む価値は無いです。僕の反省文です。
■ 良くないMVCプログラミング
データベース: db/migrate/[timestamp]_create_mains.rb
class CreateMains < ActiveRecord::Migration
def change
create_table :mains do |t|
t.integer :user_id
t.integer :feed_id
t.boolean :read_flgt.timestamps
end
end
end
モデル: app/models/main.rb
class Main < ActiveRecord::Base
belongs_to :user
default_scope -> { order('created_at DESC') }
end
コントローラー: app/controllers/mains_controller.rb
class MainsController < ApplicationController
...
def index
@main = Main.where(:user_id => current_user.id) # フィード取得用
end
...
ビュー: app/views/shared/_navmenu.html.erb
<ul class="nav nav-pills nav-stacked">
<li><%= link_to "未読一覧", "#", :style => "display:inline-block" %>
<span class="badge"><%= @main.where(:read_flg=>"f").count %></span></li>
</ul>
ビュー: app/views/mains/index.html.erb
<div class="row">
...
<div class="panel panel-default">
<%= render @main.where(:read_flg=>"f") %>
</div>
...
</div>
コントローラーで、Mainモデルから特定のユーザのレコードを引っ張ってきて、インスタンス変数"@main"にセットした後に、さらに、ビュー上でインスタンス変数"@main"の中からfalseのレコードだけを抽出しています。
肝心のモデルは、データに関してソートするだけで、コントローラーとビューが、頑張って働いてくれています。モデルさんは声がかけ辛かったので(パラメーターの渡し方が分からなかったので)、コントローラーさんとビューさんに代わりに仕事をしてもらったのですが、MVCとしての在り方としては良くないですよね、きっと。
■ 良いMVCプログラミング
つまらないけど、嵌った点を2点、先に書いておきます。
① rails4では、named_scopeは存在しない。scopeでいいらしい。
② "scope :own, :condition ..." て書き方はNG。lambda もしくは "->"を使う必要がある。
参考:Rails4でscopeにlambdaを付け忘るとチェインが外れる - Qiita
モデル: app/models/main.rb
class Main < ActiveRecord::Base
belongs_to :user
default_scope -> { order('created_at DESC') }
...
# ログインユーザのレコードを抽出
scope :own, lambda { |uid| where("user_id = ?", "#{uid}") }
# 未読のレコードを抽出
scope :unread, lambda { where(read_flg: false) }
end
コントローラー: app/controllers/mains_controller.rb
class MainsController < ApplicationController
...
def index
@main = Main.own(current_user.id).unread # 未読フィード取得
@cnt = @main.count # 未読フィード件数取得
end
...
ビュー: app/views/shared/_navmenu.html.erb
<ul class="nav nav-pills nav-stacked">
<li><%= link_to "未読一覧", "#", :style => "display:inline-block" %>
<span class="badge"><%= @cnt %></span></li>
</ul>
ビュー: app/views/mains/index.html.erb
<div class="row">
...
<div class="panel panel-default">
<%= render @main %>
</div>
...
</div>
おおお。ビューさんとコントローラーさんが凄くスッキリしましたし、メソッドを呼んでる感があるので、MVCプログラミング的には、前より良くなったのではないでしょうか?
正解かどうかはわかりませんが、少なくとも前の「良くないMVCプログラミング」よりは断然可読性が上がったと思います。
■ 残課題
- lambdaって何者?発音も含めて。