Un idiom, para aquel que no lo sepa, es [...] a means of expressing a recurring construct in one or more programming languages (o eso dice la wikipedia, así que yo me lo creo).
Ruby es un lenguaje que permite hacer cualquier cosa de muy diversas maneras, por lo que no es de extrañar que existan multitud de idioms para hacer multitud de cosas. El caso concreto que nos ocupa tiene que ver con la asignación condicional o inicialización… ¿perezosa? Nunca recuerdo cómo se traduze (lazy initialization). Vamos, el operador ||=
my_var = nil my_var ||= 5 #=> 5 my_var ||= 7 #=> 5
que viene a ser el forma idiomática de expresar en Ruby la construcción más tradicional
if (my_var != nil) my_var = value end
(para un ejemplo de uso y alguna información adicional importante, ver este post de Jay Fields).
Al grano… al idiom
Con el advenimiento de REST, los controladores Rails han vuelto a la estructura clásica de una acción GET para mostrar un formulario, una acción POST para procesarlo. A la hora de hacer CRUD, lo normal es tener algo similar a esto (para la C en CRUD, por ejemplo):
# GET def new @user = User.new @countries = Country.available_countries @jobs = Job.available_jobs end #POST def create @user = User.create(params[:user]) if @user.save flash[:notice] = 'Yeah!' redirect_to user_path else @countries = Country.available_countries # <= RM (Repeat Myself) @jobs = Job.available_jobs render :action => 'new' end end
Evidentemente, el código anterior no es muy DRY. Estamos duplicando la “preparación” de los datos para renderizar la acción de ‘new’. Un primer impulso nos puede llevar a refactorizar por ahí y extraer un nuevo método que podría ser algo similar a
def prepare_data_for_new_and_edit # Porque para edit también lo necesitaríamos :D @countries = Country.available_countries @jobs = Job.available_jobs end
y utilizar este método para cargar las colecciones necesarias tanto en la acción de ‘new’ como en la de ‘create’. Pero la asignación condicional nos permite hacer algo que, a mi juicio, es más directo y más cómodo (aunque también puede resultar un poco más oscuro): es suficiente con hacer que la asignación de la variable de instancia @user sea condicional en ‘new’ y podremos llamar al método ‘new’ directamente desde ‘create’. En código:
# GET def new @user ||= User.new @countries = Country.available_countries @jobs = Job.available_jobs end #POST def create @user = User.create(params[:user]) if @user.save flash[:notice] = 'Yeah!' redirect_to user_path else new render :action => 'new' end end
En este caso, como en muchos otros, el idiom Ruby conduce a un idiom Rails.