En regardant en diagonale quelques vidéos de Grafikart sur Ruby on Rails, j’ai noté quelques astuces intéressantes :
rails s -b IP
Pour binder l’IP sur laquelle l’application écoute.
Par exemple, rails s -b 0.0.0.0
permet d’écouter sur toutes les interfaces (utile pour les machines virtuelles)
Callback de modèle
Pour ne pas avoir à ajouter du code dans le contrôleur (après un @objet.save
par exemple).
Son exemple était l’utilisation d’un before_validation
pour setter le slug en fonction du titre d’un article.
Scope avec paramètre
exemple :
scope :online, -> (online) { where(online: online) } |
scope :online, -> (online) { where(online: online) }
Scope par défaut
default_scope where(published: true) |
default_scope where(published: true)
Attention aux effets de bord, notamment si on met un order
dans le defaut_scope
et qu’on veut redéfinir le tri dans le contrôleur !
Pour éviter ces effets de bord, les méthode reorder
, unscoped
et unscope
peuvent être intéressante.
render mon_objet
Si on a un partial du même nom qu’une classe, on peut directement utiliser cette syntaxe.
Exemple : si on boucle sur un tableau d’élément pour les afficher les uns sous les autres, on peut écrire :
@elements.each do |element|
render element
end |
@elements.each do |element|
render element
end
à partir du moment où on a un fichier partial _element.html.erb
.
On peut même écrire :
render "element", collection: @elements |
render "element", collection: @elements
ou même :
qui donnera le même résultat. Et ça c’est fort !
content_for
et yield
Penser à les utiliser !
content_for(:title, @element.titre)
yield(:title)
content_for?(:title) |
content_for(:title, @element.titre)
yield(:title)
content_for?(:title)
exemple :
content_for?(:title) ? yield(:title) : "Mon super titre" |
content_for?(:title) ? yield(:title) : "Mon super titre"
config.generators
On peut configurer les fichiers qui sont générés quand on fait un rails ...
dans le application.rb
. Par exemple, pour ne pas créer un helper à chaque fois qu’on génère un contrôleur, on peut écrire :
config.generators.helper = false |
config.generators.helper = false
Plus d’infos sur guides.rubyonrails.org.
Lancer un serveur en production
Attention, il faut du coup une base de données de production.
Supprimer un contrôleur et les fichiers associés
Quand on crée un contrôleur avec la commande rails g controller mon_controleur
, plusieurs fichiers sont générés : le contrôleur, le fichier de test, un fichier SCSS et un fichier JS (ou Coffee).
Pour supprimer ce contrôleur et tous les fichiers associés, on peut utiliser la commande :
rails d controller mon_controleur |
rails d controller mon_controleur
Utiliser un CDN
config.action_controller.asset_host = 'cdn.domain.fr' |
config.action_controller.asset_host = 'cdn.domain.fr'
Preview d’email
Quand on génère un mailer avec rails g mailer mon_mailer
, il est généré un fichier mailer dans /app/mailers
, un répertoire de vues dans app/views
, mais aussi un fichier de preview dans test/mailers/preview
.
Dans ce fichier, on crée des méthodes qui appellent celles du fichier mailer. Par exemple, si notre fichier mailer contient un méthode contact(prenom), on peut définir une méthode contact dans notre fichier preview :
ContactMailer.contact("Toto") |
ContactMailer.contact("Toto")
Ensuite, on peut accéder au preview via l’url rails/mailers/contact_mailer
qui liste toutes les méthodes de preview.
Associations
.includes
Exemple : on affiche un tableau d’articles avec pour chaque article sa catégorie. Pour cela, dans le contrôleur on aurait écrit :
Et dans la vue, quelque chose comme :
<%= article.categorie.titre %> |
<%= article.categorie.titre %>
Cela n’est pourtant pas très efficace : on a une requête qui récupère les articles :
et pour chaque article, une requête qui va chercher sa catégorie :
SELECT * FROM categorie WHERE id = 2 LIMIT 1 |
SELECT * FROM categorie WHERE id = 2 LIMIT 1
Soit n+1 requêtes (où n correspond aux nombres d’articles).
Pour contrer cela, on peut faire dans le contrôleur :
@articles = Article.includes(:categorie).all |
@articles = Article.includes(:categorie).all
Ce qui donnera, au niveau des requêtes :
SELECT * FROM articles
SELECT * FROM categories WHERE id IN (2,3) |
SELECT * FROM articles
SELECT * FROM categories WHERE id IN (2,3)
On peut même faire :
@articles = Categorie.includes(articles: :tags).all |
@articles = Categorie.includes(articles: :tags).all
Pour récupérer toutes les catégories et les articles associés ainsi que les tags associés aux articles.
:dependent
Pour supprimer tous les articles associés à une catégorie à la suppression de la catégorie, on peut écrire :
class Categorie < ApplicationRecord
has_many :articles, dependent: :destroy
end |
class Categorie < ApplicationRecord
has_many :articles, dependent: :destroy
end
qui supprimera les objets articles associés (et appellera donc les callbacks)
ou :
class Categorie < ApplicationRecord
has_many :articles, dependent: :delete_all
end |
class Categorie < ApplicationRecord
has_many :articles, dependent: :delete_all
end
qui supprimera directement les articles associés en base de données (et n’appellera pas les callbacks)
:counter_cache
Pour afficher le nombre d’associations sans faire de requête supplémentaire, on peut utiliser un « counter_cache » :
class Article < ApplicationRecord
belongs_to :categorie, counter_cache: true
end |
class Article < ApplicationRecord
belongs_to :categorie, counter_cache: true
end
Il faut pour cela ajouter un champ posts_count dans la table catégorie (avec 0 comme valeur par défaut).
La valeur de posts_count sera mis à jour automatiquement quand on ajoute ou supprime un article à une catégorie.
has_and_belongs_to_many
Pour créer une table de liaison, on peut faire la migration :
rails g migration create_join_table_articles_tags article tag |
rails g migration create_join_table_articles_tags article tag
et utiliser le has_and_belongs_to_many
class Article < ApplicationRecord
has_and_belongs_to_many :tags
end
class Tag < ApplicationRecord
has_and_belongs_to_many :articles
end |
class Article < ApplicationRecord
has_and_belongs_to_many :tags
end
class Tag < ApplicationRecord
has_and_belongs_to_many :articles
end
L’association has_many: :through permet de faire la même chose avec une classe de liaison. Cela peut être utile lorsqu’on veut stocker des choses dans la table d’association.
article.tags.delete(tag)
supprime la liaison
article.tags.destroy(tag)
supprime le tag et les liaisons