🎯 Intention


Les scopes en Rails reprĂ©sente la passerelle entre le langage mĂ©tier et une requĂȘte SQL.

L’objectif est que chacun(e) sache comment Ă©crire un bon scope et le tester

<aside> ✅ PrĂ©-requis

✅ Points clĂ©s


<aside> ⌛ Temps indicatif : 30min

</aside>

Etape

Visuel / Exemple


✍ CrĂ©er un scope

Raison :

En utilisant le vocabulaire métier, il suffit de reprendre les mots du product owner en appelant les scopes pour réaliser sa demande.

Extraire une partie de la requĂȘte SQL permet aussi de simplifier l’écriture de test

scope :pour_le_jour, ->(*jours) { where('EXTRACT(ISODOW FROM date) IN (?)', jours.flatten) }
scope :uniquement_le_lundi,    -> { pour_le_jour(1) }

scope :sans_photo_detouree, -> { where.missing(:photo_detouree_attachment) }

# Ici on place la compléxité dans ce scope
# Le nom reprend les termes exactes données par le Product Owner
scope :pour_meteo_du_jour,
        lambda { |utilisateur|
          meteo = Meteo.du_jour.pour_utilisateur(utilisateur).first

          if meteo
            where('temperature_maximale >= ?', meteo.temperature_max)
              .where('temperature_minimale <= ?', meteo.temperature_min)
              .where('ARRAY[?] && conditions_meteo::text[]', meteo.temps)
          end
        }

🟱 Tester un scope

Raison :

Il s’agit de test d’intĂ©gration (et non unitaire !) car ces tests utilisent la base de donnĂ©e.

Le . avant le nom_du_scope dans le describe indique que l’on test une mĂ©thode de class

describe '.pour_meteo_du_jour' do
	# on évite de trop créer d'objet en amont pour la maintenabilité
	# on extrait la logique des context dans les [traits](<https://thoughtbot.com/blog/remove-duplication-with-factorybots-traits>)
  let(:utilisateur) { create(:utilisateur) }
	let!(:template_tenue) { create(:template_tenue, :ensoleille) }
  let(:resultat) { described_class.pour_meteo_du_jour(utilisateur) }

	# cas positif 👍
  context "quand l'utilisateur a une météo du jour" do
		before(:each) { create :meteo, :ensoleille, utilisateur: utilisateur }

    it 'retourne le template' do
      expect(resultat).to include template_tenue
    end
  end

	# cas nĂ©gatif 👎
  context "quand l'utilisateur a une météo du jour mais avec une mauvaise temperature" do
		before(:each) { create :meteo, :glacial, utilisateur: utilisateur }

    it 'ne retourne pas le template' do
      expect(resultat).not_to include template_tenue
    end
  end

	# autre cas
  context "quand l'utilisateur n'a pas de météo" do
    it 'retourne tous les templates tenues' do
			expect(resultat.size).to eq TemplateTenue.all.count
    end
  end
end

❌ Erreurs type Ă  Ă©viter


🎓Aller plus loin