le jour 06 de la piscine Ruby de 42 refait/day06 of the 42 swimming pool Ruby/rails
- les railsguides pour des explications d'ensemble et la doc de l'API pour de la doc sur une méthode précise.
Mais aussi:
- Une très bonne adresse en français grafikart
- L'excellent Rails tutorial de Michael Hartl
- goRails, d'autant qu'avec le GitHub Student Pack, on bénéficie d'un abonnement d'un an gratos
- Les vidéos de RailsCast
- Et une toute nouvelle ressource (doc + code), très complète, RubyGarage
- ton cerveau, il peut servir...
Avant toute chose et tout code, il vous faut utiliser un gestionnaire de version de Ruby (et donc de Rails) RVM et rbenv étant les plus connus et utilisés, mais existe aussi chruby, uru, etc.
Avec RVM, on installe la version de Ruby désirée, en regardant sur site officel de Ruby les versions de Ruby (rvm install 2.6.5
par exemple), créer un gemset (un environnement isolé) avec rvm gemset create nom_du_gemset
, je nomme en général mes gemsets avec la version de Ruby@rails_version, par ex rvm gemset create 2.6.5@rails4.2.7
.
Une fois le gemset créé, on rentre dedans/l'utilise avec rvm 2.6.5@rails4.2.7
dans cet exemple et ensuite, seulement on installe rails avec la bonne version avec gem install rails -v 4.2.7 -no-ri -no-rdoc
sans la doc incluse
outre le code de ce repo voici quelques pistes pour t'aider:
Pour commencer voici des ressources sur l'inscription et l'authentification d'utilisateur, faites à la main, donc sans la gem la plus connue qui fait cela très bien, Devise
- l'utilisation de
has_secure_password
dans le modèle User - l'utilisation de
helper_method
, dans application_controller, qui permet non seulement de partager ces méthodes entre tous les contrôleurs mais aussi les vues. Pour rappel, les méthodes définies dans les helpers servent, elles, dans les vues. Vu que le snippet de code fourni dans le sujet (fourni en sept 2017) ne marche plus, j'ai utilisé un petit bout de code simplissime ([].sample) - la syntaxe d'expiration du cookie
expires: 1.minute
ne fonctionnant pas (dans users_controller#home), j'utiliseexpires: Time.current + 1.minute
- l'utilisation de filtres dans app/models/user.rb tel que
before_save { self.email = email.downcase }
pour mettre en minuscule avant de sauvegarder dans la base de données
Pour l'ex01, voici un extrait du livre di livre Agile Web Development with Rails 5.1 de Sam Ruby, David Bryant Copeland, with Dave Thomas
Rails does this using a simple naming convention. If an incoming request has a controller named (say) admin/book, Rails will look for the controller called book_controller in the directory app/controllers/admin. That is, the final part of the controller name will always resolve to a file called name_controller.rb, and any leading path information will be used to navigate through subdirectories, starting in the app/controllers directory.
Imagine that our program has two such groups of controllers (say, admin/xxx and content/xxx) and that both groups define a book controller. There’d be a file called book_controller.rb in both the admin and content subdirectories of app/controllers. Both of these controller files would define a class named BookController. If Rails took no further steps, these two classes would clash.
To deal with this, Rails assumes that controllers in subdirectories of the directory app/controllers are in Ruby modules named after the subdirectory. Thus, the book controller in the admin subdirectory would be declared like this:
class Admin::BookController < ActionController::Base
# ...
end
The book controller in the content subdirectory would be in the Content module:
class Content::BookController < ActionController::Base
# ...
end
Pour les non-Rubyiste, il faut savoir que
module Foo # ou class Foo
class Bar
# ...
end
end
est équivalent à:
class Foo::Bar
pour les curieux question sur Stackoverflow
attention à bien définir vos routes (app/config/routes), j'ai utilisé (la syntaxe %i[] permet de définir un array de symboles)
namespace :admin do
resources :users, except: %i[new create]
end
pensez aux associations dans vos modèles (belongs_to :modèle_AU_SINGULIER et have_many :modèles_AU_PLURIEL
) et à
scaffolder pour créer Post rails g scaffold Post user:references title:string content:text
qui code presque
tout à votre place
- A noter dans app/models/post.rb
delegate :name, to: :user, prefix: true
qui permet de remplacer ici dans les vues @post.user.name
qui fait couiner Rails best practices par @post.user_name
- l'utilisation de partials dans les vues. Pour rappel on les appelle/affiche avec cette ligne dans une vue
<%= render 'Chemin_relatif(si besoin)/nom_du_partial', post: @post %>
# ou si le partial n'est pas dans un sous dossier
<%= render 'nom_du_partial', post: @post %>
et leurs fichiers commencent TOUJOURS par un _, ici le fichier serait _nom_du_partial.html.erb
. Ici on passe un
argument (:post) qui permet dans le partial d'utiliser directement post
à la place de @post
. Heureusement, car utiliser
@post dans le partial fait (encore) râler Rails best practices !
J'ai choisi d'implémenter la fonctionnalité en rajoutant un champ edit_by_user_id
dans la table posts
(avec bien-sûr
une migration) et en utilisant, bien-sûr, le champ updated_at
de la même table.
Ha là on tape dans le has_many through:
comme association dans le modèle User.
J'ai utilisé encore le namespacing pour
le contrôleur app/controllers/posts/votes_controller.rb (class Posts::VotesController
) et pour la vue avec partial
app/views/posts/votes/_votes.html.erb qui est "appelé" dans le posts/show.html.erb (ce qui s'avèrera très pratique pour
le dernier exo !). Le contrôleur votes_controller.rb n'a qu'une méthode create. celui d'admin possède en plus une méthode
destroy et une méthode index.
# extrait de la méthode create de posts/votes_controller.rb
vote = @post.votes.where(user_id: current_user.id).first_or_create
# value = vote.value + params[:value].to_i
vote.update_attributes(value: params[:value])
first_or_create
cherche dans la table si le vote existe et s'il n'existe pas le crée. J'ai décidé qu'un utilisateur ne
peut voter qu'une fois par Post (d'où la seconde ligne commentée ci-dessus). la valeur du vote (+1 ou -1) est envoyée
dans params pour l'upvote (le downvote se fait de la même façon avec la value: -1) par:
# app/views/posts/votes/_votes.html.erb
#...
<%= button_to 'Upvote', post_vote_path(post), method: :post, params: {value: 1} %>
puisque ce n'est pas un form(ulaire), pas besoin de strong_parameters, just params[:value]
Ici on mime un peu la célèbre gem CanCanCan (ou Pundit). Mais finalement, j'ai fait un truc très simple:
une méthode dans application_helper.rb know_your_rights(user)
pour renvoyer en fonction du user ses droits et une
autre méthode (une helper_method) count_current_user_votes
(pas besoin d'expliquer ce q'elle fait!) dans application_controller.rb. Ensuite je fais juste des if
dans les vues pour afficher ou pas, par ex:
<%= render partial: '/posts/votes/votes', locals: { post: @post, somme: @somme } if count_current_user_votes >= 3 %>
Je vous conseille d'utiliser les commandes rails g
(raccourci de rails generate
). Les exemples donnés ci-dessous
ne correspondent pas forcèment à votre exo/app...
tels
rails g scaffold Post user:references title:string content:text
qui code presque tout à votre placerails g scaffold_controller Admin::Votes
rails g model Vote user:references post:references value:integer
pour les modèlesrails g migration AddIndexToTitleToPost
,rails g migration AddFullnameToUser fullname:string
pour les migrationsrails g controller session log_in log_out
rails g -h
etrails g *objet/choix possible* -h
pour l'aide
Je suis en train de refaire ce jour 06, pour l'instant tous les exos sont finis, en respectant les consignes et les Rails Best Practices et score Rubycritic supérieur à 90 manquent encore des seeds pour les exos 2 à 5 et surtout les tests
quarkgluant/pcadiot
octobre 2019
Paris
P.S. Une petite étoile pour remercier fait toujours plaisir SI ce document vous a été utile