2017-07-13 2 views
0

Aufgrund einiger Anforderungen (durch den Product Owner) muss ich vom goldenen Pfad abweichen und überschreiben Sie eine Ressource Route für einige URLs, die eine Einschränkung entsprechen.Müssen einige Code (Einfügen in DB) vor Minitest-Route testen

Rails.application.routes.draw do 
    CATEGORY_SLUGS = Regexp.new(Category.all.collect(&:slug).join('|')) 
    get '/posts/:category', to: 'posts#index', as: :category_posts, constraints: { category: CATEGORY_SLUGS } 
    resources :posts 
end 

und mein Test:

require 'test_helper' 
class PotsControllerTest < ActionDispatch::IntegrationTest 
    # routes 
    test "/posts/:category" do 
    Fabricate(:category, slug: 'rails') 

    assert_recognizes({controller: 'posts', action: 'index', category: 'rails' }, 'posts/rails') 
    end 

Der Test schlägt fehl offenbar, weil die Strecken lange vor Beginn der Prüfung gezogen werden und die Category existiert noch nicht an diesem Punkt.

Gibt es eine gute Alternative zu der CATEGORY_SLUGS oder irgendetwas im Test zeichnen die Routen später?

+0

Warum die mehr RESTful Ansatz nicht wählen: '/ categories /: Slug/posts'? Das würde all deine Probleme lösen. Wenn dies nicht möglich ist, können Sie möglicherweise eine Integritätsbedingung einführen, die nur Nicht-Ganzzahl-Parameter erfüllt, sodass Sie nicht mit allen Elementen aus der Datenbank vergleichen müssen. – zwippie

+0

Ja, würde es, aber der Product Owner will verschiedene URLs. Nicht-Integer-Params zu finden, ist auch keine Option, da die Posts auch Slugs haben und einige Kategorien mit Zahlen beginnen. –

+0

Ich habe versucht, die Einschränkung in eine Klasse umzuwandeln, aber das hat das Problem nur verschoben. –

Antwort

1

Nach dem Testaufbau mit dem Fabricate Anruf in diesem Fall können Sie verlangen, dass Rails ihre Routen mit neu geladen:

Rails.application.reload_routes! 

Damit soll sichergestellt werden, dass die dynamischen Routen vor Ihrem assert_recognizes Aufruf generieren.

+0

Danke, das erlaubte mir tatsächlich, die Route zu testen. –

+0

Super. Und damit bin ich gerade ein Stack-Overflow-Moderator geworden (!) Https://www.dropbox.com/s/l8doas52ghrj7f/Screenshot%202017-07-16%2021.44.06.png?dl=0 – stef

+0

:) Warte einfach, bis du dein erstes goldenes Abzeichen bekommst. –

1

Dieser Ansatz (das Konstruieren einer Einschränkung in der Routingkonfiguration mithilfe von Daten aus einem ActiveRecord-Modell) hat schwerwiegende Nachteile. Nicht nur, dass es fast unmöglich ist, es richtig zu testen, sondern Sie müssen die Anwendung auch neu starten, wenn sich Kategorien ändern, um die Einschränkung neu zu erstellen.

Ich schlage vor, die Logik in die Controller-Aktion zu verschieben. Sie zahlen dafür einen kleinen Leistungspreis (eine zusätzliche Datenbankabfrage beim Rendern eines Posts), aber es lohnt sich auf jeden Fall. Es kann gemildert werden, indem bei Bedarf ein Abfrage-Cache für Kategorien eingeführt wird.

Routing:

Rails.application.routes.draw do 
    resources :posts 
end 

Controller:

class PostsController < ActionController::Base 
    def show 
    category = Category.find_by_slug params[:id] 
    if category 
     # ... render a Category 

     return 
    end 

    post = Post.find_by_slug params[:id] 
    # ... render a Post 
    end