web-dev-qa-db-ja.com

Rails Routing Helpers(つまり、mymodel_path(model))をモデルで使用できますか?

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を処理する必要がある(外部システムとの統合など)多くの場合を考えることができます。

347
Aaron Longwell

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")
662
Paul Horsfall

私はこれを自分で行う方法に関する答えを見つけました。モデルコード内に、次のように入力します。

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を返すようになります。

179
Aaron Longwell

また、すべてのメソッドを含めるよりも、次のアプローチの方がわかりやすい場合があります。

class Thing
  delegate :url_helpers, to: 'Rails.application.routes' 

  def url
    url_helpers.thing_path(self)
  end
end
113
matthuhiggins

モデル内のメソッドは厳密にデータを処理するため、ビューに表示される内容に関係するロジックはヘルパーメソッドに委任する必要があります。

できることは次のとおりです。

# 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) %>
13
Josh Delsman

次のクリーンなソリューションが本当に好きです。

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/ から

2
Swar Shah

方法があるかもしれませんが、この種のロジックをモデルから除外する傾向があります。ビューにそれを入れてはいけないことに同意します( keep it skinny )が、モデルがURLをデータの一部としてコントローラーに返さない限り、ルーティングはコントローラーにあるべきです。

1
Ryan Montgomery

(編集:以前のせせらぎを忘れて...)

わかりました、あなたはモデルか他のURLに行く状況があるかもしれません...しかし、私はこれがモデルに属しているとは本当に思いません。ビュー(またはモデル)はより適切に聞こえます。

ルートについては、私が知る限り、ルートは直接ビューではなく、コントローラーのアクション用です(通常は「魔法のように」ビューを使用します)。コントローラーはすべての要求を処理し、ビューは結果を表示し、モデルはデータを処理してビューまたはコントローラーに提供する必要があります。ここでは多くの人がモデルへのルートについて話しているのを聞いたことがありますが(私はほとんどそれを離れ始めています)、理解しているように:ルートはコントローラーに行きます。もちろん、多くのコントローラーは1つのモデルのコントローラーであり、しばしば<modelname>sControllerと呼ばれます(たとえば、「UsersController」はモデル「User」のコントローラーです)。

ビューに大量のロジックを記述していることに気付いた場合は、ロジックをより適切な場所に移動してください。リクエストと内部通信ロジックはおそらくコントローラーに属し、データ関連のロジックはモデルに配置できますが(リンクタグなどを含む表示ロジックは除く)、純粋に表示関連のロジックはヘルパーに配置されます。

0