242 votes

Conception OO dans Rails : où mettre les choses

Je suis vraiment profiter de Rails (même si je suis généralement Agité), et j'aime Ruby étant très OO. Encore, la tendance à faire d'énormes ActiveRecord sous-classes et d'énormes contrôleurs est tout à fait naturel (même si vous utilisez un contrôleur par ressource). Si vous deviez créer plus profond objet mondes, où placeriez-vous les classes (et les modules, je suppose)? Je parle de point de vue (dans les Assistants eux-mêmes?), les contrôleurs et les modèles.

Lib est d'accord, et j'ai trouvé quelques solutions pour obtenir pour recharger dans un environnement de dev, mais j'aimerais savoir si il y a une meilleure façon de faire ce genre de choses. Je suis vraiment inquiète pour les classes de devenir trop volumineux. Aussi, ce sujet de Moteurs et comment font-ils?

381voto

Yehuda Katz Points 18277

Parce que les Rails fournit la structure en termes de MVC, il est naturel de se finissent en utilisant seulement le modèle, vue, contrôleur et les conteneurs qui sont fournis pour vous. Le typique idiome pour les débutants (et même certains intermédiaires programmeurs) est à fourrer toute logique dans l'application dans le modèle (classe de base de données), de contrôleur ou de vue.

À un certain moment, quelqu'un fait remarquer le "gras-modèle, skinny-contrôleur" changement de paradigme, les intermédiaires et les développeurs hâte d'accise tout, de leurs contrôleurs et de le jeter dans le modèle, ce qui commence à devenir une nouvelle corbeille pour la logique d'application.

Skinny contrôleurs sont, en fait, une bonne idée, mais le corollaire, mettant tout dans le modèle, n'est pas vraiment le meilleur plan.

En Ruby, vous avez un couple de bonnes options pour rendre les choses plus modulaire. Un assez populaire de réponse est d'utiliser des modules (généralement planqué en lib) qui détiennent des groupes de méthodes, et puis d'inclure les modules dans les classes appropriées. Cela aide dans le cas où vous avez des catégories de fonctionnalités que vous souhaitez réutiliser dans plusieurs classes, mais où la fonctionnalité est toujours en théorie, attaché à la les classes.

Rappelez-vous, lorsque vous inclure un module dans une classe, les méthodes les méthodes d'instance de la classe, si vous avez encore jusqu'à la fin avec une classe contenant une tonne de méthodes, ils sont juste bien organisé en plusieurs fichiers.

Cette solution peut bien fonctionner dans certains cas, dans d'autres cas, vous allez avoir à penser à l'aide de classes dans votre code qui ne sont pas des modèles, vues et contrôleurs.

Une bonne façon de penser, c'est que le "principe de responsabilité unique," qui dit qu'une classe doit être responsable pour une seule personne (ou un petit nombre) des choses. Vos modèles sont responsables de la persistance des données à partir de votre application à la base de données. Vos contrôleurs sont responsables de la réception et de la demande et de renvoyer une réponse viable.

Si vous avez des concepts qui n'entrent pas dans les cases (persistance, à la demande/réponse de la direction), vous avez certainement envie de penser à comment vous serait le modèle de l'idée en question. Vous pouvez stocker des classes de modèle dans app/classes, ou n'importe où ailleurs, et ajouter ce répertoire à votre charge chemin en faisant:

config.load_paths << File.join(Rails.root, "app", "classes")

Si vous êtes à l'aide de passagers ou de JRuby, vous avez probablement vous aussi vous souhaitez ajouter votre chemin à la hâte les chemins de chargement:

config.eager_load_paths << File.join(Rails.root, "app", "classes")

La ligne de fond est que, une fois que vous arrivez à un point dans les Rails où vous vous posez cette question, il est temps de renforcer votre Ruby de côtelettes et de commencer la modélisation de classes qui ne sont pas seulement les classes MVC Rails, vous donne par défaut.

Mise à jour: Cette réponse s'applique aux Rails 2.x et supérieur.

62voto

Simone Carletti Points 77653

Mise à jour: L'utilisation des Préoccupations ont été confirmé que la nouvelle valeur par défaut dans les Rails 4.

Cela dépend vraiment de la nature du module lui-même. J'ai l'habitude de placer contrôleur/extensions du modèle dans un /des préoccupations dossier au sein de l'app.

# concerns/authentication.rb
module Authentication
  ...
end    

