[RUBY] Tutoriel Rails 6e édition Résumé d'apprentissage Chapitre 10

Aperçu

Cet article approfondit ma compréhension en écrivant un article de commentaire du tutoriel Rails pour solidifier davantage mes connaissances Cela fait partie de mon étude. Dans de rares cas, un contenu ridicule ou un contenu incorrect peut être écrit. Notez s'il vous plaît. J'apprécierais que vous me disiez implicitement ...

La source Tutoriel Rails 6e édition

Que faire dans ce chapitre

Depuis que nous avons pu implémenter la création d'utilisateur, la connexion et la mémoire des informations de connexion Ensuite, créez des fonctions de mise à jour, d'affichage et de suppression qui ont été laissées sans surveillance dans les ressources utilisateur.

Mettre à jour l'utilisateur

Modifiez l'action de modification pour mettre à jour l'utilisateur. Les nouvelles actions du contrôleur de sessions que nous avons implémentées jusqu'à présent Préparez un formulaire comme la nouvelle action du contrôleur Utilisateurs et Vous pouvez implémenter l'action d'envoi de la valeur d'entrée du formulaire à l'action de mise à jour. Bien sûr, l'utilisateur peut le modifier, mais en utilisant l'authentification implémentée jusqu'à présent Nous mettrons en place un contrôle d'accès.

Modifier le formulaire

La page de modification contient l'ID de l'utilisateur cible dans l'URL ex) users/1/edit

Utilisez cette option pour extraire l'utilisateur de l'ID d'URL et l'enregistrer dans la variable d'instance.

  def edit
    @user = User.find(id: params[:id])
  end

En faisant cela, spécifiez l'objet @ user``` comme objet modèle dans le formulaire suivant à créer.

erb:edit.html.erb


<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @user, local: true) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Save changes", class: "btn btn-primary" %>
    <% end %>

    <div class="gravatar_edit">
      <%= gravatar_for @user %>
      <a href="https://gravatar.com/emails" target="_blank">change</a>
    </div>
  </div>
</div>

Réutilisation de partiels _error_messages pour afficher des messages d'erreur lors de la saisie de valeurs non valides dans le formulaire.

De plus, il y a target = "_ blank" dans la partie lien de gravatar, mais en écrivant comme ceci, la destination du lien peut être affichée dans un nouvel onglet.

De plus, la valeur actuellement contenue dans la variable @user est automatiquement saisie dans le champ de saisie du formulaire. Il semble que Rails extraira automatiquement les informations d'attribut enregistrées et les affichera. Guu compétent.

Sauf pour le HTML réel généré à partir de cet erb <input type="hidden" name="_method" value="patch"> Il y a une telle description. Rails ne peut pas envoyer de requête PATCH, qui est une requête de mise à jour, donc Rails En spécifiant le patch dans le champ de saisie masqué, il est forgé comme une pseudo requête PATCH.

Une autre chose à garder à l'esprit est que les actions nouvelles et d'édition utilisent presque le même code erb. Pourquoi Rails peut dire s'il s'agit d'un nouvel utilisateur ou d'un utilisateur existant En effet, la méthode `` new_record? '' D'ActiveRecord peut être utilisée pour déterminer si elle est nouvelle ou existante.

