FrPlugin Tutorial » History » Version 2
Robert Tome, 2013-03-21 10:16
1 | 1 | Romain GEORGES | h1. Tutoriel du plugin Polls |
---|---|---|---|
2 | |||
3 | Remarque : Pour suivre ce tutoriel, vous devez avoir installé Redmine devel r1786 ou supérieur. |
||
4 | |||
5 | {{>toc}} |
||
6 | |||
7 | h2. Créer un nouveau plugin |
||
8 | |||
9 | Vous devez préalablement initialiser la variable RAILS_ENV sur "production" dans votre session shell pour continuer le tutotiel, pour ce faire, tapez : |
||
10 | |||
11 | <pre> |
||
12 | $ export RAILS_ENV="production" |
||
13 | </pre> |
||
14 | |||
15 | Pour créer un plugin Redmine, il existe des generateur pour les taches essentielles. |
||
16 | |||
17 | La syntaxe des générateurs est : |
||
18 | |||
19 | <pre>ruby script/generate redmine_plugin <plugin_name></pre> |
||
20 | |||
21 | pour commencer, on va se positionner dans le répertoire de l'application Rails Redmine, puis créer la structure du plugin : |
||
22 | |||
23 | % ruby script/generate redmine_plugin Polls |
||
24 | |||
25 | La structure du plugin est créé dans le repertoire @vendor/plugins/redmine_polls@: |
||
26 | |||
27 | <pre> |
||
28 | create vendor/plugins/redmine_polls/app/controllers |
||
29 | create vendor/plugins/redmine_polls/app/helpers |
||
30 | create vendor/plugins/redmine_polls/app/models |
||
31 | create vendor/plugins/redmine_polls/app/views |
||
32 | create vendor/plugins/redmine_polls/db/migrate |
||
33 | create vendor/plugins/redmine_polls/lib/tasks |
||
34 | create vendor/plugins/redmine_polls/assets/images |
||
35 | create vendor/plugins/redmine_polls/assets/javascripts |
||
36 | create vendor/plugins/redmine_polls/assets/stylesheets |
||
37 | create vendor/plugins/redmine_polls/lang |
||
38 | create vendor/plugins/redmine_polls/README |
||
39 | create vendor/plugins/redmine_polls/init.rb |
||
40 | create vendor/plugins/redmine_polls/lang/en.yml |
||
41 | </pre> |
||
42 | |||
43 | Editer @vendor/plugins/redmine_polls/init.rb@ pour adjuster les informations (attributs) du plugin (nom, auteur, description et version): |
||
44 | |||
45 | <pre><code class="ruby"> |
||
46 | require 'redmine' |
||
47 | |||
48 | Redmine::Plugin.register :redmine_polls do |
||
49 | name 'Polls plugin' |
||
50 | author 'John Smith' |
||
51 | description 'A plugin for managing polls' |
||
52 | version '0.0.1' |
||
53 | end |
||
54 | </code></pre> |
||
55 | |||
56 | Redemarrez l'application Redmine et ouvrez un navigateur sur l'URL http://localhost:3000/admin/plugins. |
||
57 | |||
58 | Après vous être loggué avec les droits d'administrateur Redmine, vous devriez voir la liste des plugins tel que : |
||
59 | |||
60 | !plugins_list1.png! |
||
61 | |||
62 | h2. Générer un modèle Rails de plugin Redmine |
||
63 | |||
64 | pour le moment le plugin ne persiste aucuns résultats |
||
65 | Nous allons donc créer un modèle Poll simple, tel que : |
||
66 | |||
67 | <pre> |
||
68 | ruby script/generate redmine_plugin_model <plugin_name> <model_name> [<fields>] |
||
69 | </pre> |
||
70 | |||
71 | La commande exacte pour notre cas sera : |
||
72 | |||
73 | <pre> |
||
74 | ruby script/generate redmine_plugin_model polls poll question:string yes:integer no:integer |
||
75 | </pre> |
||
76 | |||
77 | cette commande crée le modèle Rails Poll et les fichiers de migration correspondant |
||
78 | |||
79 | *Remarque : Il est possible que vous deviez renommer les fichiers de migration, les migrations avec des timestamps ne sont pas supportée par le moteur Redmine Actuelle, Si les migrations portent une numérotation avec des timestamps, renommez-les avec "001" "002", etc... |
||
80 | |||
81 | |||
82 | <pre>cd vendor/plugins/redmine_polls/db/migrate |
||
83 | mv 20091009211553_create_polls.rb 001_create_polls.rb |
||
84 | cd ../../../../..</pre> |
||
85 | |||
86 | Si vous avez déja executé une migration, vous devez mettre à jour les informations dans la table plugin_schema_info en adequation avec la nouvelle numérotation. |
||
87 | |||
88 | Migrer la base de données avec la commande : |
||
89 | |||
90 | rake db:migrate_plugins |
||
91 | |||
92 | Il est à noter que chaque plugin à son propre jeux de migration. |
||
93 | |||
94 | Nous allons ajouter des Votes via la console rails pour pouvoir faire des tests avec. |
||
95 | La console Rails permet l'ajout interactif d'enregistrement sur les modèles rails, c'est une shell Ruby Irb, qui pré-charge l'environnement de l'application rails depuis laquelle il est lancé. |
||
96 | Pour le moment nous allons juste créer un objet Poll |
||
97 | |||
98 | |||
99 | |||
100 | <pre> |
||
101 | script/console |
||
102 | >> Poll.create(:question => "Pouvez-vous voir ce vote ?") |
||
103 | >> Poll.create(:question => "Pouvez-vous voir cet autre vote ?") |
||
104 | >> exit |
||
105 | </pre> |
||
106 | |||
107 | Editez @vendor/plugins/redmine_polls/app/models/poll.rb@ dans le répertoire de votre plugin et ajoutez une méthode #vote qui sera appelée par votre controller: |
||
108 | |||
109 | <pre><code class="ruby"> |
||
110 | class Poll < ActiveRecord::Base |
||
111 | def vote(answer) |
||
112 | increment(answer == 'yes' ? :yes : :no) |
||
113 | end |
||
114 | end |
||
115 | </code></pre> |
||
116 | |||
117 | h2. Generer un controller |
||
118 | |||
119 | Pour le moment le plugins ne fait rien, donc nous allons créer un controller Rails pour celui-ci. |
||
120 | Nous pouvons utiliser le générateur Redmine prévue à cet effet : |
||
121 | |||
122 | <pre>ruby script/generate redmine_plugin_controller <plugin_name> <controller_name> [<actions>]</pre> |
||
123 | |||
124 | la commande exacte pour notre cas est : |
||
125 | |||
126 | <pre> |
||
127 | % ruby script/generate redmine_plugin_controller Polls polls index vote |
||
128 | exists app/controllers/ |
||
129 | exists app/helpers/ |
||
130 | create app/views/polls |
||
131 | create test/functional/ |
||
132 | create app/controllers/polls_controller.rb |
||
133 | create test/functional/polls_controller_test.rb |
||
134 | create app/helpers/polls_helper.rb |
||
135 | create app/views/polls/index.html.erb |
||
136 | create app/views/polls/vote.html.erb |
||
137 | </pre> |
||
138 | |||
139 | un controlleur Rails @PollsController@ avec 2 actions (@#index@ et @#vote@) vient d'être créé. |
||
140 | |||
141 | Editez @vendor/plugins/redmine_polls/app/controllers/polls_controller.rb@ dans le répertoire @redmine_polls@ pour implémenter ces deux actions. |
||
142 | |||
143 | <pre><code class="ruby"> |
||
144 | class PollsController < ApplicationController |
||
145 | unloadable |
||
146 | |||
147 | def index |
||
148 | @polls = Poll.find(:all) |
||
149 | end |
||
150 | |||
151 | def vote |
||
152 | poll = Poll.find(params[:id]) |
||
153 | poll.vote(params[:answer]) |
||
154 | if poll.save |
||
155 | flash[:notice] = 'Vote saved.' |
||
156 | redirect_to :action => 'index' |
||
157 | end |
||
158 | end |
||
159 | end |
||
160 | </code></pre> |
||
161 | |||
162 | Ensuite, editez la vue @vendor/plugins/redmine_polls/app/views/polls/index.html.erb@ qui va afficher les votes existants. |
||
163 | |||
164 | |||
165 | <pre> |
||
166 | <h2>Polls</h2> |
||
167 | |||
168 | <% @polls.each do |poll| %> |
||
169 | <p> |
||
170 | <%= poll[:question] %>? |
||
171 | <%= link_to 'Yes', {:action => 'vote', :id => poll[:id], :answer => 'yes'}, :method => :post %> (<%= poll[:yes] %>) / |
||
172 | <%= link_to 'No', {:action => 'vote', :id => poll[:id], :answer => 'no'}, :method => :post %> (<%= poll[:no] %>) |
||
173 | </p> |
||
174 | <% end %> |
||
175 | </pre> |
||
176 | |||
177 | Vous pouvez supprimer la vue @vendor/plugins/redmine_polls/app/views/polls/vote.html.erb@ comme il n'y a pas de rendu pour l'action correspondante. |
||
178 | |||
179 | Redemarreez le serveur Rails de Redmine et ouvrez votre navigateur sur l'URL http://localhost:3000/polls. |
||
180 | Vous devriez voir deux votes et vous pouvez les essailler : |
||
181 | |||
182 | !pools1.png! |
||
183 | |||
184 | Remarque : les resultats des votes sont remis à zero à chaque requête si vous ne lancez pas votre application en environnement "production", vue que le modèle Poll est stocké dans une variable de classe dans notre exemple. |
||
185 | |||
186 | |||
187 | h2. Traductions |
||
188 | |||
189 | L'emplacement des fichiers YAML d'internationalisation peut varier en fonction de votre version de Redmine : |
||
190 | |||
191 | |_. Version |_. Path| |
||
192 | | < 0.9 | @.../redmine_polls/lang@ | |
||
193 | | >= 0.9 | @.../redmine_polls/config/locales@ | |
||
194 | |||
195 | Si vous voulez que votre plugin marche dans les deux cas vous devez ajouter les fichiers dans les deux cas au bon format. |
||
196 | |||
197 | |||
198 | h2. Gestion des menus |
||
199 | |||
200 | Notre controller marche bien, mais nos utilisateurs n'en connaissent pas l'existence, il faut donc utilser l'API Redmine pour etendre les menus |
||
201 | 2 | Robert Tome | Nous allons ajouter un onglet au menu Application |
202 | 1 | Romain GEORGES | So let's add a new item to the application menu. |
203 | |||
204 | h3. Gestion du menu application |
||
205 | |||
206 | Editez le fichier @vendor/plugins/redmine_polls/init.rb@ à la racine de votre plugin et ajoutez la ligne suivante dans le bloc ""registration"" : |
||
207 | |||
208 | <pre><code class="ruby"> |
||
209 | Redmine::Plugin.register :redmine_polls do |
||
210 | [...] |
||
211 | |||
212 | menu :application_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls' |
||
213 | end |
||
214 | </code></pre> |
||
215 | |||
216 | la syntaxe est : |
||
217 | |||
218 | menu(menu_name, item_name, url, options={}) |
||
219 | |||
220 | Il y a cinq menu dans Redmine que vous pouvez étendre : |
||
221 | |||
222 | * @:top_menu@ - le menu en haut à gauche |
||
223 | * @:account_menu@ - le menu en haut à droite avec la gestion des comptes et connexions |
||
224 | * @:application_menu@ - Le menu affiché quand un utilisateur n'est dans aucuns projets. |
||
225 | * @:project_menu@ - Le menu affiché quand un utilisateur est dans un projet. |
||
226 | * @:admin_menu@ - le menu d'administration |
||
227 | |||
228 | 2 | Robert Tome | les options disponibles sont : |
229 | 1 | Romain GEORGES | |
230 | * @:param@ - la clef parametre utilisée pour les id de projet (valeur par défaut @:id@) |
||
231 | * @:if@ - un Proc appelé avant de faire le rendu du menu,l'item est affiché que si le Proc retourne true |
||
232 | * @:caption@ - Le label du menu du type: |
||
233 | |||
234 | * un symbole de chaine de caratères localisée |
||
235 | * une chaine de caratères |
||
236 | * un Proc qui peut pendre le project_id en argument |
||
237 | |||
238 | * @:before@, @:after@ - specifie ou l'item du menu doit être inséré (ex. @:after => :activity@) |
||
239 | * @:first@, @:last@ - si ils sont true, l'item est positionné au début ou a la fin du menu (ex. @:last => true@) |
||
240 | * @:html@ - un hachage d'options html passés à @link_to@ pour le rendu du menuitem |
||
241 | |||
242 | Dans notre exemple, nous avons ajoutez un item au menu application, qui est vide par defaut. |
||
243 | |||
244 | Redemarrez l'application et allez à l'URL http://localhost:3000: |
||
245 | |||
246 | !application_menu.png! |
||
247 | |||
248 | Maintenant vous pouvez accéder aux votes en cliquant sur l'onglet Polls depuis l'ecran d'accueil de Redmine |
||
249 | |||
250 | h3. Etendre le menu projet |
||
251 | |||
252 | On va considérer, mantenant que les votes sont définis au niveau des projets (même si ce n'est pas le cas dans le modèle de notre exemple) |
||
253 | Donc, on veut ajouter l'onglet au menu Projet et plus au menu Application. |
||
254 | |||
255 | Editez le fichier @init.rb@ et replacez la dernière ligne que nous avons ajoutez par les deux lignes suivantes : |
||
256 | |||
257 | <pre><code class="ruby"> |
||
258 | Redmine::Plugin.register :redmine_polls do |
||
259 | [...] |
||
260 | |||
261 | permission :polls, {:polls => [:index, :vote]}, :public => true |
||
262 | menu :project_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls', :after => :activity, :param => :project_id |
||
263 | end |
||
264 | </code></pre> |
||
265 | |||
266 | |||
267 | la deuxième ligne ajoute l'onglet Polls dans le menu Projet juste derrière l'onglet Activité. |
||
268 | la première ligne sert à déclarer que nos deux actions du @PollsController@ sont publiques. |
||
269 | Nous reviendrons plus tard sur les permissions. |
||
270 | |||
271 | Redémarrez encore l'application et entrez dans un de vos projets: |
||
272 | |||
273 | !http://www.redmine.org/attachments/3773/project_menu.png! |
||
274 | |||
275 | If you click the Polls tab, you should notice that the project menu is no longer displayed. |
||
276 | To make the project menu visible, you have to initialize the controller's instance variable @@project@. |
||
277 | |||
278 | Si vous cliquez sur l'onglet Polls, vous constatez que le menu projet n'est plus affiché. |
||
279 | 2 | Robert Tome | Pour continuer à l'afficher, nous devons initier la variable d'instance @@project@ du controlleur. |
280 | 1 | Romain GEORGES | |
281 | Editez votre PollsController tel que: |
||
282 | |||
283 | <pre><code class="ruby"> |
||
284 | def index |
||
285 | @project = Project.find(params[:project_id]) |
||
286 | @polls = Poll.find(:all) # @project.polls |
||
287 | end |
||
288 | </code></pre> |
||
289 | |||
290 | L'id du projet est disponible dans @:project_id@ grace à l'option @:param => :project_id@ dans la déclaration du menu item précédante. |
||
291 | |||
292 | Maintenant, vous devriez continuer à voir le menu projet quand vous visualisez un vote : |
||
293 | |||
294 | |||
295 | |||
296 | !http://www.redmine.org/attachments/3774/project_menu_pools.png! |
||
297 | |||
298 | h2. Ajouter des nouvelles permissions |
||
299 | |||
300 | Pour le moment, tout le monde peut voter. |
||
301 | On peut rendre ceci configurable en ajoutant des permissions Redmine. |
||
302 | Nous allons definir deux permissions au niveau Projet, une pour visualiser et une pour voter. |
||
303 | Ces permissions ne seront donc plus publiques (l'option @:public => true@ disparait) |
||
304 | |||
305 | |||
306 | Editez @vendor/plugins/redmine_polls/init.rb@ pour remplacer la permission précedante avec les deux lignes suivantes : |
||
307 | |||
308 | <pre><code class="ruby"> |
||
309 | |||
310 | permission :view_polls, :polls => :index |
||
311 | permission :vote_polls, :polls => :vote |
||
312 | </code></pre> |
||
313 | |||
314 | Redemarrez l'application et allez à l'URL http://localhost:3000/roles/report: |
||
315 | |||
316 | |||
317 | !permissions1.png! |
||
318 | |||
319 | on voit donc deux permissions de plus ajoutable à votre role. |
||
320 | Biensur, il va falloir ajouter du code au PollsController, donc ces actions sont pour le moment protégé par les permissions de l'utilisateur courant. |
||
321 | |||
322 | Pour cela, nous avons juste à ajouter le filtre @:authorize@ et faire en sorte que la variable d'instance @project est initialisée avant d'appeler ce filtre |
||
323 | |||
324 | Voici à quoi ça doit ressembler dans l'action @#index@ : |
||
325 | |||
326 | |||
327 | <pre><code class="ruby"> |
||
328 | class PollsController < ApplicationController |
||
329 | unloadable |
||
330 | |||
331 | before_filter :find_project, :authorize, :only => :index |
||
332 | |||
333 | [...] |
||
334 | |||
335 | def index |
||
336 | @polls = Poll.find(:all) # @project.polls |
||
337 | end |
||
338 | |||
339 | [...] |
||
340 | |||
341 | private |
||
342 | |||
343 | def find_project |
||
344 | # @project variable must be set before calling the authorize filter |
||
345 | @project = Project.find(params[:project_id]) |
||
346 | end |
||
347 | end |
||
348 | </code></pre> |
||
349 | |||
350 | Récupérer le projet courant avant le @#vote@ peut-être fait de façon très similaire. |
||
351 | Après ça, voir un vote et voter ne sera accessible qu'aux administrateur ou aux utilisateurs que on un rôle approprié dnas le projet. |
||
352 | |||
353 | Pour traduire les symboles de vos permissions dans plusieurs langues, vous devez ajouter les labels de textes necessaires dans vos fichiers de langues tel que : |
||
354 | labels like this: |
||
355 | |||
356 | <pre><code class="ruby"> |
||
357 | |||
358 | permission_view_polls: Voir les votes |
||
359 | permission_vote_polls: Voter |
||
360 | |||
361 | </code></pre> |
||
362 | |||
363 | Dans cette exemple, on a créé le fichier fr.yml, mais on peut créer des fichiers pour toutes les langues que l'on souhaite. |
||
364 | |||
365 | On voit dans cette exemple, que le lable est le symbole de la permission @:view_polls@ et @:vote_polls@ préfixé de @permission_@ |
||
366 | |||
367 | |||
368 | Redemarrez votre application et pointer sur la section permissions. |
||
369 | |||
370 | h2. Créer un module de projets |
||
371 | |||
372 | Pour le moment, la fonctionnalité de vote est ajoutée à tous vos projets, mais on souhaite la rendre activable ou désactivable pour chaque projet. |
||
373 | On va donc créer un module de projet 'Polls'. |
||
374 | On fait ceci en inclant les permissions dans un bloc @#project_module@. |
||
375 | |||
376 | |||
377 | Editez @init.rb@ et changez la déclaration des permissions : |
||
378 | |||
379 | <pre><code class="ruby"> |
||
380 | project_module :polls do |
||
381 | permission :view_polls, :polls => :index |
||
382 | permission :vote_polls, :polls => :vote |
||
383 | end |
||
384 | </code></pre> |
||
385 | |||
386 | Redemarrez votre application et pointer sur un de vos projet dans sa configuration. |
||
387 | Cliquez sur l'onglet Modules, vous y verez le module Polls à la fin de la liste de modules, désactivé par defaut. |
||
388 | |||
389 | !modules.png! |
||
390 | |||
391 | Vous pouvez l'activer ou le désactiver pour chaque projet. |
||
392 | |||
393 | |||
394 | h2. Améliorer la vue du plugin |
||
395 | |||
396 | h3. Ajouter des Styles CSS |
||
397 | |||
398 | On va commencer par ajouter un CSS à notre vue |
||
399 | |||
400 | Créez un fichier nommé @voting.css@ dans le répertoire @vendor/plugins/redmine_polls/assets/stylesheets@ : |
||
401 | |||
402 | <pre> |
||
403 | a.vote { font-size: 120%; } |
||
404 | a.vote.yes { color: green; } |
||
405 | a.vote.no { color: red; } |
||
406 | </pre> |
||
407 | |||
408 | Quand on redemarrer l'application, les plugin assets sont copié dans @public/plugin_assets/redmine_polls/@ |
||
409 | par le moteur de Rails pour les rendrent disponibles via votre serveur Web. |
||
410 | Donc toute modification des CSS des plugins impliques un redemarrage de Rails. |
||
411 | Ensuite, on va devoir ajouter les lignes suivantes dans la vue @vendor/plugins/redmine_polls/app/views/polls/index.html.erb@ pour que nos CSS soient pris en compte et incluent dans le header de cette vue par Redmine : |
||
412 | |||
413 | |||
414 | <pre> |
||
415 | <% content_for :header_tags do %> |
||
416 | <%= stylesheet_link_tag 'voting', :plugin => 'redmine_polls' %> |
||
417 | <% end %> |
||
418 | </pre> |
||
419 | |||
420 | Notez que l'option @:plugin => 'redmine_polls'@ est requise quand on appelle le helper @stylesheet_link_tag@. |
||
421 | |||
422 | Les Javascripts peuvent être inclut dans le plugin en utilisant le helper @javascript_include_tag@ de la même manière. |
||
423 | |||
424 | h3. Modifier le titre de la page |
||
425 | |||
426 | on peut modifier le titre HTML de la page depuis le vue elle-même grace au helper @html_title@ |
||
427 | Exemple: |
||
428 | |||
429 | <% html_title "Polls" -%> |
||
430 | |||
431 | |||
432 | h2. Tester votre plugin |
||
433 | |||
434 | h3. test/test_helper.rb: |
||
435 | |||
436 | Voici le contenu de mon fichier de tests : |
||
437 | |||
438 | <pre> |
||
439 | require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper') |
||
440 | </pre> |
||
441 | |||
442 | h3. Exemple de test: |
||
443 | |||
444 | Contenu de requirements_controller_test.rb: |
||
445 | |||
446 | <pre> |
||
447 | require File.dirname(__FILE__) + '/../test_helper' |
||
448 | require 'requirements_controller' |
||
449 | |||
450 | class RequirementsControllerTest < ActionController::TestCase |
||
451 | fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details, |
||
452 | :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, |
||
453 | :attachments, :custom_fields, :custom_values, :time_entries |
||
454 | |||
455 | def setup |
||
456 | @skill = Skill.new(:skill_name => 'Java') |
||
457 | @project = Project.find(1) |
||
458 | @request = ActionController::TestRequest.new |
||
459 | @response = ActionController::TestResponse.new |
||
460 | User.current = nil |
||
461 | end |
||
462 | |||
463 | def test_routing |
||
464 | assert_routing( |
||
465 | {:method => :get, :path => '/requirements'}, |
||
466 | :controller => 'requirements', :action => 'index' |
||
467 | ) |
||
468 | end |
||
469 | </pre> |
||
470 | |||
471 | h3. Initialisation de la base de test : |
||
472 | |||
473 | Il semble plus facile d'initialiser la base de tests directement par la commande rake : |
||
474 | |||
475 | <pre> |
||
476 | rake db:drop db:create db:migrate db:migrate_plugins redmine:load_default_data RAILS_ENV=test |
||
477 | </pre> |
||
478 | |||
479 | h3. Executer les tests: |
||
480 | |||
481 | Pour executer the requirements_controller_test.rb on utilise la commande suivante : |
||
482 | |||
483 | <pre> |
||
484 | rake test:engines:all PLUGIN=redmine_requirements |
||
485 | </pre> |
||
486 | |||
487 | h3. Tester avec des utilisateurs et des projets |
||
488 | |||
489 | If your plugin requires membership to a project, add the following to the beginning of your functional tests: |
||
490 | |||
491 | Si votre plugin requière de appartenances à un projet, ajouter les lignes suivantes pour que ce soit opérationnel : |
||
492 | |||
493 | <pre> |
||
494 | def setup |
||
495 | @request = ActionController::TestRequest.new |
||
496 | @response = ActionController::TestResponse.new |
||
497 | User.current = nil |
||
498 | end |
||
499 | |||
500 | def test_index |
||
501 | @request.session[:user_id] = 2 |
||
502 | get :index, :project_id => 1 |
||
503 | assert_response :success |
||
504 | assert_template :index |
||
505 | end |
||
506 | </pre> |