ThingというRailsモデルがあるとします。 Thingには、オプションをインターネット上のどこかのURLに設定できるurl属性があります。ビューコードでは、次のことを行うロジックが必要です。
<% if thing.url.blank? %>
<%= link_to('Text', thing_path(thing)) %>
<% else %>
<%= link_to('Text', thing.url) %>
<% end %>
ビュー内のこの条件付きロジックは見苦しいです。もちろん、ビューを次のように変更するヘルパー関数を作成できます。
<%= thing_link('Text', thing) %>
これで冗長性の問題は解決しますが、モデル自体に機能があることを本当に望んでいます。その場合、ビューコードは次のようになります。
<%= link_to('Text', thing.link) %>
これには、明らかに、モデルのリンクメソッドが必要です。含める必要があるものは次のとおりです。
def link
(self.url.blank?) ? thing_path(self) : self.url
end
問題の点までは、thing_path()はモデルコード内の未定義のメソッドです。いくつかのヘルパーメソッドをモデルに「プルイン」することが可能だと思いますが、どのように?そして、ルーティングがコントローラーでのみ動作し、アプリのレイヤーを表示する本当の理由はありますか?モデルコードがURLを処理する必要がある(外部システムとの統合など)多くの場合を考えることができます。
Rails 3、4、および5では、次を使用できます。
Rails.application.routes.url_helpers
例えば.
Rails.application.routes.url_helpers.posts_path
Rails.application.routes.url_helpers.posts_url(:Host => "example.com")
私はこれを自分で行う方法に関する答えを見つけました。モデルコード内に、次のように入力します。
Rails <= 2の場合:
include ActionController::UrlWriter
Rails 3の場合:
include Rails.application.routes.url_helpers
これにより、thing_path(self)
が現在のもののURLを返すようになり、other_model_path(self.association_to_other_model)
が他のURLを返すようになります。
また、すべてのメソッドを含めるよりも、次のアプローチの方がわかりやすい場合があります。
class Thing
delegate :url_helpers, to: 'Rails.application.routes'
def url
url_helpers.thing_path(self)
end
end
モデル内のメソッドは厳密にデータを処理するため、ビューに表示される内容に関係するロジックはヘルパーメソッドに委任する必要があります。
できることは次のとおりです。
# In the helper...
def link_to_thing(text, thing)
(thing.url?) ? link_to(text, thing_path(thing)) : link_to(text, thing.url)
end
# In the view...
<%= link_to_thing("text", @thing) %>
次のクリーンなソリューションが本当に好きです。
class Router
include Rails.application.routes.url_helpers
def self.default_url_options
ActionMailer::Base.default_url_options
end
end
router = Router.new
router.posts_url # http://localhost:3000/posts
router.posts_path # /posts
http://hawkins.io/2012/03/generated_urls_whenever_and_wherever_you_want/ から
方法があるかもしれませんが、この種のロジックをモデルから除外する傾向があります。ビューにそれを入れてはいけないことに同意します( keep it skinny )が、モデルがURLをデータの一部としてコントローラーに返さない限り、ルーティングはコントローラーにあるべきです。
(編集:以前のせせらぎを忘れて...)
わかりました、あなたはモデルか他のURLに行く状況があるかもしれません...しかし、私はこれがモデルに属しているとは本当に思いません。ビュー(またはモデル)はより適切に聞こえます。
ルートについては、私が知る限り、ルートは直接ビューではなく、コントローラーのアクション用です(通常は「魔法のように」ビューを使用します)。コントローラーはすべての要求を処理し、ビューは結果を表示し、モデルはデータを処理してビューまたはコントローラーに提供する必要があります。ここでは多くの人がモデルへのルートについて話しているのを聞いたことがありますが(私はほとんどそれを離れ始めています)、理解しているように:ルートはコントローラーに行きます。もちろん、多くのコントローラーは1つのモデルのコントローラーであり、しばしば<modelname>sController
と呼ばれます(たとえば、「UsersController」はモデル「User」のコントローラーです)。
ビューに大量のロジックを記述していることに気付いた場合は、ロジックをより適切な場所に移動してください。リクエストと内部通信ロジックはおそらくコントローラーに属し、データ関連のロジックはモデルに配置できますが(リンクタグなどを含む表示ロジックは除く)、純粋に表示関連のロジックはヘルパーに配置されます。