# controllers/application_controller.rb
class ApplicationController
  include Authentication
end



# concerns/configurable.rb
module Configurable
  ...
end    

class Model 
  include Indexable
end 

# controllers/foo_controller.rb
class FooController < ApplicationController
  include Indexable
end

# controllers/bar_controller.rb
class BarController < ApplicationController
  include Indexable
end

/lib est mon préféré pour l'usage général des bibliothèques. J'ai toujours un projet d'espace de noms dans le répertoire lib où j'ai mis toutes les applications spécifiques des bibliothèques.

/lib/myapp.rb
module MyApp
  VERSION = ...
end

/lib/myapp/CacheKey.rb
/lib/myapp/somecustomlib.rb

Ruby/Rails de base extensions ont généralement lieu dans les config des initialiseurs de sorte que les bibliothèques ne sont chargés une fois sur les Rails de bootstrap.

/config/initializer/config.rb
/config/initializer/core_ext/string.rb
/config/initializer/core_ext/array.rb

Pour réutilisables fragments de code, j'ai souvent créer des (micro)des plugins afin que je puisse les réutiliser dans d'autres projets.

Les fichiers d'aide tient généralement les méthodes d'assistance et parfois des classes lorsque l'objet est destiné à être utilisé par des aides (par exemple Constructeurs de Forme).

C'est vraiment un aperçu général. Veuillez fournir plus de détails sur des exemples précis si vous souhaitez obtenir plus de suggestions personnalisées. :)

10voto

Mike Woodhouse Points 27748

... la tendance à faire d'énormes ActiveRecord sous-classes et d'énormes les contrôleurs est tout à fait naturel ...

"énorme" est juste un mot... ;-)

Comment sont vos contrôleurs de devenir énorme? C'est quelque chose que vous devriez regarder: idéalement, les contrôleurs doivent être fines. Sélection d'une règle-de-pouce hors de l'air mince, je proposerais que si vous avez régulièrement plus de, disons, 5 ou 6 lignes de code par la méthode du contrôleur (action), alors vos contrôleurs sont probablement trop gras. Est-il double emploi qui pourraient se déplacer dans une fonction d'assistance ou un filtre? Est-il logique d'entreprise qui pourrait être poussé vers le bas dans les modèles?

Comment vos modèles d'arriver à être énorme? Devriez-vous être à la recherche des moyens de réduire le nombre de responsabilités dans chaque classe? Existe-il des comportements fréquents, vous pouvez extraire dans mixin? Ou des zones de fonctionnalités que vous pouvez déléguer à des classes d'aide?

EDIT: en Essayant de développer un peu, j'espère ne pas déformer quoi que ce soit trop mal...

Helpers: vivre en app/helpers et sont principalement utilisés pour faire des vues plus simple. Un contrôleur spécifique (également disponible à tous les points de vue pour que le contrôleur) ou généralement disponibles (module ApplicationHelper dans application_helper.rb).

Filtres: Disons que vous avez la même ligne de code dans plusieurs actions (assez souvent, la récupération d'un objet à l'aide d' params[:id] ou similaire). Cette duplication peut être abstrait d'abord à une méthode distincte, et ensuite sur les actions entièrement en déclarant un filtre dans la définition de la classe, comme before_filter :get_object. Voir la Section 6 du ActionController Rails de Guide de Laisser de programmation déclarative être votre ami.

Refactoring de modèles est un peu plus d'une chose religieuse. Les Disciples de l'Oncle Bob va suggérer, par exemple, que vous suivez les Cinq Commandements de SOLIDE. Joel & Jeff peut recommander un plus, er, approche "pragmatique", même s'ils ne le semblent être un peu plus facilement par la suite. Trouver un ou plusieurs des méthodes dans une classe, qui fonctionnent dans un cadre clairement défini sous-ensemble de ses attributs est une façon d'essayer d'identifier les classes qui pourraient être remaniée de votre ActiveRecord-modèle dérivé.

Rails de modèles n'ont pas à être des sous-classes de ActiveRecord::Base, par la manière. Ou pour le dire d'une autre façon, un modèle n'a pas à être un analogue d'un tableau, ou même lié à tout ce qui est stocké à tous. Mieux encore, aussi longtemps que vous le nom de votre fichier dans app/models selon Rails de conventions (appel #trait de soulignement sur le nom de la classe pour savoir ce que les Rails rechercher), Rails trouverez sans aucun requires est nécessaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X