Rails Best Practices 6: Filtri e file helper

Con il post di oggi intendo concludere la mia serie sulle best practices di Ruby On Rails. Questo non perchè gli argomenti da trattare siano terminati, quanto piuttosto perchè dopo il rilascio della versione 3.0 di Rails alcune cose cambiano e vanno riviste.
Probabilmente in futuro torneremo a parlare di best practices, basandoci però sulle novità introdotte dall’ultima versione.
Prima però voglio descrivere due tecniche che restano valide e che sono legate principalmente all’organizzazione del proprio codice.

1. Uso dei filtri
Al fine di rimuovere codice duplicato all’interno dei controller è buona pratica utilizzare i filtri per far eseguire quelle operazioni comuni a più metodi se non a tutti.
Un caso classico di utilizzo si ha ad esempio per gestire metodi in cui sia necessaria l’autenticazione dell’utente.
Un altro esempio può essere una funzione che fa il log delle attività degli utenti.
Vediamo un esempio molto semplice e a solo scopo dimostrativo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

class ApplicationController < ActionController::Base

def add_log
#create new log
log = ActivityLog.new
# read data from request
log.session_id = request.session_options[ :id]
log.user_id = current_user.id
log.browser = request.env['HTTP_USER_AGENT']
log.ip_address = request.env['REMOTE_ADDR']
log.controller = controller_name
log.action = action_name
log.request_at = Time.now
# Save the log
log.save
end

#other methods here

end

Abbiamo definito la nostra funzione add_log che salva su db un log con i dati della request.
Ora nei nostri controller faremo qualcosa del tipo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

class PostController < ApplicationController

def index
add_log
@posts = Post.all
end

def new
add_log
@post = Post.new
end

def show
add_log
@post = Post.find(params[ :id]
end

def edit
add_log
@post = Post.find(params[ :id]
end

def create
add_log
@post = Post.create(params[:post]
end

def update
add_log
@post = Post.update(params[:post]
end

def destroy
add_log
@post = Post.find(params[ :id]
@post.destroy
end
end

Il PostController può essere ottimizzato utilizzando un before_filter nel seguente modo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

class PostController < ApplicationController

before_filter :add_log

def index
@posts = Post.all
end

def new
@post = Post.new
end

def show
@post = Post.find(params[ :id]
end

def edit
@post = Post.find(params[ :id]
end

def create
@post = Post.create(params[:post]
end

def update
@post = Post.update(params[:post]
end

def destroy
@post = Post.find(params[ :id]
@post.destroy
end
end

Se vogliamo poi che le chiamate ad alcuni metodi (ad esempio show e index) non vengano tracciate possiamo semplicemente definire il filtro come segue

1
2
3
4
5

class PostController < ApplicationController

before_filter :add_log, :except => [:show, :index]

# methods

Ovviamente l’utilizzo dei filtri va fatto in modo attento poiché un eccessivo uso di before_filter o after_filter per operazioni non troppo generiche può rendere il codice meno immediato da comprendere.

2. Organizzare i file di helper per funzionalità
La seconda tecnica che voglio presentarvi oggi è solo un miglior sistema (a mio avviso) di organizzare i file di helper.

Tipicamente Rails genera un file helper per ogni controller per cui è facile trovarsi in poco tempo ad avere numerosi file di hepler e molto spesso utilizzarne solo pochi.
Ad esempio:

1
2
3
4
5

app/helpers/application_helper.rb
app/helpers/comments_helper.rb
app/helpers/posts_helper.rb
app/helpers/users_helper.rb
# ...

E nell’ApplicationController:

1
2
3

class ApplicationController < ActionController::Base
helper :all # include all helpers, all the time
end

Un sistema che io trovo molto comodo è invece organizzare gli helper per funzionalità, rimuovendo poi tutti i file vuoti ed inutili.

1
2
3

app/helpers/application_helper.rb
app/helpers/buttons_helper.rb
app/helpers/treeviews_helper.rb

Nell’ApplicationController non è necessario modificare nulla in quanto come prima caricherà tutti gli helper presenti nella cartella helpers. Il vantaggio di questa soluzione è quello di avere meno file helper e di sapere subito dove inserire o cercare un metodo quando lo si deve aggiungere o modificare.