2009-07-30 6 views
0

Je dois séparer les modèles: les sections imbriquées et les articles, section a_many articles. Les deux ont attribut path comme aaa/bbb/ccc, par exemple:contrôleur de rails de commutation

movies # section 
movies/popular # section 
movies/popular/matrix # article 
movies/popular/matrix-reloaded # article 
... 
movies/ratings # article 
about # article 
... 

Itinéraires J'ai:

map.path '*path', :controller => 'path', :action => 'show' 

Comment créer une action de spectacle comme

def show 
    if section = Section.find_by_path!(params[:path]) 
    # run SectionsController, :show 
    elsif article = Article.find_by_path!(params[:path]) 
    # run ArticlesController, :show 
    else 
    raise ActiveRecord::RecordNotFound.new(:) 
    end 
end 

Répondre

1

Vous devez utiliser le middleware Rack pour intercepter la demande, puis réécrire l'URL de votre application Rails appropriée. De cette façon, vos fichiers de routes restent très simples.

map.resources :section 
map.resources :articles 

Dans le middleware vous regardez l'entité associée au chemin et l'URL pour remappez simple url interne, ce qui permet Rails de routage à être envoyé au contrôleur correct et la chaîne invoquant filtre normalement.

Mise à jour

est ici simple procédure pas à pas d'ajouter ce type de fonctionnalité en utilisant un composant Rails Metal et le code que vous avez fourni. Je suggère que vous cherchiez à simplifier la façon dont les segments de chemin sont recherchés puisque vous dupliquez beaucoup de travail de base de données avec le code actuel.

$ script/generate metal path_rewriter 
     create app/metal 
     create app/metal/path_rewriter.rb 

path_rewriter.rb

# Allow the metal piece to run in isolation 
require(File.dirname(__FILE__) + "/../../config/environment") unless defined?(Rails) 

class PathRewriter 
    def self.call(env) 
    path = env["PATH_INFO"] 
    new_path = path 

    if article = Article.find_by_path(path) 
     new_path = "/articles/#{article.id}" 

    elsif section = Section.find_by_path(path) 
     new_path = "/sections/#{section.id}" 

    end 

    env["REQUEST_PATH"] = 
    env["REQUEST_URI"] = 
    env["PATH_INFO"] = new_path 

    [404, {"Content-Type" => "text/html"}, [ ]] 
    end 
end 

Pour une bonne introduction à l'utilisation de métal et rack en général, consultez Railscast Ryan Bates episode on Metal et episode on Rack.

+0

Je devrais intercepter avant le module de routage? Ou existe-t-il un moyen de créer un itinéraire avec proc/lambda? – tig

+0

Oui, interception avant le module de routage. Ensuite, les routes dans votre application "Rails" restent très normales, mais une application middleware réécrit les URL entrantes en fonction du chemin indiqué par le navigateur. –

1

Plutôt que instanciation les autres contrôleurs Je voudrais juste rendre un modèle différent de l'action show de PathController selon si le chemin correspond à une section ou à un article. à savoir

def show 
    if @section = Section.find_by_path!(params[:path]) 
    render :template => 'section/show' 
    elsif @article = Article.find_by_path!(params[:path]) 
    render :template => 'article/show' 
    else 
    # raise exception 
    end 
end 

La raison en est que, alors que vous pouvez créer des instances d'un contrôleur dans une autre, cela ne fonctionnerait pas comme vous voudriez. c'est-à-dire que le second contrôleur n'aurait pas accès à vos paramètres, session, etc. et que le contrôleur appelant n'aurait pas accès aux variables d'instance et aux demandes de rendu effectuées dans le second contrôleur.

+0

mais je vais devoir dupliquer tous les filtres de ces contrôleurs et toutes les actions de show – tig

+0

Quels filtres avez-vous? Peut-être qu'ils peuvent être déplacés vers une super-classe commune ou un mixin parce que vous voulez probablement qu'ils s'appliquent à PathController ainsi que SectionController et ArticleController. Avez-vous déjà montré une section ou un article via SectionController et ArticleController ou est-ce que toutes les requêtes show sont maintenant routées via PathController? – mikej

+0

pour l'instant - restrictions d'accès (article ou section est-il visible publiquement), mais le projet est en cours de développement afin que quelque chose puisse apparaître dans un proche avenir – tig

Questions connexes