Comprobar si una relacíon contiene un elemento
Muchas veces cuando trabajamos con ActiveRecord nos olvidamos / ignoramos qué hace por debajo.
Un claro ejemplo lo encontramos cuando tenemos una relación :has_many y queremos comprobar si un elemento está incluída en dicha relación.
Por ejemplo:
class Place < ActiveRecord::Base has_many :items end
class Item < ActiveRecord::Base belongs_to :place end
Seguro que más de una vez, para comprobar que un place contiene un ítem hemos utilizado el "rubysta" include?:
place.items.include?(item)
Pensándolo fríamente 0.2 segundos nos damos cuenta de que estamos cargando un array con todos los elementos de una relación, que pueden ser 10 o pueden ser 1.000.000. Y ya sabemos lo generoso que es Ruby con la memoria que toma y que nunca deja ir.
Un truco para evitar que esto suceda sin dejar de utilizar include? es definir dicho método dentro de la relación tal que así:
class Place < ActiveRecord::Base has_many :items do def include?(item) count(:conditions => ["item_id = ?", item.id]) > 0 end end end
Es decir, resolvemos el problema con un simple COUNT de Mysql.
¿Alguien se anima a hacer un plugin? Creo que sería bastante inmediato para cuando se cumplen las convenciones y sabemos que la clave foránea de la relación es singular del nombre de la relación_id. O quizá ni eso, si encontramos la forma de preguntarle a ActiveRecord cuál es la clave foránea de una relación.
