Rails Best Practices 1: Fat Model – Skinny Controller

Mantenere un controller scarno (skinny) è una delle cose più importanti per aumentare la leggibilità e la testabilità del codice.
Vediamo dunque alcune pratiche per spostare la logica dal controller al model.

1. Named Scope

In questo primo esempio vediamo come utilizzare le named_scope per definire i metodi di ricerca nel model, semplificando il controller.

Supponiamo di avere un controller dove nel metodo index vogliamo estrarre l’elenco delle auto berline e quello delle station wagon.
La prima implementazione che possiamo ipotizzare è la seguente:

1
2
3
4
5
6
7
8

class CarsController < ApplicationController
def index
@sedan_cars = Car.find(:all,
:conditions => { :category => 'sedan' })
@wagon_cars = Car.find(:all,
:conditions => { :category => 'wagon'})
end
end

Definendo due named_scope nel model Car vediamo come risulti molto più semplice scrivere lo stesso metodo index del controller

1
2
3
4
5
6
7
8
9
10
11

class Car < ActiveRecord::Base
named_scope :sedan, :conditions => { :category => 'sedan' }
named_scope :wagon, :conditions => { :category => 'wagon'}
end

class CarsController < ApplicationController
def index
@sedan_cars = Car.sedan
@wagon_cars = Car.wagon
end
end

La nuova versione del metodo index oltre che più semplice risulta anche più facile da testare.

2. Model Association

Nel secondo esempio voglio mostrarvi come utilizzare le “model association” per semplificare un metodo create.
Supponiamo di avere il classico esempio del blog, in cui dobbiamo creare un nuovo post associato all’utente corrente.
La prima implementazione che si può fare è la seguente:

1
2
3
4
5
6
7

class PostsController < ApplicationController
def create
@post = Post.new(params[:post])
@post.user_id = current_user.id
@post.save
end
end

Definendo una model association di tipo has_many tra utenti e post possiamo semplificare il metodo create come segue:

1
2
3
4
5
6
7
8
9
10

class User < ActiveRecord::Base
has_many :posts
end

class PostsController < ApplicationController
def create
@post = current_user.posts.build(params[:post])
@post.save
end
end

3. Scope Access

Continuando l’esempio del blog, vediamo in questo terzo esempio come si può snellire il metodo di edit usando una scope access.
Nel nostro metodo edit vogliamo permettere la modifica di un post solo se questo appartiene all’utente corrente.
Come il solito, vediamo una prima implementazione:

1
2
3
4
5
6
7
8
9

class PostsController < ApplicationController
def edit
@post = Post.find(params[:id)
if @post.current_user != current_user
flash[:warning] = 'Access denied'
redirect_to posts_url
end
end
end

L’ottimizzazione che si può fare in questo caso è di semplificare il metodo edit in modo tale che se il post non appartiene all’utente corrente venga sollevata un eccezione di tipo RecordNotFound.
Usando la named scope l’intero metodo si riduce ad una sola riga di codice:

1
2
3
4
5

class PostsController < ApplicationController
def edit
@post = current_user.posts.find(params[:id)
end
end

Per questo primo post mi limito a questi esempi. Nel prossimo post di questa serie dedicata alle Rails Best Practices vedremo altri metodi per semplificare i controller e spostare la logica maggiormente nei model.