>> new_user = User.new
   (1.3ms)  SELECT sqlite_version(*)
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil>
>> user1 = User.first
  User Load (0.6ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "take", email: "[email protected]", created_at: "2020-06-14 02:57:10", updated_at: "2020-06-20 03:53:57", password_digest: [FILTERED], remember_digest: "$2a$12$tYO.HIfYezXpTk2zRp9s6uqJY4wUkPM28NfYuJ7vxq/...">
>> new_user.new_record?
=> true
>> user1.new_record?
=> false
>> 

Dans l'ERB réelform_Pour les objets de modèle lors de l'utilisation avecnew_record?```Regardez le résultat de Déterminez s'il s'agit d'un post ou d'un patch.

Enfin, définissez un lien vers l'action d'édition dans la barre de navigation. <li><%= link_to "settings", edit_user_path(current_user) %></li>

#####Exercice 1.Comme cela m'intéressait, après avoir enquêté sur le type de vulnérabilités, l'article suivant a été utile, je vais donc le laisser. https://webegins.com/target-blank/ "noopener"Super important!

2.La partie formulaire est presque la même dans la nouvelle vue et la vue d'édition, et il y a des différences Il s'agit du texte du bouton d'envoi. Par conséquent, utilisez la méthode provide pour modifier le contenu du texte du bouton d'envoi. Refactoriser tous ensemble dans un partiel.

erbb:_form.html.erb


    <%= form_with(model: @user, local: true) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit yield(:btn_text), class: "btn btn-primary" %>
    <% end %>

erb:new.html.erb


<% provide(:title, 'Sign up') %>
<% provide(:btn_text, "Create my account") %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= render 'form' %>
  </div>
</div>

erb:edit.html.erb


<% provide(:title, "Edit user") %>
<% provide(:btn_text, "Save changes") %>
<h1>Update your profile</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= render 'form' %>
    <div class="gravatar_edit">
      <%= gravatar_for @user %>
      <a href="https://gravatar.com/emails" target="_blank" rel="noopener">change</a>
    </div>
  </div>
</div>

####Échec de l'édition Comme pour l'enregistrement des utilisateurs, nous l'implémenterons en ce qui concerne les échecs d'édition lors de la tentative de mise à jour avec une valeur invalide. Nous allons implémenter l'action de mise à jour, mais c'est la même chose que la création d'un utilisateur à l'aide de paramètres avec l'action de création. Mettre à jour à l'aide des paramètres envoyés par l'action d'édition. La structure est assez similaire. Bien sûr, il est dangereux de mettre à jour la base de données directement avec les paramètres, donc cette fois aussi StrongParameter(Utilisateur préalablement défini_méthode params)utilisation.

  def update
    @user = User.find(params[:id])
    if @user.update(user_params)
      
    else
      render 'edit'
    end
  end

En ce moment avec la validation du modèle utilisateur_error_messages Parce qu'il y a une partie Une erreur est renvoyée pour les valeurs non valides.

#####Exercice 1.Échouer. image.png

####Tester lorsque l'édition échoue Créez des tests d'intégration liés à l'édition utilisateur. Cette fois, comme le titre l'indique, j'écrirai un test lorsque l'édition échoue. rails g integration_test user_edit

users_edit_test.rb


require 'test_helper'

class UserEditTest < ActionDispatch::IntegrationTest
  def setup 
    @user = users(:michael)
  end
  
  test "unsuccessful edit" do
    get edit_user_path(@user)
    assert_template 'users/edit'
    patch user_path(@user) , params:{user:{name: "",
                                           email: "foo@bar",
                                           password: "foo",
                                           password_confirmation: "bar"}}
    assert_template 'users/edit'
  end
end

1.OBTENIR la demande sur la page d'édition, vérifier si la page d'édition est dessinée 2.Envoyer une demande de correctif, valeur non valide pour mettre à jour l'action 3.Vérifiez si la page d'édition est redessinée.

Cela devient un test de l'ordre de.

#####Exercice 1. assert_select 'div.alert', "The form contains 4 errors."

####Modification réussie avec TDD Cette fois, nous mettrons en œuvre l'opération au moment du succès. Utilisateur⁻ L'image fonctionne déjà car elle est implémentée dans Gravatar. name,email,Implémentez la modification réussie d'autres attributs tels que le mot de passe.

Un test pour écrire un test d'intégration avant d'implémenter une fonctionnalité et déterminer si la fonctionnalité est acceptable lorsque la fonctionnalité a été implémentée Est appelé un "test d'acceptation". Mettons en œuvre une édition réussie avec TDD.

Il sera plus facile à comprendre si vous l'implémentez en vous référant au test au moment de l'échec que vous avez implémenté précédemment.(Bien sûr, j'enverrai des données valides)

  test "successful edit" do
    get edit_user_path(@user)
    assert_template 'users/edit'
    name = "foo"
    email = "[email protected]"
    patch user_path(@user) , params:{user:{name: name,
                                           email: email,
                                           password: "",
                                           password_confirmation: ""}}
    
    assert_not flash.empty?
    assert_redirected_to @user
    @user.reload
    assert_equal name, @user.name
    assert_equal email, @user.email
  end

Approfondissez votre compréhension en rédigeant des articles de commentaires du tutoriel Rails pour vous assurer Cela fait partie de mon étude. Dans de rares cas, un contenu ridicule ou un contenu incorrect peut être écrit. Notez s'il vous plaît. J'apprécierais que vous me disiez implicitement ...

La source Tutoriel Rails 6e édition

###Que faire dans ce chapitre Depuis que nous avons pu implémenter la création d'utilisateur, la connexion et la mémoire des informations de connexion Ensuite, créez des fonctions de mise à jour, d'affichage et de suppression qui ont été laissées sans surveillance dans les ressources utilisateur.

###Mettre à jour l'utilisateur Modifiez l'action de modification pour mettre à jour l'utilisateur. Les nouvelles actions du contrôleur de sessions que nous avons implémentées jusqu'à présent Préparez un formulaire comme la nouvelle action du contrôleur Utilisateurs et Vous pouvez implémenter l'action d'envoi de la valeur d'entrée du formulaire à l'action de mise à jour. Bien sûr, l'utilisateur peut le modifier, mais en utilisant l'authentification implémentée jusqu'à présent Nous mettrons en place un contrôle d'accès.

####Modifier le formulaire La page de modification contient l'ID de l'utilisateur cible dans l'URL ex) users/1/edit

Utilisez cette option pour extraire l'utilisateur de l'ID d'URL et l'enregistrer dans la variable d'instance.

  def edit
    @user = User.find(id: params[:id])
  end

En faisant cela, le prochain formulaire que vous créerez sera un objet modèle.@userSpécifiez l'objet.

erb:edit.html.erb


<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
     <%= form_with(model: @user, local: true) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Save changes", class: "btn btn-primary" %>
    <% end %>

    <div class="gravatar_edit">
      <%= gravatar_for @user %>
      <a href="https://gravatar.com/emails" target="_blank">change</a>
    </div>
  </div>
</div>

Pour afficher un message d'erreur lors de la saisie d'une valeur non valide dans le formulaire_error_messages La partie partielle est réutilisée.

Aussi dans la partie lien de gravatartarget="_blank"Cependant, en écrivant comme ceci, la destination du lien peut être affichée dans un nouvel onglet.

De plus, dans le champ de saisie du formulaire@La valeur actuellement contenue dans la variable utilisateur est automatiquement saisie. Il semble que Rails extraira automatiquement les informations d'attribut enregistrées et les affichera. Guu compétent.

Sauf pour le HTML réel généré à partir de cet erb <input type="hidden" name="_method" value="patch"> Il y a une telle description. Rails ne peut pas envoyer de requête PATCH, qui est une requête de mise à jour, donc Rails En spécifiant le patch dans le champ de saisie masqué, il est forgé comme une pseudo requête PATCH.

Une autre chose à garder à l'esprit est que les actions nouvelles et d'édition utilisent presque le même code erb. Pourquoi Rails peut dire s'il s'agit d'un nouvel utilisateur ou d'un utilisateur existant ActiveRecordnew_record?En effet, la méthode peut déterminer si elle est nouvelle ou existante.

>> new_user = User.new
   (1.3ms)  SELECT sqlite_version(*)
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil>
>> user1 = User.first
  User Load (0.6ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "take", email: "[email protected]", created_at: "2020-06-14 02:57:10", updated_at: "2020-06-20 03:53:57", password_digest: [FILTERED], remember_digest: "$2a$12$tYO.HIfYezXpTk2zRp9s6uqJY4wUkPM28NfYuJ7vxq/...">
>> new_user.new_record?
=> true
>> user1.new_record?
=> false
>> 

Dans l'ERB réel, regardez le résultat de new_record? Pour l'objet de modèle lors de l'utilisation de `` `form_with" Déterminez s'il s'agit d'un post ou d'un patch.

Enfin, définissez un lien vers l'action d'édition dans la barre de navigation. <li><%= link_to "settings", edit_user_path(current_user) %></li>

Exercice
  1. J'étais curieux, donc après avoir enquêté sur les types de vulnérabilités, l'article suivant a été utile, je vais donc le laisser. https://webegins.com/target-blank/ "noopener" super important!

  2. La partie formulaire est presque la même dans la nouvelle vue et la vue d'édition. Il s'agit du texte du bouton d'envoi. Par conséquent, utilisez la méthode provide pour modifier le contenu du texte du bouton d'envoi. Refactoriser tous ensemble dans un partiel.

erbb:_form.html.erb


   <%= form_with(model: @user, local: true) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit yield(:btn_text), class: "btn btn-primary" %>
    <% end %>

erb:new.html.erb


<% provide(:title, 'Sign up') %>
<% provide(:btn_text, "Create my account") %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= render 'form' %>
  </div>
</div>

erb:edit.html.erb


<% provide(:title, "Edit user") %>
<% provide(:btn_text, "Save changes") %>
<h1>Update your profile</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= render 'form' %>
    <div class="gravatar_edit">
      <%= gravatar_for @user %>
      <a href="https://gravatar.com/emails" target="_blank" rel="noopener">change</a>
    </div>
  </div>
</div>

Échec de l'édition

Comme pour l'enregistrement des utilisateurs, nous l'implémenterons en ce qui concerne les échecs d'édition lors de la tentative de mise à jour avec une valeur invalide. Nous allons implémenter l'action de mise à jour, mais c'est la même chose que la création d'un utilisateur à l'aide de paramètres avec l'action de création. Mettre à jour à l'aide des paramètres envoyés par l'action d'édition. La structure est assez similaire. Bien sûr, il est dangereux de mettre à jour la base de données directement avec des paramètres, nous allons donc utiliser StrongParameter (méthode user_params précédemment définie) cette fois également.

  def update
    @user = User.find(params[:id])
    if @user.update(user_params)
      
    else
      render 'edit'
    end
  end

Parce qu'il y a une validation du modèle utilisateur et des messages _error_messages partiels pour le moment Une erreur est renvoyée pour les valeurs non valides.

Exercice
  1. Échec. image.png

Tester lorsque l'édition échoue

Créez des tests d'intégration liés à l'édition utilisateur. Cette fois, comme le titre l'indique, j'écrirai un test lorsque l'édition échoue. rails g integration_test user_edit

users_edit_test.rb


require 'test_helper'

class UserEditTest < ActionDispatch::IntegrationTest
  def setup 
    @user = users(:michael)
  end
  
  test "unsuccessful edit" do
    get edit_user_path(@user)
    assert_template 'users/edit'
    patch user_path(@user) , params:{user:{name: "",
                                           email: "foo@bar",
                                           password: "foo",
                                           password_confirmation: "bar"}}
    assert_template 'users/edit'
  end
end
  1. OBTENEZ la demande sur la page d'édition, vérifiez si la page d'édition est dessinée
  2. Envoyer une demande de correctif, valeur non valide pour mettre à jour l'action
  3. Vérifiez si la page d'édition est redessinée.

Cela devient un test de l'ordre de.

Exercice

1. assert_select 'div.alert', "The form contains 4 errors."

Modification réussie avec TDD

Cette fois, nous mettrons en œuvre l'opération au moment du succès. Utilisateur⁻ L'image fonctionne déjà car elle est implémentée dans Gravatar. Implémentez la modification réussie d'autres attributs tels que le nom, l'adresse e-mail et le mot de passe.

Un test pour écrire un test d'intégration avant d'implémenter une fonctionnalité et déterminer si la fonctionnalité est acceptable lorsque la fonctionnalité a été implémentée Est appelé un "test d'acceptation". Mettons en œuvre une édition réussie avec TDD.

Il sera plus facile à comprendre si vous l'implémentez en vous référant au test au moment de l'échec que vous avez implémenté précédemment. (Bien sûr, j'enverrai des données valides)

  test "successful edit" do
    get edit_user_path(@user)
    assert_template 'users/edit'
    name = "foo"
    email = "[email protected]"
    patch user_path(@user) , params:{user:{name: name,
                                           email: email,
                                           password: "",
                                           password_confirmation: ""}}
    
    assert_not flash.empty?
    assert_redirected_to @user
    @user.reload
    assert_equal name, @user.name
    assert_equal email, @user.email
  end

Bien sûr, le test échoue. Premièrement, il n'implémente pas les messages flash. Vous n'avez pas spécifié de redirection. Ces deux se font prendre. Et la partie la plus importante. La valeur du mot de passe étant vide, la validation est interceptée et elle ne peut pas être mise à jour normalement.

Les deux premiers sont mis en œuvre sur cette ligne.

  def update
    @user = User.find(params[:id])
    if @user.update(user_params)
      flash[:success] = "Profile updated"
      redirect_to @user
    else
      render 'edit'
    
    end
  end

À ce stade, @ user.update sera intercepté lors de la validation avec un mot de passe vide et passera à une instruction else. Le test ne fonctionne pas non plus. En guise de contre-mesure, ajoutez la gestion des exceptions lorsque le mot de passe est vide. Dans de tels cas, il est pratique d'utiliser l'option allow_nil: true. Avec cela, même s'il est vide, il ne sera pas pris lors de la validation. Cette option passe la vérification d'existence, mais lors de la création d'un objet du côté de la méthode `` has_secure_password '' Puisque la validation d'existence fonctionne, nil est repoussé lors de la création d'un nouveau, et s'il est nul lors de la mise à jour, le mot de passe n'est pas changé. L'opération peut être réalisée. De plus, en ajoutant cette option allow_nil: true, la validation définie dans le modèle has_secure_passwordCela résout également le problème d'affichage du même message d'erreur en raison d'une validation de méthode en double.

Exercice
  1. Réussir image.png

  2. L'image Gravatar par défaut est affichée à la place. image.png

Autorisation

L'authentification dans une application Web identifie l'utilisateur. L'autorisation consiste à gérer la gamme des opérations pouvant être effectuées par l'utilisateur. Les actions de mise à jour et d'édition qui ont été implémentées jusqu'à présent présentent des défauts majeurs, Dans l'état actuel, tous les utilisateurs peuvent être modifiés, quel que soit l'utilisateur connecté. Le lien Paramètres dans la barre de navigation vous amène à la page d'édition de l'utilisateur connecté Si vous spécifiez l'action de modification de différents utilisateurs directement dans l'URL, vous pouvez y accéder et la mettre à jour.

C'est mauvais, alors changez le comportement pour le bon. En particulier Si vous n'êtes pas connecté, passez à la page de connexion + affichez un message. Si vous êtes connecté mais que vous essayez d'accéder à un autre utilisateur, transférez à l'URL racine.

Demander à l'utilisateur de se connecter

Avant la modification, l'action de mise à jour est exécutée à l'aide du filtre avant sur le contrôleur Utilisateurs Assurez-vous de mettre en œuvre pour forcer la connexion.

  before_action :logged_in_user, only:[:edit,update]
  .
  .
  .
    def logged_in_user
      unless logged_in?
        flash[:danger] = "Please log in."
        redirect_to login_url
      end
    end

En implémentant de cette manière, la méthode log_in_user est toujours exécutée avant d'exécuter les actions d'édition et de mise à jour. Lorsque vous n'êtes pas connecté, un message flash s'affiche pour vous inviter à vous connecter. Redirigez-vous vers la page de connexion.

Et à ce stade, si vous accédez à la vue d'édition sans vous connecter, vous serez redirigé vers la page de connexion. Le test échoue car il est maintenant ignoré.

Dans user_edit_test.rb, connectez-vous avant d'accéder à l'action d'édition pour que le test réussisse. Utilisez la méthode log_in_as car elle est définie pour les tests.

Le test va maintenant réussir. Cependant, commenter la ligne before_action ne rejette pas le test. C'est une faille de sécurité sérieuse et c'est mauvais si elle n'est pas touchée lors du test Je vais le réparer pour qu'il repousse fermement dans le test.

  test "should redirect edit when not logged in" do
    get edit_user_path(@user)
    assert_not flash.empty?
    assert_redirected_to login_path
  end
  
  test "should redirect update when not logged in" do
    patch user_path(@user), params:{ user: {name: @user.name,  
                                            email: @user.email }}
    assert_not flash.empty?
    assert_redirected_to login_path
  end 

En ajoutant des tests comme celui-ci Pour toujours tester si log_in_user est en cours d'exécution avant d'exécuter des actions de modification Cela ouvrira des failles de sécurité dans les tests.

Exercice
  1. Une nouvelle page ou une nouvelle action d'inscription ne peut pas être exécutée et une erreur se produit.
 FAIL["test_should_get_new", #<Minitest::Reporters::Suite:0x00007f1d1cf4dab8 @name="UsersControllerTest">, 0.06502773099964543]
 test_should_get_new#UsersControllerTest (0.07s)
        Expected response to be a <2XX: success>, but was a <302: Found> redirect to <http://www.example.com/login>
        Response body: <html><body>You are being <a href="http://www.example.com/login">redirected</a>.</body></html>
        test/controllers/users_controller_test.rb:10:in `block in <class:UsersControllerTest>'

 FAIL["test_invalid_signup_information", #<Minitest::Reporters::Suite:0x00007f1d1cff74c8 @name="UsersSignupTest">, 0.08553676799965615]
 test_invalid_signup_information#UsersSignupTest (0.09s)
        expecting <"users/new"> but rendering with <[]>
        test/integration/users_signup_test.rb:12:in `block in <class:UsersSignupTest>'

 FAIL["test_valid_signup_information", #<Minitest::Reporters::Suite:0x00007f1d1d0494d0 @name="UsersSignupTest">, 0.09624041300003228]
 test_valid_signup_information#UsersSignupTest (0.10s)
        "User.count" didn't change by 1.
        Expected: 2
          Actual: 1
        test/integration/users_signup_test.rb:20:in `block in <class:UsersSignupTest>'

  9/9: [================================================================] 100% Time: 00:00:01, Time: 00:00:01

Demandez le bon utilisateur

Ensuite, même si vous êtes connecté, vous ne pourrez pas modifier à moins que vous ne soyez la personne. Nous allons procéder avec TDD.

Tout d'abord, ajoutez un deuxième utilisateur à l'appareil pour créer une situation dans laquelle vous vous connectez en tant qu'autre utilisateur.

users.yml


archer: 
  name: Sterling Archer
  email: [email protected]
  password_digest: <%= User.digest('password') %>

Ensuite, connectez-vous en tant que @other_user dans le test et Écrivez un test pour mettre à jour @user.

  test "should redirect edit when logged in as wrong user" do
    log_in_as(@other_user)
    get edit_user_path(@user)
    assert flash.empty?
    assert_redirected_to root_path
  end
  
  test "should redirect update when logged in as wrong user" do
    log_in_as(@other_user)
    patch user_path(@user), params:{ user: { name: @user.name,
                                             email: @user.email}}
    assert flash.empty?
    assert_redirected_to root_path
  end

Il s'agit d'un test car le message flash n'est pas affiché et est simplement ignoré vers l'URL racine.

J'écris un test et bien sûr il ne passe pas Écrivez le code pour réussir le test.

Plus précisément, si vous créez une méthode `` correct_user '' et qu'il n'y a pas d'utilisateur avant d'exécuter la modification, mettez à jour l'action Écrivez le processus pour passer à l'URL racine.

users_controller.rb


  before_action :correct_user, only:[:edit,:update]
    


  private
    def correct_user
      @user = User.find(params[:id])
      redirect_to root_url unless @user == current_user
    end

Le test va maintenant réussir.

Enfin, définissez la méthode current_user? '' Et intégrez-la dans la méthode correct_user '' définie précédemment.

    def correct_user
      @user = User.find(params[:id])
      redirect_to root_url unless current_user?(@user)
    end
  def current_user?(user)
    user && user == current_user
  end
Exercice
  1. Si vous ne protégez pas l'action de mise à jour, directement avec la commande curl etc. sans passer par l'action d'édition (page d'édition) Si vous envoyez une valeur, vous pouvez la mettre à jour.

  2. L'action d'édition est plus facile à tester. (En fait, connectez-vous et affichez le chemin de modification d'un autre utilisateur)

Expédition amicale

Cela rend également cette fonctionnalité de mise à jour utile. En particulier logged_in_userLorsque la méthode repousse l'accès à la page d'édition d'un utilisateur non connecté et passe à la page de connexion Si vous vous connectez tel quel, vous serez dirigé vers la page des détails de l'utilisateur (afficher) sans poser de questions, C'est un peu gênant de voir la page d'exposition lorsque je me connecte pour accéder à la page d'édition. Améliorez cela pour que lorsque vous vous connectez, vous serez redirigé vers la page d'édition (transfert convivial)

Puisque le test peut être mis en œuvre de cette manière Cochez pour accéder à la page de modification sans vous connecter et redirigez vers la page de modification après la connexion.

test "successful edit with friendly forwarding" do
    get edit_user_path(@user)
    log_in_as(@user)
    assert_redirected_to edit_user_url(@user)
    name = "foo"
    email = "[email protected]"
    patch user_path(@user) , params:{user:{name: name,
                                           email: email,
                                           password: "",
                                           password_confirmation: ""}}
    
    assert_not flash.empty?
    assert_redirected_to @user
    @user.reload
    assert_equal name, @user.name
    assert_equal email, @user.email
  end

Maintenant que j'ai écrit un test qui échoue à ce stade, je vais écrire le code pour que ce test réussisse. Écrivez un processus pour enregistrer la page au moment de la demande et la rediriger lors de la connexion.

Définissez une méthode dans sessions_helper.

sessions_helper.rb


  def redirect_back_or(default)
    redirect_to(session[:forwarding_url] || default)
    session.delete(:forwarding_url)
  end
  
  def store_location
    session[:forwarding_url] = request.original_url if request.get?
  end

store_locationPuis J'écris un processus pour enregistrer l'URL de la destination de la demande dans une session temporaire. Pour le moment, je ne dois enregistrer que la demande GET

Dans le cas peu probable où vous vous connectez pour accéder à la page du formulaire et supprimer les cookies d'informations de connexion enregistrés intentionnellement Lorsque je soumets le contenu du formulaire, les URL telles que la publication et le correctif sont enregistrées. Si vous utilisez la méthode redirect_back_or``` dans cet état, une requête GET sera envoyée à l'URL qui attend la publication, le correctif, etc. par redirection Il sera envoyé et il y a de fortes chances qu'une erreur se produise. Vous pouvez éviter ces risques en vous concentrant sur les demandes GET.

logged_in_userÀ la méthodestore_locationMettez la méthode, enregistrez l'url de destination de la requête, En mettant la méthode redirect_back_or` dans l'action de création de sessions_controller Lors de la connexion, si une URL est enregistrée dans la session, redirigez-la vers elle.

sessions_controller.rb


  def create
    @user = User.find_by(email: params[:session][:email].downcase)
    if @user&.authenticate(params[:session][:password])
      log_in(@user)
      params[:session][:remember_me] == '1' ? remember(@user) : forget(@user)
      redirect_back_or @user
    else
      flash.now[:danger] = "Invalid email/password combination"
      render 'new'
    end
  end

users_controller.rb


    def logged_in_user
      unless logged_in?
        store_location
        flash[:danger] = "Please log in."
        redirect_to login_url
      end
    end

Au fait, sauf s'il y a un retour ou un appel direct à la dernière ligne de la méthode La redirection se fait à la fin de la méthode.

Le test réussit avec le contenu ci-dessus.

Exercice
  1. Assurez-vous que l'URL enregistrée disparaît lorsque vous vous connectez et redirigez vers la page d'édition.

user_edit_test.rb


  test "successful edit with friendly forwarding" do
    get edit_user_path(@user)
    log_in_as(@user)
    assert_nil session[:forwarding_url] #Ajouter ici
    assert_redirected_to edit_user_url(@user)
    name = "foo"
    email = "[email protected]"
    patch user_path(@user) , params:{user:{name: name,
                                           email: email,
                                           password: "",
                                           password_confirmation: ""}}
    
    assert_not flash.empty?
    assert_redirected_to @user
    @user.reload
    assert_equal name, @user.name
    assert_equal email, @user.email
  end
(byebug) session[:forwarding_url]
"https://12b7e3b6aec94b45960b81560e233372.vfs.cloud9.us-east-2.amazonaws.com/users/1/edit"
(byebug) request.get?
true

finalement

J'en fais de plus en plus à la fin du chapitre Je vais le résumer pour le moment.

rails t
git add -A
git commit -m "Finish user edit, update, index and destroy actions"
git co master
git merge updating-users
git push
rails t 
git push heroku
heroku pg:reset DATABASE
heroku run rails db:migrate
heroku run rails db:seed

La base de données de production se fait avec pg: reset DATABASE . De plus, le nom de l'application qui réinitialise la base de données pour éviter les erreurs Il vous sera demandé de le saisir, alors saisissez-le et réinitialisez Ou avec l'option --confirm

reset DATABASE -c Nom de l'application


 Tu peux le faire.

 Après cela, migrez et ajoutez des échantillons sur heroku et terminez.


 [Aller au chapitre précédent](https://qiita.com/take_webengineer/items/48bb1a43ffac4290959f)

 [Vers le chapitre suivant]()


Recommended Posts

Tutoriel Rails 6e édition Résumé d'apprentissage Chapitre 10
Rails Tutorial 6e édition Résumé de l'apprentissage Chapitre 7
Tutoriel Rails 6e édition Résumé de l'apprentissage Chapitre 4
Tutoriel Rails 6e édition Résumé de l'apprentissage Chapitre 9
Tutoriel Rails 6e édition Résumé de l'apprentissage Chapitre 6
Tutoriel Rails 6e édition Résumé de l'apprentissage Chapitre 5
Rails Tutorial 6e édition Résumé de l'apprentissage Chapitre 2
Tutoriel Rails 6e édition Résumé de l'apprentissage Chapitre 3
Rails Tutorial 6e édition Résumé d'apprentissage Chapitre 8
Tutoriel Rails (4e édition) Mémo Chapitre 6
Tutoriel Rails Chapitre 3 Apprentissage
Tutoriel Rails Chapitre 4 Apprentissage
Tutoriel Rails Chapitre 1 Apprentissage
Tutoriel Rails Chapitre 2 Apprentissage
Tutoriel Rails 4e édition: Chapitre 1 De zéro au déploiement
tutoriel rails Chapitre 6
tutoriel rails Chapitre 1
tutoriel rails Chapitre 7
tutoriel rails Chapitre 5
tutoriel rails Chapitre 10
tutoriel rails Chapitre 9
tutoriel rails Chapitre 8
Tutoriel Rails Chapitre 0: Apprentissage préliminaire des connaissances de base 5
[Rails] Didacticiel Apprendre avec les rails
Mémorandum du didacticiel Rails (Chapitre 3, 3.1)
[Tutoriel Rails Chapitre 4] Rubis à saveur de Rails
[Tutoriel Rails Chapitre 5] Créer une mise en page
Tutoriel de mastication des rails [Chapitre 2 Application jouet]
rails tutry
tutoriel sur les rails
rails tutry
tutoriel sur les rails
rails tutry
tutoriel sur les rails
tutoriel sur les rails
Seul résumé lié à la configuration du tutoriel Rails
Test du tutoriel sur les rails
Mémorandum du didacticiel Rails 1
Tutoriel Rails Chapitre 1 De zéro au déploiement [Essayer]
Rails Learning jour 3
Tutoriel Rails Memorandum 2
Rails Learning jour 4