19530


RailsでViewからのクラスメソッドの呼び出しについて教えて下さい。

インスタンス固有の値を持たないようなメソッドについて、クラスメソッドでもインスタンスメソッドでも呼び出しは出来ると思うのですが、どちらを利用するべきかで疑問がわきました。

MyClass.find_case(param1) のようなメソッドをfor分の中で呼び出すとします。

どちらのようにするのが正しいのでしょうか？

  1. コントローラーでインスタンス変数を作ってからviewから呼び出す。  
Controller  
`@my_class = MyClass.new`  
View  
`<%= @my_class.find_case(param1) %>`

  2. viewから直接呼び出す。  
View  
`<%= MyClass.find_case(param1) %>`

どちらでも動くと思うのですが、Viewから直接モデルのクラスを呼び出す事がなんとなく気持ち悪く質問させていただきました。

効率の面でも教えていただければ幸いです。


CC BY-SA 3.0
2015-12-01T05:21:18.480
19496
2015-12-02T02:16:19.987
8919
question
ruby-on-rails
RailsでViewからのクラスメソッドの呼び出しについて


どちらでも動きますし、絶対どちらにしなければならないというルールはありませんが、後者の方がベターです。

やろうと思えばコントローラ内でいくらでもインスタンス変数を作ってビューに渡すことはできますが、コントローラとビューの間にコンテキスト（暗黙の前提条件）が増えてしまうので、インスタンス変数の定義はむしろ制限した方が良いです。

その際の大雑把なガイドラインとして、「HTMLではなく、JSON等のAPIとしてレスポンスを返すときに、そのインスタンス変数のデータを返却するか？」を考えてみるのがいいと思います。

たとえば `/books.json` であれば

[code]

    def index
      @books = Book.all
    end
    
[/code]

とするのは自然です。

しかし、

[code]

    def index
      @books = Book.all
      @my_class = MyClass.new
    end
    
[/code]

と書いた場合、おそらく `@my_class` はJSONとして返却する値にはならないと思います。

もちろん、例外的にJSONでは使わないような値をインスタンス変数としてビューに渡すケースはありますが、それは珍しいパターンだと思った方がいいでしょう。


CC BY-SA 3.0
2015-12-01T21:57:57.210
19530
2015-12-01T21:57:57.210
85
19496
answer


私は後者を使用していますが、確かにView側でクラスメソッドを使うのは気持ち悪いですね。  
パフォーマンス等はfor文でSQLを何度も呼び出す点において避けたいですね。  
クラスにするかインスタンスにするかはほとんど無視していいんじゃないでしょうか。

また、もしかしたらお節介な回答になってしまうかもしれませんが、ViewModelsというディレクトリを作るとそのような状況を避けることが出来るかもしれません。(求めているものとスルーして下さい!)

私の推測だと、そのような対応を強いられる問題はコントローラーでビューに渡すオブジェクトを生成しきれていないことが原因だと思うのですが、無理やりコントローラーで生成するとコントローラーが汚くなる。

for文をネストする状況ではよくあるかもしれません。

そこで、ビューオブジェクトを生成するViewModel層を導入すると良いかもしれません。  
以下は適当な例です。

app/controllers/hoge_controller.rb

[code]

    class HogeController < ApplicationController
       def index
         @view_obj = ViewModel.new(current_user)
       end
    end
    
[/code]

app/view_models/view_model.rb

ViewModelでは、なるべくViewのインターフェースをすっきりさせるために整形しておきます。  
for文のネストならば、ハッシュを創るロジックが多いです。

[code]

    class ViewModel
      def initialize(user)
        @user = user
      end
    
      def loop_date
        # 整形ロジック
      end
    end
    
[/code]

app/views/hoge.html.erb

[code]

    <% @view_obj.each do |obj| %>
      <% = obj.book %>
    <% end %> 
    
[/code]

Viewのインターフェースをなるべく綺麗にし、コントローラーでViewのための整形ロジックは書かずにViewModelに委譲する。  
ViewModelについては以下を参考にしてみてください。  
5\. ビューオブジェクト  
<http://techracho.bpsinc.jp/hachi8833/2013_11_19/14738>


CC BY-SA 3.0
2015-12-02T02:03:42.937
19535
2015-12-02T02:03:42.937
12758
19496
answer


クラスメソッドであるべきものはクラスメソッドであるべきですので、少なくとも

> コントローラーでインスタンス変数を作ってからviewから呼び出す。  
>  Controller
[code]

>     @my_class = MyClass.new
>  
[/code]

>
> View
[code]

>     <%= @my_class.find_case(param1) %>
>  
[/code]

というのは良い方法ではないと明確に言えます。


CC BY-SA 3.0
2015-12-02T02:16:19.987
19536
2015-12-02T02:16:19.987
5793
19496
answer