Rails: Verschachtelte Ressourcen Konflikt, wie Umfang der Index Aktion in Abhängigkeit von der genannten Route

StackOverflow https://stackoverflow.com/questions/1811163

Frage

Stellen Sie sich vor, Sie haben zwei definierten Routen:

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

beide zugänglich Helfer / Pfade

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

Wenn Sie /articles, index Aktion von ArticlesController besuchen ausgeführt wird.

Wenn Sie /category/1/articles besuchen, index Aktion von ArticlesController wird auch ausgeführt.

So

Was ist der beste Ansatz für bedingt nur den scoped Artikel Auswahl abhängig von der anrufenden Route?

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

Lösung

Sie haben zwei Möglichkeiten hier, je nachdem, wie viel Sie Ihre Logik und Ihre Sicht auf den Umfang gebunden ist. Lassen Sie mich erklären weiter.

Die erste Wahl ist, den Umfang innerhalb des Controllers, um zu bestimmen, wie bereits von den anderen Antworten erklärt. Ich in der Regel eine @scope Variable einige zusätzliche Vorteile in meiner Vorlagen zu erhalten.

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

Der Grund für die @scope Variable ist, dass Sie den Umfang Ihrer Anfrage außerhalb der einzelnen Maßnahmen wissen brauchen könnten. Nehmen wir an, Sie die Anzahl der Datensätze in der Ansicht angezeigt werden sollen. Sie müssen wissen, ob Sie nach Kategorie sind Filterung oder nicht. In diesem Fall müssen Sie einfach @scope.count oder @scope.my_named_scope.count rufen, anstatt jedes Mal die Prüfung auf params[:category_id] zu wiederholen.

Dieser Ansatz funktioniert gut, wenn Sie Ihre Ansichten, die mit Kategorie und das eine ohne Kategorie, sind recht ähnlich. Aber was passiert, wenn der durch Kategorie gefiltert Eintrag ist völlig anders im Vergleich zu dem ohne eine Kategorie? Dies geschieht sehr oft: Ihre Kategorie Abschnitt enthält einige Kategorie orientierte Widgets, während die Artikel Abschnitt einige Artikel bezogenen Widgets und Filter. Auch Ihre Artikel Controller hat einige spezielle before_filters Sie vielleicht nutzen wollen, aber Sie haben sie nicht zu verwenden, wenn der Artikel-Eintrag zu einer Kategorie gehört.

In diesem Fall möchten Sie vielleicht die Aktionen trennen.

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

Nun ist die Liste nach Kategorien gefiltert wird durch die CategoriesController verwaltet und es erbt alle Controller Filter, Layouts, Einstellungen ... während die ungefilterte Auflistung der ArticlesController verwaltet wird.

Dies ist in der Regel, weil meine bevorzugte Wahl mit einer zusätzlichen Aktion müssen Sie Ihre Ansichten und Controller mit Tonnen von bedingten Kontrollen nicht unübersichtlich.

Andere Tipps

Ich mag oft diese Aktionen zu trennen. Wenn die daraus resultierenden Maßnahmen sehr ähnlich sind, können Sie die Bereiche in der Steuerung durch den Anblick leicht trennen, wenn params. [: Category_id] vorhanden ist usw. (siehe @SimoneCarletti Antwort)

Normalerweise Aktionen in der Steuerung zu trennen, indem individuelle Routen mit bietet Ihnen ein Höchstmaß an Flexibilität und klare Ergebnisse. Folgende Code führt in Normalweg Helfer Namen, aber die Routen zu bestimmten Aktionen in der Steuerung gerichtet sind.

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

Dann können Sie in 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

Mit nur eine einzige verschachtelte Ressource, eine Bedingung, dass die params basierend Verwendung zu bestimmen ist Umfang der einfachste Ansatz wäre. Dies ist wahrscheinlich die Art und Weise, in Ihrem Fall zu gehen.

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

Allerdings, je nachdem, welche andere verschachtelten Ressourcen, die Sie für das Modell haben, mit diesem Ansatz stecken kann ziemlich mühsam bekommen. In diesem Fall mit einem Plugin wie resource_controller oder make_resourceful wird einfacher machen dies viel.

class ArticlesController < ResourceController::Base
  belongs_to :category
end

Dies wird tatsächlich tun alles, was man erwarten würde. Es gibt Ihnen alle Ihre Standard RESTful Aktionen und automatisch Setup den Spielraum für /categories/1/articles.

if params[:category_id].blank?
  # all
else
  # find by category_id
end

Ich mag die Aktion unabhängig von der Route zu prüfen. Egal, wie sie dorthin zu gelangen, macht eine vernünftige Entscheidung, was zu tun ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top