12

2 つのルートが定義されているとします。

map.resources articles
map.resources categories, :has_many => :articles

どちらもヘルパー/パスからアクセス可能

articles_path # /articles
category_articles_path(1) # /category/1/articles

にアクセスする/articlesと、indexアクション fromArticlesControllerが実行されます。

にアクセスする/category/1/articlesと、indexアクション fromArticlesControllerも実行されます。

では、呼び出しルートに応じてスコープ付きの記事のみを条件付きで選択するための最良のアプローチは何ですか?

#if coming from the nested resource route
@articles = Articles.find_by_category_id(params[:category_id])
#else
@articles = Articles.all
4

4 に答える 4

13

ここでは、ロジックとビューがスコープにどの程度関連付けられているかに応じて、2 つの選択肢があります。さらに説明しましょう。

最初の選択肢は、他の応答で既に説明したように、コントローラー内のスコープを決定することです。私は通常、@scope 変数を設定して、テンプレートに追加の利点をもたらします。

class Articles

  before_filter :determine_scope

  def index
    @articles = @scope.all
    # ...
  end

  protected

    def determine_scope
      @scope = if params[:category_id]
        Category.find(params[:category_id]).articles
      else
        Article
      end
    end

end

@scope 変数を使用する理由は、単一のアクション以外のリクエストのスコープを知る必要がある場合があるためです。ビューにレコード数を表示するとします。カテゴリでフィルタリングしているかどうかを知る必要があります。この場合、on をチェックするたびに繰り返す代わりに、単に@scope.countorを呼び出す必要があります。@scope.my_named_scope.countparams[:category_id]

このアプローチは、ビュー (カテゴリを含むビューとカテゴリを含まないビュー) が非常に似ている場合にうまく機能します。しかし、カテゴリでフィルタリングされたリストが、カテゴリのないリストとはまったく異なる場合はどうなるでしょうか? これは非常に頻繁に発生します。カテゴリ セクションではカテゴリに焦点を当てたウィジェットを提供し、記事セクションでは記事関連のウィジェットとフィルターをいくつか提供します。また、Article コントローラには、使用したい特別な before_filters がありますが、記事のリストがカテゴリに属している場合はそれらを使用する必要はありません。

この場合、アクションを分離することができます。

map.resources articles
map.resources categories, :collection => { :articles => :get }

articles_path # /articles and ArticlesController#index
category_articles_path(1) # /category/1/articles and CategoriesController#articles

現在、カテゴリ別にフィルタリングされたリストは によって管理され、CategoriesControllerすべてのコントローラ フィルタ、レイアウト、設定を継承します。一方、フィルタリングされていないリストは によって管理されますArticlesController

追加のアクションを使用すると、ビューやコントローラーを大量の条件付きチェックで混乱させる必要がないため、これは通常私のお気に入りの選択です。

于 2009-11-28T08:56:35.273 に答える
3

私はしばしばそれらのアクションを分離するのが好きです。結果のアクションが非常に似ている場合、params[:category_id] が存在するかどうかなどを確認することで、コントローラー内のスコープを簡単に分離できます (@SimoneCarletti の回答を参照)。

通常、カスタム ルートを使用してコントローラーでアクションを分離すると、最も柔軟で明確な結果が得られます。次のコードは通常のルート ヘルパー名になりますが、ルートはコントローラーの特定のアクションに向けられます。

routes.rb:

resources categories do
  resources articles, :except => [:index] do
    get :index, :on => :collection, :action => 'index_articles'
  end
end
resources articles, :except => [:index] do
  get :index, :on => :collection, :action => 'index_all'
end

次に、 ArticlesController.rbに含めることができます

def index_all
  @articles = @articles = Articles.all
  render :index # or something else
end

def index_categories
  @articles = Articles.find_by_category_id(params[:category_id])
  render :index # or something else
end
于 2011-09-29T15:59:00.817 に答える
2
于 2009-11-28T04:41:23.037 に答える
1
if params[:category_id].blank?
  # all
else
  # find by category_id
end

ルートから独立したアクションを考えるのが好きです。どうやってそこにたどり着いたとしても、何をすべきかについて合理的な決定を下してください。

于 2009-11-28T02:13:55.207 に答える