REST API with Ruby on Rails: The Complete Guide | Sebastian Wilgosz | Skillshare

Playback Speed


  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

REST API with Ruby on Rails: The Complete Guide

teacher avatar Sebastian Wilgosz

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

60 Lessons (6h 7m)
    • 1. Introduction

      2:04
    • 2. 1.0 installing required software

      6:51
    • 3. 1.1 Create and run app

      11:13
    • 4. 1.2 Article's model

      6:22
    • 5. 1.3 RSpec introduction

      12:12
    • 6. 1.4 Factory bot introduction

      5:35
    • 7. 1.5 Article validation tests

      6:48
    • 8. 1.6 Article validations

      4:09
    • 9. 1.7 Article validation assignment start

      2:28
    • 10. 1.8 article validations assignemnt complete

      3:38
    • 11. 2.0 article list routes tests

      6:42
    • 12. 2.1 articles list routing

      8:52
    • 13. 2.2 articles show route start

      2:03
    • 14. 2.3 articles show route assignment finish

      2:19
    • 15. 2.4 articles listing requests tests

      10:30
    • 16. 2.5 article serialization

      10:41
    • 17. 2.6 code improvements

      5:05
    • 18. 2.7 recent articles

      4:46
    • 19. 2.8 pagination tests

      4:07
    • 20. 2.9 paginating resources

      8:43
    • 21. 2.10 handling not found error

      2:47
    • 22. 3.0 creating github application

      1:01
    • 23. 3.1 create user model

      8:01
    • 24. 3.2 octokit integration

      3:14
    • 25. 3.3 authentication service failure

      6:52
    • 26. 3.4 authentication service success

      10:32
    • 27. 3.5 fetching existing user

      2:46
    • 28. 3.6 create access token

      4:54
    • 29. 3.7 create session route

      1:50
    • 30. 3.8 create sesssion controller failure

      6:28
    • 31. 3.9 shared examples

      3:36
    • 32. 3.10 create session controller success

      7:20
    • 33. 3.11 authorization error handler

      4:35
    • 34. 3.12 refactoring error tests

      3:41
    • 35. 3.13 logout and authorize

      8:11
    • 36. 4.0 create articles routes and failure

      4:39
    • 37. 4.1 create invalid articles

      6:56
    • 38. 4.2 create articles success

      7:35
    • 39. 4.3 articles update showcase

      3:25
    • 40. 4.4 update only owned articles

      6:25
    • 41. 4.5 destroy articles

      4:32
    • 42. 5.0 commenting scaffolds cleanup

      10:01
    • 43. 5.1 creating comments scaffolds cleanup

      12:03
    • 44. 5.2 listing comments improvements

      10:10
    • 45. 5.3 create comments

      7:15
    • 46. 6.0 creating heroku account

      2:01
    • 47. 6.1 deploying to heroku

      8:43
    • 48. 7.0 section plan

      3:46
    • 49. 7.1 standard login multiple authentication handlers

      6:41
    • 50. 7.2 standard login controller preparation

      5:10
    • 51. 7.3 fix our tests

      5:08
    • 52. 7.4 standard authenticator specs

      5:49
    • 53. 7.5 standard login user password

      7:37
    • 54. 7.6 standard login user finder

      5:34
    • 55. 7.7 standard login token creation

      6:29
    • 56. 7.8 login with password endpoint tests

      8:25
    • 57. 7.9 login with password success

      6:54
    • 58. 8.0 registrations tests

      8:38
    • 59. 8.1 registration valid request

      4:26
    • 60. 8.2 registration invalid request

      8:09
  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

28

Students

--

Projects

About This Class

Build an API application that you can use EVERYWHERE and hook up ANYTHING into it!

Check out!

  • SUPER productive videos with a total focus on what is important!

  • CODE SNIPPETS for each coding lesson!

  • Comprehensive resources and articles!

  • Learn Test Driven Development like a PRO

  • Get familiar with best Practices for API development!

In this course, you'll know how to create professional API application in Ruby on Rails with TDD!

You probably heard about a popular trend to create web applications with a split API and frontend parts. Having a pure API application allows you to hook up ANY frontend you will ever wish. 

Knowledge about creating pure API applications is necessary for modern microservice architectures for REALLY BIG projects!

-------------------------------------------------

What Will You Build?

All of my courses are 'learn-by-doing': I'll create a real-life application and you can follow each step to make similar one for yourself.  In this course we'll build one complete API application, that can work as a link-log, similar to RubyFlow project. We'll do all this using Test Driven Development, the way the best developers in the world develop their applications every day.

This mega app will include the full set of features, including everything from authentication to managing comments.  You'll learn how to create an app that allows multiple users to log in, publicize articles and list them as a newsfeed.  It's my goal to ensure you understand each feature we build into this app so you can apply them to your own personal or professional projects in the future.

I can always help in case of any troubles so if you'll encounter some, just write through one of our communication channels.

----------------------------------------------------------------

Here is what we'll learn:

Basic/Intermediate API

  • Create modern Ruby on Rails API applications with the best practices.

  • Create backend for a LinkLog application, similar to RubyFlow.

  • Authenticate users using their logins and encrypted passwords!

  • Authorize your applications using Social Media as leverage to get registered users!

  • Register new users!

  • Integrate application with Github using oAuth!

  • Write microservices that you can hook up anything into!

  • You will be able to get a job on those professions: Ruby on Rails developer, backend developer!

  • Find and Kill any bugs in your Rails applications

  • Test application responses in a very convenient way

  • Write REAL applications that actually works

  • Deploy application so it will be publicly available

  • Work with database relationships and manage related objects

  • Master CRUD ( create, read, update, destroy ) with REST API

  • Serialize responses using the most popular format

Professional API topics

  • Be an expert with TDD (Test Driven Development)

  • Authorize requests and manage access

  • Write automatic tests like the best developers do every single day

  • Advanced API Error Handling!

  • Continue and improve your skills even after the course ends using our communication channels and external resources!

I've built the course that I would have wanted to take when I was learning to build RESTful API for my applications. A course that explains the concepts and how they're implemented in the best order for you to learn and understand them.

I know your time is expensive, so I prepared really compressed videos, including only what's important!

Feel free to check it out!

Who this course is for:

  • This course is for any web developer that wants to create modern web applications using API and frontend split apart.
  • It's perfect for a junior Ruby developer who wants to learn to create modern API applications.
  • It's also a choice of intermediate developer that wants to be even better.

Meet Your Teacher

Class Ratings

Expectations Met?
  • Exceeded!
    0%
  • Yes
    0%
  • Somewhat
    0%
  • Not really
    0%
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction: Welcome to pro-gun rights API course, where you will learn how to design, implement, and deploy API applications that you can hook anything into. My name is Sebastian, and they lead you through the whole course. I started my developer career in 2012, My making several projects using Groovy and right technology. Soon after improving my skills, I started working from crackup is where I was the youngest full-stack developer for over three years. Guarantee aside of supporting my best client as a full-stack developer, I drive the digital company where we help others evolving the Internet. I designed the course for anyone willing to create modern web applications in the way the best developer's tool, using recommended practices and properly testing each feature reactant. By the end of this course, you will be able to plan, implement, and covered with tests, complete a RESTful API applications regardless of the size. I'll be teaching you how to create a BI applications like a professional using test-driven development across the Holocaust. It's a method widely used by the best developers around the world. It gives us incredibly good results. We don't need to worry about breaking entity, but can complete diplococcus on delivering features. Not only I'll tell you how to do it, but either code review, preparing a real life application that I'll release, or the community. The ideal student for this course is the existing web developer that has at least basic knowledge about tribune writes and wants to expand on current skills to deliver even better software following newest trends and market needs, they're free to take a look at the course description and some lessons. And I'm looking forward to seeing you in class. 2. 1.0 installing required software: Hi. In this course, I plan to write a complete dryers API application and therefore do not distract you too much later. In the single video, I will go through most of the software I will use in the rest of the class. I mean software specific for the creation of the application. For example, I know you probably have your paper each terminal already set up. So I will not waste too much of her time on this part. Let's begin then. To even start with writing Amy Ruby application, you need a Ruby interpreter being installed on your machine. And if you are interested in writing API specific applications, chances are you already worked with Ruby before. So you already have different versions of Rubinstein. During this course, we will work with Ruby version 2.7.2. And to not mess with versions of Ruby already installed on your system, I will use Arabic version of a network. One of such tools is named our VM. And it is the one I would choose to install multiple versions of Ruby on the same machine. You can also check our band for, which is another popular told touching exactly the same thing. However, as I will be using RVM if you choose, Because feel free to fast forward this video to skip the installation guides. When you will visit the official documentation website, you will see the detailed installation instructions with various options depending on your needs. I installed the most basic version without any specific Ruby being pre-installed. In my case, the most used through B version constantly changes depending on which client has served or what project I'm working at the moment. Then I just copy this part to the terminal. And after a moment or two, the installation is complete. This notice that I already have our VM installed on my machine, so the output here may look different for you. Oh, here discrete detected some legacy files being installed on my computer. So I will clean up following this suggestion and we are ready to go. Now, I can use RVM prefix commands to manage my Ruby versions. For example, RVM list shows all the Ruby versions installed on my system. And as you can see, there is no Ruby 2.7.2 here just yet. I can easily install it though using RVM install command, passing the target with Ruby version as an argument. I think they're rupee prefix is not required here though. Let me dial it now. I consists of deprecation warnings, but nothing that aim to worry about at the moment. Okay. Since the installation goes on without any issues, but as it can take awhile, let me keep it to the end. Okay. There will be is installed, but by default, it's installed without any documentation to save some space. I may use it in my IDE, however, during the development. So I'm going to install it right now using RVM docs generate her eye. Now I can switch to the newly installed version by typing error VM US, followed by the just installed Ruby version length. This would switch your shell contexts to the default setup jumps in start for this specific Ruby version. And this means that all jams in studying other context, other Ruby versions are invisible from this environment and there won't be any version conflicts. However, chances are that you will work on different projects at the same time, all of them using the same Ruby version. How to avoid gem version conflicts in that case, well, LLVM has a solution for the two. For each instance Ruby version, you can create a separate named environment which is completely encapsulated. And whatever is installed in this context won't be visible outside of it. Such an environment is called a gem set. And the we can switch to the specific gem set by appending the Ruby version here, we add followed by a name of gem set. We want to switch. As I don't have such gems had created just yet. I need to add a flag, dash, dash create, and press Enter. Now, when I want a nice Ruby versions installed, you can see the 2.7.2 being added at the bottom and being an active one. Then I can list the available gem sets within this Ruby version. And as you can see, I'm using the Rails API gem set specific for this project. Having the gem set setup, I can install the recent Rails, which for me download the version 6.3 and we are almost ready to go. The next big thing I want to show you, It's a similar solution to RVM to manage multiple PostgreSQL version. If you use Postgres as your database and work on multiple projects, chances are you will encounter similar pressures, conflicts on the database client level. In such case, postgres app can help you with it. This is the most convenient tool I know to manage multiple pulse respirations in the system if you don't want to continue to raise your app during development. I totally recommend it. So if you don't use Docker in development, give it a shot as it can make your life much, much easier. The last important tool used across the course is, of course, the Postman app to manage and test requests against our APIs. But as there is a whole section about postman in this course, I won't spend too much time on it anymore. This is all the most important software we will use in this course. And if anything extra will be needed, I will show you that when we will encounter them. In the next video. I will create and run the actual app. So see you there. 3. 1.1 Create and run app: When we have everything installed and setup, let's start the implementation by creating a brand new Rails application named API. To do so, I will use a standard application generator that comes with the rails gem. I will write the riots new, followed by the name of the application, which will be their API in our case. Then I will add a few options to this command to adjust application according to our needs. First is the capital T flag to tell trials that we don't want to generate the default test folder. I forgot to mention earlier, but we will use the RSpec jam as our testing framework in the whole class. The rails comes with the default solution to write unit tests. But from my experience, most of the real projects use RSpec as it offers many more possibilities and it's more intuitive to work with. Then at the end of the comment, I will add dash, dash API option. So rights will know to create EPA on the application. As you probably know, Ruby on Rails is a framework designed to create a complete web applications. And those, it comes with a whole enzyme to serve HTML views, css, and JavaScript assets, and so on. In our case, however, the front and we'll be done separately. So we don't need to generate any views and our app will be kept as skinny as possible. Then finally, at the very end, you can add dash d followed by Postgres SQL string, which is a very popular database adapter. And chances are you may be interested in using kid instead of the fault one. The rails comes with a default SQLite 3 adapter, which is Firebase, to not force anybody to install external dependencies for new applications. But in more advanced projects is important to have the same database locally that is used in production to prevent some random issues. I don't need it at the moment. So to keep things simple, just for now I will use the default is colleague 3 provider, which basically is just a database written in a fire. While SQL light is pretty enough to work within the development environment before going to production, I will change it to pause rest. So if you wish, you can do it right away. But please notice that to use Postgres, you don't need the external Postgres clients that I have mentioned in the last video. Again, if you don't care or you don't want to install the Bosphorus. No issue with that. We will not have any problems as long as you don't plan to deploy this thing to production server, just do not add this flag. And your application will be installed with the default SQLite database data. Now when I click Enter, the generator script had been launched and it starts to create a tremendous amount fires filled with all the content needed to have a complete helloworld web application. Now, when all files are created, I can verify if everything had been generated properly. Listing files only shows the project folder and my Visual Studio Code workspace I have created for this project. Now, it can go into the project folder where all my riots scaffold files had been generated and then ran the editor. My editor shows an error message that the Ruby language server cannot be launched. And I will fix that in a moment. For now, however, let's just verify if installation is done properly. This seems to be the standard writes application folder, but there should be some small differences from what you have probably get used to. Let's take a look at the application RB file stored in the config directory. We need to check whether there is an option named APA only. And if it's set to true, it is. So since the app is set up in the right way, you can also notice that in this application there is no assets folder. It's all fine as we completely do not need it. The future front-end application will take care of delivering everything, the front and everything looks nice. So it's time to add our gems. We will use several gems in dapp, and now I will install two of them. So do so, I will add them to the fire named Jim fire. I assume that more or less, you know how gems and it's tying them works. So I will not go through the details. I just want to mention that here in the Gemfile there are specified or Ruby dependencies needed for our application to work. Scrolling down, I'm looking for the group keyword with development and test keywords. There are some gems useful only during the development or test environment. And we don't want to install them on the production server for various reasons. Those two gems, I'm going to start right now are the perfect example for that. Both of them will be only relevant for running our automatic tests. And on the production server, they are completely not needed. This is why I will replace both of them in the side of this development and test group. The name of the first gem I want to add is RSpec rise. As I mentioned before, this is our testing framework. Rspec is the most popular testing framework for a Ruby applications. It's used to make our lives a little easier by providing a lot of useful human-readable syntax for all kinds of automatic tests. And if you are not familiar with it yet, I strongly suggest getting into it as it's used almost everywhere. Rspec, Ryan's jam is a wrapper to RSpec. Pretend just to integrate aspects in riots applications is 0. It replaces the default assertions. And it's my preferred way to write automatic tests. Here on the gems official website in the installation section, there is a note to add a specific version after the gems name. It didn't work last time I checked, but I will give it another chance. And if there will be any issues, I will use the older version. I just needed to copy that part and put it into my Gem file. Now, let's move to the next Jam will use constantly in discourse is a factory, but this is a fixture replacement for our tests. It allows us to define sample objects and create them inside of our testing examples. And similar to before the factory bot has arrived, integration being extracted to a separate gem, which we will use for easier configuration. Now, when we have new gem specified, I will go back to the terminal and run the bandwidth to download and install new dependencies. Let me just confirm that I have the correct Jameson active. Okay. I have so when I'm when run bundle, all the gems in stout will be added only to this specific contexts. Now let's visit the documentation of the RSpec again. When you will scroll down a little bit, you will see that after installing the gym, we are supposed to run a built in RSpec generator to add some configuration file to our project. Let me do it now. By running RSpec install. I have created three configuration files specifically for this gem, which we don't cover in detail in this course because the default configuration is sufficient for our needs. Okay? Maybe we will add a few weeks later in this course, but then I will turn more about those files. Now, let me go back to the factory but documentation and go to the configuration section. Here you can see all kinds of scripts helping to integrate the gem specific syntax methods depending on what your project uses in the set. I will grab one for RSpec and riots. And as the contagion suggests, I will place it in the rise spec RB file generated by our aspect and scholar a minute ago. Here in the configuration block, I can remove the first line, as I will not use built-in fixtures, but for their factories instead. Now it's time to check if we did everything Tolkien. I can run the server now using their rights as commands and check the browser by visiting the local host at port 3000, I should get the default starting page of the project, and I do. When I will open the terminal again, you will see several issues reported on the screen. One of them already have opened and GitHub issue and it's not relevant at the moment. The second one is related to missing a public com and can be solved by adding a fab icon into the public folder. None of them will affect us though, so I will just ignore them for the moment. Now, let's run our tests suit and check if tests can run without any problems. This has run all our tests. As we have no tests yet. 0 examples are run. But it gives us important information saying that the whole configuration is loaded properly. It work with a single warning saying that we have a gem installed that is not used in the system. These dissident for data, GM is specific for Microsoft systems. And as I use Unix-based system now, and we will use the Unix also on production. I can just get rid of this gem completely. Now I just run bundle again to refresh the list of installed champs. And I'm ready to go. This is amazing because now we can implement the first feature which is listing the articles. So quick pause on my side and we'll be back in the next section. 4. 1.2 Article's model: At this point in time, we have the new API application up and ready. And in the previous lesson, I made a quick introduction to the APA in general and how our articles data will look from the client's point of view. Now to be able to show this data I presented in the slides a moment ago, I need a database representation of that articles object. And this is what we will do right now. So as you probably know already, adding objects that are ready to be saved in our application's database in the Rails projects is extremely easy. We just need to run a single generator command to create our object, and it will automatically add several files to work with. You can use several different generators to speed up a reward. And if you are interested in all of them, I will link to the proper section of the rights documentation in the resources of this lesson. But for me and you, there one interesting for now is the model generator. All I need to do is open the shadow from the Projects folder. And here I would run rights G, which is an abbreviation of degenerate keyword, followed by the type of the generator script I will use. In this case, it's a model generator. Then I specify the name of the class I want to create. This. Notice that this is a singular noun, not the pleura one. This is a convention in rice community to name modals in singular form. So I will stick with that here as well. Then after that, I need to list all attributes are article will contain with the appropriate types assigned. So I'll need a title type of string. To specify the type, I need to split. The name of the attributes are part of the type declaration using the column. And this is what I will be doing for all other types. But for string attributes, this is not necessarily as this is the default attribute type when you use the rights model generator. So in this particular case, we can omit the type declaration and rise will know that this is a title and this is a type of string as long as we want explicitly told otherwise. The next attribute I need is the content. And here I need to append the attribute name with the column and the type of attribute. As in this case, I need the content to be texts, not string. String type can only contain up to 256 characters. And for our blog posts, it can be definitely not enough. Then the last aspect between it is a slab, which is also a string. So I can safely omit the type declaration. Then I click Enter and after A-sharp, while my model is created, you can see that in the app folder there is this file called models slash article RB, where there is ab definition of article classes start ordering that there were several other pile is created automatically, like the immigration file to create the Articles table in our database. And two files in the RSpec folder. Those last two are related to the automatic tests we will have, right very soon. Article spec file is a place where we will store all our automatic tests related to the articles object. And the factory fire comes from the factory bought jam we installed before and is used to help us easily create fake records required for our tests to run. Now, we can open the editor and visit the articles model file to check it out. It's an empty Active Record instance without any logic inside. So there's not really much to cover. Having a dad. Let me go back to the terminal session and run one more command to run the migration. We see above. I assume, you know what migrations are. So I will not explain it in detail, but just in case you don't. I will quickly mentioned that this is a script with instructions to our database to update its current state. We started a project to refactor database and we want to have the Articles table being created. So we have a place to persist our records. And you have just run a generator that created emigration file that tells RDB how to create such table. Now I just need to apply this integration to update the database schema and we will be ready to go. Now, I will run the migrations using rides db migrate command. And our article model is now fully created. I can check it out, opening the Rights Council and playing with the articles object a little bit. For example, I check how many articles we have in the database. And as you may expect, we don't have any, As we never created one. Now, let me create one empty object. And now when we fetch all articles, we will get exactly one element. There is one problem with this. However, as you noticed, I just created an article with an empty title and content, which doesn't seem right. And especially we didn't specify the slab. So front-end would never know under which URLs show the article. This is what we will fix in the next video. You and I will implement some validation to ensure that the newly created article is always correct. So see you there. 5. 1.3 RSpec introduction: Welcome back. In the previous section, we have managed to create an article object, but we quickly figured out that this object needs to be validated somehow. We don't want to allow anybody to create articles without empty titles or content right? Now, we want to add those validation rules to ensure every article has always correct data assigned. Bad. As I mentioned several times before, I planned to write everything in test-driven development. And this will be the first test related episode in this course. For the next two videos, I will guide you through the very basics of the RSpec and factory bot. So we can easily follow the rest of the tests related sections without wondering what specific methods actually do. Then we will write the first real expectation for validating our article objects. You already know pretty well how to test your apps. You can just skip this section and jump directly to the implementation. And if not, just stick with me to have a complete overview of what we are doing. Let me open my editor and visit the articles model spec file, where I will add a few validation tests to be sure that we always have only appropriate articles saved. As you may remember, this spec file had been automatically generated by our model generator after installing the RSpec rice jam. So if you don't have this folder, you probably haven't installed the RSpec properly. In such a case. This go back to the section about creating the rise application and installed that startup gems. Again. When I open the file, you can see that there isn't too much going on here. And you could, of course, just create this file manually. But I'm using the generator to save some time. As this file structure is identical in every single test file I will write. So let me introduce you to what's going on here. At the very top of the file. You can see they're acquired directive, which includes the RSpec configuration for the rice project. Rspec comes with two different configuration files. In the right spec is used whenever you need the rise application to be loaded. Like when you test database connection controllers, behavior, rendering views and so on. If you will write a Ruby class that is independent of any rise specific code and you will want to test it. Chances are that you would really like to have the other configuration fire placed here to avoid unnecessary writers loading and speed-up protest suit. Then below it, there is the RSpec describe directive with an article class passed as an argument and alittle hash type model being set as the second attribute. This described method. Perhaps all our test examples for the class specified above. In other words, this is a group of tests that provides several methods to be accessible inside of the block. The first parameter here, an article, is the name of the group. It could be literally anything. As at the end, it's converted to a string. But the nice thing to have it named from article class is that in the situation when we don't have an article defined in the system, this line will raise an error and we will immediately get notification about it without writing and explicit test to check that. Moving forwards to the bottom, you can see that there is a method called pending with a string being attached to it. Let's check out what would happen if we will run this file. To run the test file, I need to go to the terminal and type the RSpec common. This by default runs all Ruby files stored in the spec folder that R sub fixed by underscore speck string. It's possible to run only a subset of tests, of course. But ASU and I have no tests written just yet. It makes no difference whatsoever if we will run all of them are not. So I can just run RSpec and enjoy the results. As you can see, I've got a message that there is one pending example in our tests. And even if it fails, it is expected to fail. So no problems with that. If you use the pending keywords, you can ride the failing test, but you will still be able to deploy applications and do not have any kind of failing beards during the development. I personally barely use them. And usually if something fails and trying to fix it immediately. This is why in this course, we will not bother too much about pending examples. And whenever tests will fail, we will get an error message saying that we need to fix it to proceed. Okay, let's go back to that file where I will add a few test examples. Let me remove this spending example and write the actual test. The first example will be only a damaged test to present to you the logic behind RSpec methods we will use across the whole course. I will now write a test checking if a specific number is positive. And I will do that for several different ways. So we can see a few aspects of personal action for this. So I need to make use of the eat method appended with the name of the test. And then at the block, at the end where we will place the test sludgy. The nice thing about RSpec is how it allows to write test suits and generate reports using almost common English language. For example, I want to check the first test to check if the number is positive. So I named the test HIV tests and number to be positive. It's unnatural to read. And when I will see an error message, I will also have no problems with understanding what exactly went wrong. Here inside, I will add our expectations. But first, let me move to our diagrams board to show you how the expectations syntax looks like. And I would immediately want to add our glow explanation here. I don't want to list here all the possible methods you can use in the RSpec to test your applications, to memorize that there is no better place than visiting the documentation page. I would rather like to show you the common structure. And then whatever you put inside will work pretty much the same. So the expectation begins from the expect method. And as an argument, you pass a value to it. This argument can be literally anything. An object method call anything that can be considered as a value to check. Then you change the method to into it and pass a matter inside under the hood. Anything you pass into the method is channeled into the matter provided into that to matter. And about this matter, it is a helper method that the only thing it does, it checks if the provided value is what you want to have. Respect comes with many predefined matters. And you can easily write your own if you wish. Okay, but you may ask, why the heck is it so complicated? Why we can't just use plain Ruby to compare values. While those RSpec matters are designed pretty much to make test code as much clear and easy to read as possible. I will show it to you on the example. So let's go back to the editor. I want our test to check if the number is positive. So I will write expect, then open around a bracket and pass a number inside, then close the bracket chain with two method. Open another set of brackets and type B positive inside. Then close the parenthesis and our expectation is finished. A few words of explanation here. They be positive is a variation of the beam matter. The MIMO allows you to call a method on the checking value and evaluate if the result is true. So under the hood, it's something like the positive is the same as one. That positive with question mark is equal to true. You can pass any method name to be matter. And it will try to call this method on the provided object, self fixing it with a question mark. What are our benefits here? Well, the most obvious one is the readability. When I check the code, I can just read it as it would be written in English. I expect the provided number to be positive. Also, this syntax allows you to search those expectations easily across the whole project, which is again, parade advantage against writing the plain Ruby. And this is probably why RSpec as a testing framework, grew so popular. And one more note here. As you may or may not know, Ruby allows you to omit the parentheses for the last method call in the chain. So in this case, if we remove the last set of brackets, the evaluation of the Ruby code will be exactly the same. But I will have less code to write. And as I plan to write a lot of tests, I will enjoy not to have to write this extra unnecessary code. So from now on, I will omit the last set of brackets whenever I can. And I just want to point it out to you so everything is clear. We could achieve the same by passing aerobic comparison operator like so. I expect five to be greater than three. This will compare against a given value, not only 0. If you wish to get a deeper understanding of what is possible with which matters, I will link to an RSpec documentation in the resources of this episode. But for now, let's run this test to see the result. As you can see, the results says that our tests have been passing without any details because usually we are only interested in what went wrong. If everything is passing, that's fine. We can move forward and never come back. But if you wish to have the detailed report of all running examples, you can add dash, dash format flag to RSpec command assigning to it documentation value. And when we will run this thing, now you will see all the examples run with all the messages added as a tests descriptions. Okay, that was a long introduction, but I hope it's useful for you. And for now, let's take a quick pause and I will come back to you in the next section. 6. 1.4 Factory bot introduction: In the previous video, I have a guide you through that damage test example written using the RSpec hard parts. And I really want to write the actual test. But before I will do it, There is just one more little thing that I need to show you. Remember that in the very first lesson, we have added up plugging or jam named factory bought. We will use it in almost every test we are going to write it. So I believe it's extremely important to explain to you why we actually needed while. When I will visit my article spec file, you might expect that inside we will test the article opposite behavior and chances are that we will need to create an article pretty often. Normally, to use an article object, I would need to go with something like this. As an article, assigned article, create and pass the random data inside to create a valid object. Now, this imagine that across the whole application you need a lot of these objects scattered around all your tests suit. First of all, you would need to have the logic responsible to create a dummy object stored in multiple places. And secondly, if, for example, the validation on the article object will ever change, you would need to go through all those test examples and manually adjust all those created dummy records to be valid. Again, as we will very often need a palette records across our test tube filled with random neighbor. I would rather want to have a very tiny Ruby object that would contain the logic to automatically do that for me, those kinds of objects are called factors. And you may recognize from the gems name that the factory bought is a tool helping us create exactly those factories easily. You may remember that when we have created the article model, fires had been generated and one of them was the article factor. Here is the place where I can define the logic for generating valid objects for my testing proposers inside of this factory. But the final block, I can define multiple factories and then refer to them based on the same name I provided. So here is the article factor, and by default, it always create or build articles with static strings passed as an attribute. Now I can add more details to the generator by defining that. For article title, it will always pass a sample string. Let's say sample article. Then for the content, I will pass the sample content. And for the slug, I will write the sample article with dash instead of space. I can access this factory from my test examples by calling a few methods that factory but provides. One of which is the create method. Then inside I just pass the factory name. And this will create a dummy article record for our test with the title already field with the default Virial with specified. I can check it out very quickly by writing an expectation. When I create this article and assign it to a variable, I expected the article title to be equal to sample article string. I loved the syntax. Rspec seems to be designed just for video courses. Now, let me go back to the terminal and run our tests. As you can see, everything is green. So we have just successfully built the sample article for our tests. But there is one little improvement I would like to apply to my code. As you see in the example. I need to write factory but dot create. Whenever I want to create a new article. This is not very convenient. And you may know that we actually can improve it. I actually can remove that factor in both class module code, and our tests will pass without any issue. It happens because of the factory but syntax method being included in a Rails helper, we have integrated during the application and utilization. But I have felt it's important to highlight that they're affected. Does this a little improvement? Make my test item leaner? Even though I didn't call the factory. But explicitly, all our tests are passing without any problems. Awesome. So now when you know what is the factor Got you and I will use how to use it and why I wanted to have it in my project. Finally, we can jump to the real test examples. So a quick break, and I will see you in the next section. 7. 1.5 Article validation tests: In the previous section, I have talked about RSpec and factor basics. As we will constantly use those to occur the whole course. I will not deep dive into the mechanics behind either of those drums. But I will try to explain this parts that we use. And you can always find links to the documentation in the resources attached to this video. And the way, just by following these videos, you in-kind a pretty neat knowledge about using the most popular features, those gems along. Now, having that said, let's jump directly to write a real test examples. In this video, I will write a few tests to check our validations on the articles object. So to check if something is valid, I need to write a simple expectation. It starts with the expected article to be valid. The argument passed to the expect method can be an object or method call, and its value will be passed to the B matrix to compare. As I explained in the previous section, the article object is an Active Record instance, so it has the valid methods are fixed by a question mark defined. And this is why we automatically can use be valid hyperlink. So in this case, this is almost equivalent to article valid equals true. But it's much more readable and intuitive to understand. If I'm lucky, our tests should still pass. Nice. Now, let's take a look to this article creation process. Previously, we used the create method which saved the object into the database. But here we just check the validations that happened before we save the record. So there is no need to even touch the database, which makes our tests are a little bit faster. This is my usual approach. We're in one test. I always make sure that the factor we use is valid. And in other tests, a reuse the same factor with replacing a single attribute with an appropriate value. So having this test, I expect it to pass. As I haven't defined any validation just yet. Then I will write the second test example, which tests the title being invalid. Let's name it has an invalid title. Now inside a good article again, but here I pass explicitly the attribute name with the desired value, which will override the default title coming from the factoring. This one to be invalid. And to do that, I can use and not to method chained into the excitation. Then I will add a second expectation. Tracking that error message of the title will include the string. Can't be blank. Now I can run the tests again to be sure they are failing. So I'm switching to the terminal and run the RSpec comment again. They fail as expected because we don't have any validation defined just yet. And that's completely fine. It says exactly what had been gone wrong at the line where we check the validation. I expected the article object to not be valid, but it actually was just this noticed. The failing test doesn't necessarily need to be a bad thing. It is a very good if we expect it to fail because it means it's written well. But also, it's really good if we don't expect it to fail. Because it means that we broke something. And our test just prevented us from deploying the buggy code to the production. I will add those validations in a moment to make our green again. But before, I want to do a little clean up, remember how we talked about the describe block at the very top of the test file that wraps all our tests together. The thing is that usually this grouping is not enough. And as our test to become bigger and bigger, they also tend to be messier. And this is why RSpec allows us to add nested groups for our projects. And I really like to make heavy usage of this feature. I will now wrap all tests related to the validations inside of that nested describe block named validations. Have you noticed that I prefix the string with a hash? This is a naming convention I use when testing methods. Whenever I test something on the class, I used the dot prefix for naming. And whenever I test something on the instance, I prefix the group name with a hash, it helps me to keep the test files clean, which is especially important when the project girls. Now when we have it nicely grouped, there is one more thing I can improve. Kind of see how the line with building an article is exactly the same in both my tests. Chances are that this situation will repeat in the future. I always want to have the valid object at the beginning so I can extract this article definition outside of our test example. And the Find it at the top of the group. From here. It will be available in the whole describe dogs. But to do so, I need to change the syntax a little bit. Instead of just assigning the value to a variable, I will need to make use of a method called lead. This method actually sets a variable with a name passed as an argument into it. So I will pass the article symbol inside. And then the rest of the line I need to wrap inside of the ruby dock, which are just currently brackets. Now, our test fire is a little bit cleaner and you may ask me if that's necessary. Well, the answer is not really. The thing is that this file here is really small. And I always think what happens if my test will grow and I will need to refactor, then I don't like that to ever happen. So I always try to keep things dry and clean whenever possible. Now, I can check if everything is still right. Yes. The failures are the same as they were before. So let's take a quick pause here, and I will implement the validation in the next video. 8. 1.6 Article validations: In the previous video, I did, I did the guide to the testing toolkit we will use across the course and you alignment on the right are first working tests. In this video, we will write the actual validation. And I warn you that this episode will be extremely short. It's nice that by writing tests, the failure message actually tells you what to do next. The model is always valid because we have never actually added any validation rules to it. Let me fix this easier now. I need to visit the article model definition file. When I will add one validation rule for our title. I'm not sure how deep I need to explain everything. As this course is designed for people who already have at least some experience with fries applications. But if you have never seen this stuff, I will link to the more detailed article into resources. So please make sure to check it out. Writing validation rules in the active record object is extremely easy. We just need to add validate skew or then type the name of the attributes it will affect. And at the end, append the actual rules we went to the apply. I want to be sure that our articles always have the title set when we tried to save to our database. So I will need to use the presence validation rule and set it to draw, believe me or not. But that's all when I will run our tests now. All green again. And that means we can move on to the next feature. You can ask me now, while SEP, why the hell have you recorded a separate video just to add one line to the file. Let me explain. In the previous sections, I actually guided you through the testing concepts and I wanted to do the first test driven iteration as clear as possible. This is why it took a lot of time to just write a validation tests. Then I wanted to be sure that if you already practice TDD daily in the note that aspect by heart. But just want to learn to write the API. It is easy for you to just keep that test rate sections, at least most of them. From now on. These iterations will be a little bit more balanced. But still, you can follow the course to learn TDD workflow or just implementing the features. I will try to lead the test episode from the actual implementation whenever that makes sense. So that's being said. It seems we could finish here. But there is one little thing you can think, okay, we have just added the validation tests and actually validations for the title attribute. What about the content or the slab? Here is, where comes the first challenge I have prepared for you? So let's take a quick pause and I will see you in the first coding assignment in this section. 9. 1.7 Article validation assignment start: Welcome to the first coding challenge I have for you. So far. Following that TVD concept, I have added a validation rule for the article's title. And during that, the title is always provided. Now, I would love to ask you to write similar validation for the content. And Tesla, I want you to add two tests, checking if the content and Slack needs to be provided for an article to be valid. And then fix that test failures by adding those validations. But this task itself doesn't seem to be very challenging, even though it allows you to practice TDD quite work. So I have prepared something more engaging for you. Whenever the user will visit the article on our page, we always want to be sure that they have a unique slag pointing, always two different URLs. So front-end with always know which article to display. Currently, however, we can add as many articles with the same slag as we want. And the goal is to change that. So they're really challenge for this assignment is to write a test and then the validation rule for slugs, unique wellness in our article. I know that I didn't mention how to do that yet in this course. So I will link to exactly connotation about uniqueness, validation in the resources. And when it comes to tests, you just need to create an article with a specific slag, check if it's valid, and then tried to save another record with the same slack, that should be invalid. There are two things that you may find tricky here. First is writing that test example I have described above. But the second thing is to write a factory that generates the unique slags every time you create a record. I will not tell you how to do that, but I will post a link, the exact section in there, james documentation where you can check it out on your own. Finally, I will show you how I solved this issue in the summary of this lesson recorded in the next video. So I wish you all the best and we'll see you in a moment. 10. 1.8 article validations assignemnt complete: I hope you have no problems whatsoever with completing the first challenge. And here is how I have a 100 decision. I would like to show you that test files first, as this is what I started from. As you can see, I have added two additional tests for checking the presence of the attributes. And they are completely identical to what we had before. And just change the attribute names and expectations. Then I have added another test to check the uniqueness of the slack. And as I had to validation tests for the same attribute, I have renamed the rest of the examples to be more descriptive. Here inside, I have created one valid record and use the create method to actually save it in the database. I tried to build a new object, but as I want this to be for sure exactly the same as the one in the first article, I needed to pass the slag attribute value and explicitly set it to the valid article that slack. Here I used the build method only because I expect this one will not be valid anymore. So we don't want to save it in the system. At the very end of test, I check the format of the return an error message in a similar way we did before. Then I have run the test and I was told to add some validations. So this is what I have done next. I visited the article that are b file. And here I added the presence validations for the content and the slug. But for the slug, I also added the extra validation rule named uniqueness and also set it to true. You could expect that it was all. But unfortunately, there was one more thing to be done. In my test. I have added a test for my factory. I wanted to always create a valid records. So to be sure it generates the unique slugs. I have to it the first test a little bit. First of all, after the first expectation, I have saved my article object into the database. And then I have that. When I will call the factor again, it will still generate a valid record. This test failed. And it meant that as I added more validations, I needed to also update the factory to meet those rules. Then they have moved to articles factory. And here you can see that I have changed the definition to use an argument passed to a block to always generate the unique identifier. This was not obvious, and I know that, but I believe that it's completely fine. If you struggle with a challenge, without that has not a challenge and your isn't. This feature allows us to create dynamic attributes by using a variable passed to our blog, which is incremented every time this factor is used. After fixing the factory, I have checked my test suits again and all my tests appeared to be green once more. I don't show it to you like it would be the only way to solve this problem. But I just wanted to present you my approach. If your solution differs and Kim, to see it in the submitted answer, maybe I will learn something new from you. Thanks for your activity and let's jump to the next lesson where we can finally torched the API stuff. 11. 2.0 article list routes tests: In the previous lesson, we have implemented our article object and validated it properly. Now it's time to prepare an endpoint to deliver the actual articles, least. As implementing the whole endpoint touches a few topics. I decided to split it apart. And in this video, I will implement the rooting for articles, URLs, or to be more specific tests for a road. Currently, if I run my server, open the browser, and visit the slash articles URL, I wouldn't get a nice deep roots in carer saying that there is nothing in the application that handles the URL. There is no roads yet defined which would manage that URL. And this is exactly what you can read here. I would change that very soon, but before I will do that, according to the TV workflow, I wanted to start from writing basic routine tests. Just a little disclaimer. There are routing tests and requests, which kind of the same or very similar thing. And because of that, routine, tests are quite often omitted in rights applications. As in the routing, there is not too much to go wrong. And usually URLs are covered in different tests types. However, I will still write them because chances are that the application you are working on. We will need that Wald test at rooting for its API to support multiple versions or multiple ways to access the same controllers action. So let's go back to the topic. As you probably know at this point, thanks to the RSpec gem on our test examples are stored in the spec folder. Note that test folder as default. And all files in this folder which end on underscore speck are recognized as test files automatically. So they will be immediately include that. When running the RSpec common. I would like to create a new routing tests for articles that will check if we have a proper URL defined in our application and did not think more. High, create a new folder named routine, where I will place all my routing tests and add a file named Articles spec are being inside of this file. I will require arrives heartburn be present in all our test files. And then I will add a describe a blog below it, which groups all tests related to articles and name it articles rules. Then we can write an example. I named the test. It routes to the articles index action. Now inside of it, I will place my expectation, which should be quite easy. Here. I don't want to kick any kind of response delivered to the client from the server. I'm not interested in the response status code. If it succeeded or return an error. I don't care if the responses that JSON or HTML format. The only thing that this test checks is the, if we have a definition of the root, the finding that system that matches our expectations. So basically, I'm only checking if there is a rule in the routes.rb file that for the specific URL typed in the browser. Those are application, which controller, and which action should this request be handled by? I expect that GET request to the articles URL. This noticed that I had omitted one set of brackets and the expression will be still fine here. I expected to route to a controller named articles and its action named index. So this is the test. But rise has an alternative, shorter syntax to write root definition instead of long has shown above. I could also write articles hash index. This is an alternative syntax which I like much more as it's just shorter. I will leave the other example for you in the comment as a reference for now. Then any dynamic parameters would be added after the string. So for example, if I would like to check the URL with a page number parameter, this would be added to the row definition as a hash with a key page and then nested hash with key number and divided tree. This just take a look at the syntax of this statement. I can just read this code in English and I will know what tasks, even without any Rubik's experience. And this is why I love Ruby so much. Now I can run this test to see what happens. As you and I have ordered the other tests written in article spec or beefier. Chances are that we don't want to all those tests being run every single time. It makes no difference now, but when your product is big, running the whole test really slow down the development. Fortunately, we can filter out everything and run what's important. Letting the continuous integration tools running all the tests after pushing changes to the repository. In this case, I'm only concerned about the routing tests we are written so I can pass the path to the file or folder containing only tests we are wanting to run. Here it's spec routing articles spec. The test fails of course, because we don't have the root defined just yet. Do you see that this is the same message as we saw in the browser? It's really often like that. However, as you can see there only one error message here, but in our test example, we have two expectations. It happened because once the first expectation fails, the test stops at that line and the code below is never called. I can improve that by wrapping my both expectations in an aggregate faders bulk. With this, when I would run my test again, both error messages will be shown. Now as I reproduce the problem by writing an automatic tests, I can add an implementation to fulfill the expectation. Let's take a quick break here and I will see you in the next video. 12. 2.1 articles list routing: In the previous lesson, I have shown you how to implement the basic routine tests. And I managed to reproduce the problem I have seen in the browser when I visited the slash articles URL. In this episode, I will show you how to solve it, and also I will show you why, even if you develop your application using test-driven development, it doesn't necessarily solve all of your problems. First of all, our tests or browser says that we have no road slash articles defined in the application. So I need to add one. As you may or may not know. All roads for our application are placed in the routes.rb file inside of the config directory. Now, I think I wrote is only one line of code. And I could make only a ten seconds video writing it and letting you move on. But I want to take a moment here and explain you a few little things that I think may be important. First of all, there are several ways to define the roads. Use exactly the same syntax we have used in the test. So I could write something like get slash articles to articles hash index. It informs our Ryan's application to map URL into a specific action in the correct controller. So whenever there will be a request coming from this URL, the actual index of the articles controller will be called and all the additional data and attributes will be posted there. You can preview all the routes defined in our application using a pre-defined rise common shell script. Let me show it to you. Here in the terminal. I can type Ryle throat. And then all the roads defined in application will appear here. If you are working on the existing project, chances are that you will have very long list of rows here and it will be quite hard to verify if your newly-created growth is there or not. To filter their results. You can use standard shells, wrap function, passing whatever you want inside. Here is how to list only articles related roads. You can also add the Azure V flag followed by Arius keyword to filter out. Roads are automatically generated by writers. However, rates also provides you a built in filter for this command. If you will pass dash g flag, it will be just a different syntax for filtering results. And as you can see, it works pretty the same. Now, let's go back to their roots are beefier. I have shown you one way to define the URL in the application, but I will use the second one. Making use of the resources had been the syntax for it is just a keyword, resources up and stunned by the name of the resource I want to define. In our case, it will be articles. The advantage of this approach is that by default, this helper creates routes for all crud actions. Brad is simply a shortcut for create, read, update, and destroy. The best is to show it to you by checking all the resources in our application. Let me go to the terminal and the one I will list our roads. You can see that now we have not one but five-folds the final automatically. The resources helper basically says that we want those five rows to be defined and served by the default methods in their controller named articles. If I would change the name of the resource to users, it would expect an anergic situations for users. Now having that, you can have all basic roles defined using a single line of code. And this is why I prefer the syntax from an agent, my roots. And the last part, eventually, I will implement all those roads listed here. But it is a good practice to only keep in the application those rows that it actually uses. This is why I will go back to the roots are beefier and apt, an option name only and insight. The arguments list. I'm going to place the index action. After going back to the terminal, you can see that all of my extra roads disappeared. Now let's check what happens in our test. If I will run it now, it will fail, but with different message saying that no controller is serving the specified action, it's fine. As because the error message differs, it usually means that we went forward with our implementation. Now, as I'm set that I haven't necessarily controller. Let me create one in my editor. I'm going to the controllers folder and Articles controller RB file here inside I defined my articles controller class, which inherits from their application conflict. Now it's a fun part. Let me run the tests. Again. It passed. However, don't celebrate just yet. Let me visit the browser under the Articles euro. Surprise, surprise. It still shows an RV error content. This time with a message that there is no actual index in the files in the specified controller. That that's actually fine. The routing is only about accepting the request and saying which part of the application will take care of handling that. When we run our routing test. No configure methods are called. It only checks if inside of the router B file there is a root definition. This error we see is not related to the routing at all. The tests only ensures that the part of the code which is covered works well. So in this case, we only check if the articles URL is defined in our system and also if the appropriate controller is there. But we don't check anything inside of the counselor because it's controller's responsibility. I didn't cover the controllers behavior at all. And this is why I didn't get any information about the problem before checking the browser. But the important lesson from this video is that the fact you do test-driven development doesn't mean you will have no bugs in your application. And it doesn't mean that if your tests are green, the application is working perfectly. Seeing the error is not always a bad thing. It just means that my test coverage is not complete. And this is something you should always keep in mind. Mixing it is extremely easy. I just need to add this action to the controller and we're ready to go. I can visit the newly created consider and define an empty index action inside. Now, our browser won't crash anymore. But if you visit the root, it does nothing. I tried to refresh. Now, the browser didn't even refresh the page. It's because we deliver no response. It will be clearly shown in the postman. Sending the same request tells us that the response has no content status. I can render anything here in the controller. For example, render empty JSON object. Now, refreshing the browser will show you exactly that. But this is actually a task for the controller. The controller is responsible for what's rendered and delivered to the page. The road think is only about which controller and which action should be called. If an action does nothing, It's actually fine. We will implement it later. So let me undo those controllers changes for now. As in the next few episodes, we will implement the container index action properly. But being driven by r to be implemented tests, we do TDD like uproar, remember? So a quick break, and I will see you in the next section. 13. 2.2 articles show route start: In the previous video, you and I had been working on the routing for articles collection. And soon I will implement the controller's action for delivering the actual results. The nice thing about API and TDD is that endpoints are pretty similar to each other and may working on one. You can implement other end points just based on the ones already written. This is why I came here with another challenge for you. The task is to implement the single article she wrote action. And further in the course, I will ask you to implement this show action together with me writing the index one. So your goal is to implement the routing test, checking if there is a route for articles slash. For example, one recognized by our application and served by the show action in the articles controller. Here, the root implementation is absolutely trivial, especially if you will use the resources helper. I have shown you previously that test implementation. However, it can be a little bit tricky. Or at least it can contain a few things that will make you think. It's important to remember that the ID of the article you'll provide is dynamic and it will be passed to your controller's actions as a parameter. I'm pretty sure however, that you will figure it out. And in case of any problems, you can always check out the notes I added just after this video to help you go through it. In the next video, however, I will show you how I have implemented that. So to summarize, I want you to write a routing test for articles show action, and then tweak their roots or B file to actually implement that route into your application. Now, I'm living discharge for you and we'll come back to your internet showcased video. 14. 2.3 articles show route assignment finish: Welcome back. I hope you have finished the challenge without any problems. And in this video, I want to show you my implementation just to be sure everything will work the same way when we will proceed further in their class. First, let's check our tests file. Here I have added an additional test for the show action. It's really similar to the one we already wrote. And it differs only with three little things. First of which is the URL. It includes the ID of the specified article at the end on the diagram from the previous video who have seen their ID at the end, too informal how it's interpreted by a rise application. But the tests should actually check the real URL, not the fake one. Now, moving to the next difference, it says that request should be Hamlet by show action. All that was pretty intuitive, but then I need to pass an attribute to my expectation results where I explicitly check that except the euro. This request will contain dynamic attribute named ID with the value being set to one. And this is the key difference. In my previous example, the application had been only interested in the URL. Yeah, I added this pagination example to help you out. But now they're also receives the parameters. So if you would just type the controller's name and action here, that test would fail. Now, let's check their roots are beefier. Here I just added our show method 2, the only option in the resources definition, which actually define the proper route. No magic here. And I think it's pretty straightforward. I can confirm that it works by switching to the terminal and running rake routes in the console. You should see two routes defined here. Now, as everything is clear, Let's move on to the articles action implementation. 15. 2.4 articles listing requests tests: By this point, you and I have the routing to get information about articles already implemented. And we did it for extracting both that collection and the single article. Now we are going to dive inside of the controllers behavior to actually deliver correct responses to our client. In this video, I will write the tests for our controllers index action to an Azure are further implementation always works great. Here is a little disclaimer. Usually, when you do that TDD, you want to follow Smile iterations and improve the code by fixing one test at a time. I have told you before that I will still test. Episodes are part of the actual implementation whenever possible. And you have experienced that so far. I will also do that later in the course. But sometimes it would be important to keep the test code together with the implementation to better show the actual durations. And this is such a case. If I would write all my tests just one after the other and then do the implementation. It would be somewhat unnatural as this is not what I'm usually doing. Usually I'm writing one or a few related tests at the time and then fix them before going forward. I really want to show you the real flow of the professional development. And this is why. Here I will do the small iterations where I first write a test or two, and then I'm making them green before going forward. First of all, I would like to switch to my avatar and create a new request test file for articles. I have already created one and filled it in with the default dataset. Not waste your time on repeating process. This. Remember that it needs to have a name and underscore speck, because without that, RSpec will not run those tests automatically and you will need to additional configuration to grab it. Also, it's pretty important to place the test inside of the requests folder. It's because RSpec recognizes that test file type based on the folder name. You can override it, of course, but I mentioned it. Just in fact, you will face some weird method missing errors in your own applications. Inside. The same as before. I have acquired rails helper. And then they describe a blog to aggregate all my test examples. In this file. At the end of the day, we would have a lot of test examples and we will have a few tests written for every single controller action. So I immediately add the one more nested describe block for the index section. Now I can implement all my tests inside. When you write any tests for your application components, you should always think about what's important for it to work well, when we are checking the HTTP service responses, we are usually concerned about the status code of the response, the body. And sometimes it's headers. In this case, we don't care about the headers, but knowing if the request succeeded or not is pretty important. So my first example, we'll test if the server returns a proper HTTP status code, let's name it should return a success response inside of it. As the first thing, I need to send a get request to our articles index section. This notice that this test and gauges routing as well. And this is why most of people only rights requests tests. However, this takes a bit longer to execute. So if you have several endpoints pointing to the same controller, it may be beneficial to have routing tests separated. So if you find yourself in the project wherein there is no routing tests, don't panic. It's even more often prioritized. And the case I have shown you. Now, I want to write the actual expectation. I expect the response to have an HTTP status code being exactly Okay. Yes. I have used another built-in matter from the RSpec jam. In the resources of this video, you can see a link to the article where there is a list of all controllers briefed in matters. Just check it out to get an idea of what's often used to hear. When I send the request in the first line, the response object is being filled in and I can make expectation on its state. This one is equivalent of typing expect response status to be acquired to hundreds. We live it out as a reference. Just this notice that I have used an okay symbol at the end of the expectation. You can use the row number of the appropriate response here. Just a matter of preference, I prefer symbols as they are easier to read. Rice provides a nice helpers to be used whenever you render a status code and they match exactly what's officially listed as the name of the specific status code. I have also prepared a list of all HTTP steatosis we will use in this course with a short explanation about each of them. So you can check them out in the resources of this lesson. If I will run the test now, it will fail with an error saying that there is no such action as index in the controller we want to call. Oh, that's not my expected error. I mess up at the beginning. Held onset. I should send a request to the sludge articles, not the index. Not sure why I messed it up, but it's super easy to change. Now, the error message is exactly what I expect. No actual index in the articles controller. This is the message I have seen in the browser in the last episode. Just let me implement that back very quickly and tried to run the test again. Now, when I have the index action already defined and run the test the second time, it will still not pass, but the message would be much more readable. Now, the message says that the status code differs from what we expect because we return absolutely nothing. And that's the status of no content. Okay? But we want the status code to be 200 or so. To change it in the controller, we need to render the empty JSON object with the proper status code. Actually, the status code here is not needed as when you have any response. It will be added by default. But I like to have such things listed explicitly. Awesome, The first test passed. But obviously it's not enough. Now, it's time to improve it and make it fail. Again. Let me back to the comparators test file and here I will add another test that checks the body of the response name. It should return a proper Jason. In the first line, I will send the request to the same way as above, but the expectation below will be different. You and I need to compare the body of the response now. So let's assign it to the variable first. Has a body, assign a response that body. This however, will be a row JSON object. So in fact, in Ruby it will be a string, which is very hard to work with. I want to make it much easier to check and compares. So I would love to have it as a hash. To do so, I will make use of adjacent model and use the parse method, passing the response body as an argument. As you remember, we expect the specific format of the response to be returned. I will show it again here. We want objects with data key that contains the idea of the resource, its type, and proper attributes listed inside of the attributes hash. Also, all of that should be wrapped in an array. When we talked about the collection of the resources for a single object, the array wrapper would not be here. So in the test, I expect the content to be exactly like in that diagram. I'm most concerned about the content of the data harsh, so I will extract that to a separate variable in a moment. Before however, let's check it out. If our body actually contains a key named data. Then inside of the data attribute, I will place the expected boating. It should contain the ID field set to the article id, then the type being an article strings. And the attributes hash, including article's title, the content, and the slag. Obviously, that will not work because first we have hard-coded static JSON in the controller. And secondly, we didn't create any artists in our test example. In the test using a create method provided by the factory. But I can create a new article. Whoops. And this of course, should be an RI with an object inside as we expect a collection to be returned. Of course, there is no way it will pass as we still have hard-coded empty JSON in the response of the contracts action. I will fix that in the next video. So let me have a sip of coffee and I will come back to you in a moment. 16. 2.5 article serialization: In the previous video, we had been implemented requests, tests to check if our server returns an expected response for listing articles. And I have also added the index action to our controller to get rid of that nasty error we experienced before. Now I will work a little bit on the implementation of that feature. Currently, we render the empty JSON in the controller. And this is what we will seen when I will visit the browser. From now on, we mostly use Postman and I will often say burrows are referring to the Postman app. Our goal for this lesson is all the articles we have stored in the database. So let's just dive into it. If you pass something to the render method in the API controller under the hood, it's translated to adjacent object using the two JSON method. As you may notice, here, we actually passed a hash, not JSON object, but it had been translated to a properly formatted string and sent back to the browser. This feature allows us to pass into the render method, literally entity, which will have the adjacent method defined. As you may expect. When I will fetch all my articles from the database, the active record collection object is returned, and it has the two JSON method already implemented, so it's fully compatible with derives controllers. The same applies to any single Active Record object. So in other words, I can just replace this hash here we've article dot all. And now, when we will visit the browser, instead of the empty hash, the empty RI will be rendered. That's fine, but I wanted the article stupider right? To do so. I need to switch into the terminal and open the rights console. Here I will marijuana other two articles. Testing proposers. If you write your application using automatic tests, it's not needed as we will create two articles before our test is being clowns. But here in the console, I will write article dot create with title set to sample article, content, my awesome article and slack, meaning sample article with dash instead of space. Then I will repeat the same for the second article. Let me just add a number to two, all of those attributes and we are ready to go. Now in the browser, there will be two articles listed, but still there is something wrong with the response. The format of the collection is completely different from what I have shown you before. There is no data key and the whole objects are flat without attributes and type. Also, there are some extra attributes provided like created at and updated at, which I don't want to be listed just yet. Now, when I run my test, I will see exactly what I have shown you in the browser. And for me, jazz the same. Very often I work with my browser being completely closed and referred to Postman mostly to get the documentation about the API to implement. Now let me explain the reason of why this test fails. It happened because rise by default does not use the JSON API standards to deliver responses and serializes their results in its own way. To deliver the expected format, we would need to sterilize records manually, and there are several ways to do so. First would be to override to JSON method on the active record collection and active record base objects. But overriding the rise code is not something I would recommend. The second approach is to write as serializer class, where you have all the serialization rules defined. And for any object passed as an argument, you will produce the appropriate JSON as our result. However, writing all those rules that JSON API documentation provides can't be tricky and very time-consuming. So what I would recommend is to use some gems that will help you if that's the fastest way to serialize records is a gem JSON API serializer, initially created by Netflix team under the name a JSON API. This gem helps us to change the format of the returned JSON for all objects in the application. And the managers, their attributes, links, and relationships. Without too much problems. In order to use it, I need to do three things. First, of course, is installing it. According to the documentation. We will need to add it into the gem file and it will be ready to be used out of the box. So let me do that very quickly. I opened the gem file and here. I will add a new gem named Jason API serializer. Then I quickly ran the handler so it will be installed on my computer. Now, let's create an article serializer class, which is easiest by running the generator that is provided by the gem. In the terminal. I'm going to type rights G for generate. Then the type of the generator or being a serializer followed by the name of the model I want to sterilize. I can also add a list of attributes to be returned in the client's response, similar to creating a model using a standard riots generator. When I will open it, you can see that there is not too much inside, is just a class with a list of attributes. We will pass an article object as a parameter to its constructor. And by default, the sterilizer will try to call exactly those methods on the provided object. We can tweak it out, of course, and if you need it, I will link to the documentation of the gem in the resources of this lesson. For now, the default behavior is completely fine. Whatever attributes we defined here, they will be visible to the client. The only thing that is interesting is the include keywords with adjacent API serializer module at the very top. This single line actual defines the whole behavior of this object. This however, will not change anything in our confidence behavior. Because the last thing we need to do is actually use this sterilizer inside of the index action. So inside of my controller, I will create a new method named serializer, returning a class of the newly created article serializer. Then I replace the row articles collection with sterilised one by initializing a sterilizer with the articles list. Now, let me define the articles variable and we can fix the browser to see what happens. Well, it returns an error saying that there is no article sterilizer. I bet it's because as I have installed a new gem, I would need to restart the server to make it working. Let me do it quickly. And after refreshing the page, the response looks exactly as we expect. Awesome. Let's now run our tests. They still felt though I can see a data key and an RI with proper hashes. But the server returned a hash with strings as keys. And I expected symbols in my test example happens all the time for me. Let me fix it quickly. In the test file. I just need to add deep symbolized keys to the return JSON and check out my test. Again. You can see that the keys are fine now, but there are small differences in the expected and actual values. Here the type I expect is plural, while the actual return value is singular. It's okay, and I will adjust my expectation to leave the default value. However, it's a nice opportunity to show you how to override the resource type if you need it. To do it in the sterilizer, you need to call a method set type. Whatever you will adhere as a value will be taken instead of the default mapping. This should pass. Now, what still failing? Know wha, what is wrong with it? Kinda see a difference. I literally cannot find the difference here. Let me look out the restaurants body in the prettier format. If I will use WP method before my expectation, the response body will be logged out to the screen in the much more readable way, which often helps out finding such little differences. Oh, the value of the returns ID is also the string, not a number. Of course it is. It's kind of embarrassing for me, but I will not add it this video. And we'll show all other banks that I will make during the course as this debugging is a really important skill and I hope you will find it useful that I actually show how to find your own backs. Anyway. Now, the test should finally pass rate. I will quickly clean up the code by removing the login and the restaurant, the default resource type. Congratulations. The articles collection is almost, almost finished at this point. But there is one more little thing to be added here. Currently, my articles collection is returned in the natural order. So the first article we have created is returned first. What we want is to have all the newest articles of the top and old ones being pushed to the bottom of the collection. And this is what I will work on in the next section. 17. 2.6 code improvements: In the last video, we managed to make our controller so distinct articles in the appropriate format. However, we encountered a little issue with our test run. Even with only a single resource being listed. It was a pain to compare those two hashes and find the differences. Also, we will compare the body of our requests in most of her tests. And here is our logic responsible for transforming car server response into the hash that is easier to work with. This could be extracted to a sharable place. So we want to duplicate this logic over and over again. Let me extract this code. First. Do it. I would create a new file inside of the support directory and name it, let's say API helpers. Please notice that it's named because not end with underscore speck. It will not include test examples. So we don't want to run it when we launched our tests. Here. I can add any code that I would like to be available in old test. It is not loaded by default, but we will change that in a moment, so no worries about that. Then I create a module API helpers and adjacent method in it. The body of this Jason helper is exactly the same as we wrote in the test example before. Let me copy that really quickly. Then below, I will create another helper named JSON data and return a value of Theta key from our JSON. In my test, I can now use my newly created helpers, which will simplify the code a little bit. I can compare only the JSON data value here, so the body assignment won't be needed anymore at all. Also, I can remove the data key from here. Now, I need to make this module accessible in our test examples. And to do so, I need to open the rise her profile. Again. These take a look on all of this commented text. It's an explanation that if we want to define our custom matchers are helpers. They should be placed in a support directory. And there is even aligned to load this folder to our test Should we can uncomment that now, the problem is, if we leave it as it is right now, each time we will want to use JSON method, the adjacent APA helpers module name would be required to be called. To simplify that, I will include this module in the RSpec configuration below and the logos to factory. But we did the beginning of this course. And now we can use our custom methods directly. Now, when I run my tests, they should still all paths. That's great. Now let's take a moment to improve our data check. So it will always return a nice readable error messages instead of those ugly hashes that takes so much time to the back. At the very beginning, I would check if the returns restaurants body is an array containing only one element. Then I extract the article object into the variable named expected. Now I can easily compare if the returned type is as expected. Repeat the same for an ID. And below, check the attributes part. Let me copy that attributes hash into the new expectations and now I can remove the outcome. Finally, I can wrap all that into the aggregate failures block to always see all messages that fail. Not only the first one. When I will run this test now, I shall get a nice error message pointing to my ID as it's again, not a string. How cool is that? Now it's hard to miss the difference. Let's look what will happen when I will change something in the attributes section. Look, the difference is also clearly presented, telling which attribute is different and all the rest as they are fine, where he didn't respect can bring you detailed information about the house differences. But for nested hashes, it doesn't work so great. It's a nice improvement for me. So let's go on. Now it's time to move forward and add proper ordering and pagination to our release that will be covered in the next episodes. So let's take a shift post and I will come back to you in the next video. 18. 2.7 recent articles: Hello again. In the last section, we managed to implement the articles listing, and it's actually almost complete. The server responds with a collection of articles now, and it also summarizes the results. So everything is following the JSON API specification. There are a couple of tweaks we would like to add though. And one of them is the proper sorting of the articles. Usually when you visit any kind of link log and newsfeed or a blog, the newest articles are landing at the very top of the list, while the older ones are pushed to the bottom, we want to achieve the same effect here. As usual, I will start by writing a proper test for death. Let's name our test. It returns articles in the proper order. Now inside I create a new article which I want to be their recent one. Then create an article that is older. And to be sure it's older, I will set up the accreted up to one hour before. Now I need to write the expectation. I will compare the JSON data, but I already checked that detailed format of the response in that order tests I have written. So here I only need to verify if the returned records are in the correct order. I will then iterate through those returns objects and return only ideas to be compared. Now, I expect this IDs to be exactly an array, including our recent article in the first place. I'm going to call the request period. It's funny, but the test passed already. Even though we did nothing to change the order. It happens because the default ordering he uses ID of the created frequency. And as the first record I have created has lowered IT. It's returned first. If I will just create those objects in different order, that test will fail. Again. This final example shows why it's important to write the test first. When you expect a failure and the test passes, it shows that your test is invalid or has holes in their implementation. In a moment, I will write a more detailed version of the test in the articles model. So I will not bother with it right now. For now, let me jump into the controller. Instead of returning all articles, I would love to use something like recent on the articles glass. Who return all articles in the proper order. To do so. In the articles modal class, I will underscore which orders that are given collection by created at column in the reverse direction. And that makes our test passing again. But as we have shown a moment ago, it has holes. This is why I will now open the articles model test file. And here I will test there isn't method properly. First, I will create a describe a bloke named recent and prefixed it with dot. So it tells us that it's a class method, not the instance one. Then inside I will write a test name. It returns articles in the correct order. Here I can copy these three lines responsible for creating articles from the other test file. And below, I can check if calling the recent method sorts the articles correctly. This test is green, but now I want to fix the issue I have experienced before. I want to be sure that our scope orders records using the creative ABC column. Something else that randomly matches my expectation. To do so, I would grab my recent article and we update. It's created at column 2, two hours ago. I use have the common here to not change any other attribute on this object. Still, my tests are green, and now the app is fully tested so we can relax and switch to implement the next important feature, which is pagination. 19. 2.8 pagination tests: Welcome back. In the previous lesson, we manage to order our article list to deliver recent articles first. But there is still something to do. Currently, we return all articles at once. But if we would have thousands of articles, this would be a problem. Nobody likes to wait several seconds to get website content, neither. Having the browser to be crushed. To ensure a nice performance, we want the users to be able to specify which page they want bloat and how many items they want to have on each page. In this lesson, I will write a few automatic tests to 35 if our pagination works fine. When I will visit the adjacent API specification, I will get detailed information about how the paginated results should look like. The page parameter in the URL should have a number and size keys to describe the requested page. Also, you can see that except our data section here in the response example, there are two additional keys, including Meta information about the paginated collection and the related links to fetch more resources. In Postman, I can easily add those attributes to the URL. Let's say I want the page number to be tool and the page size to be one. Newly added parameters have been added. This params table below, which allows us to describe each of them or easily toggle whatever we want to keep being visible. Anyway. At the end of the day, I expect this request to return only the second article. And this is our goal for the next episode. Now, I will just focus on testing this part. In the requisite test file. I need three articles to get them easily. I will use create a list helper provided by the factory, but which accepts the name of the factory to use and a number saying how many objects to create. Then I send this request to the server passing pagination parameters to it. According to the JSON API specification, we will need a nested query parameter named page with two elements in it. Numbers specifying which page to load. And the size refers to how many items we want to load per page. Having that, I expect that the length of the return JSON data to be exactly the same as the size parameter value. In this case, it's one. Next, I will add another expectation, checking that the ID of the return object is exactly the same as the second article I have created. There is one more important element to it. Let me copy this test as a one to test if the response contains pagination links that the JSON API suggests to have. Those things help front-end apps to easily navigate between pages. First two lines, I will live the same, but I need to adjust expectations a little bit. I expected the JSON links section to have five elements in it. Then I expect the content to include them, all the links specified in the documentation. This line fields quite long, so I will move it to the next line, 0. And this should be such articles you're now, let me run the tests to see the failures. Of course, we don't support pagination yet. And as we created three articles, all three are returned, which causes the test to fail. Expected failure is always good. Now, I need to actually implement the pagination support, and we'll do that in the next lesson. So see you there. 20. 2.9 paginating resources: In the last lesson, we have written a few tests to ensure the correct behavior of our pagination support. Now it's time to implement that stuff. We could implement pagination from scratch matter. The Ruby community comes with at least a dozen gems for pollination support. Here are three main solutions you can choose from. First, tool are becoming airy and will paginate. Both are closely tied to Active Record, which can be a good or bad thing depending on your needs. For sure, implementing any of those above is extremely easy. As the jazz extend your models. However, I want to use any of them as there is one more attractive gem published, which I use in all my projects. No matter what framework they use to write them. It's a page each gem. And even if it's not so convenient meals, it's thousands of times faster than any of the solutions listed above. However, as this gem is so Framework Agnostic, there is always a bit of code you would write to make it compatible with JSON API format and the Ryan's controllers. I have already written that code multiple times as ER him I didn't know I work with microservices, so I have a lot of smart projects I'm working on simultaneously. I have decided to extract it into a tiny wrapper around Beijing to deliver a convenient experience for any JSON API compatible app. And named it get's some pagination. This is a simple class that we can use in any place of the application, not only in the contours, in any kind of Ruby application. I will now add this to my app as gem. But if you want to use directly, just feel free to copy this source or fork the repo and included into your app. As it's really simple piece of code. I like to jump solution as I already have it fully covered with tests and it's just easier for me to maintain it this way. I will now add the adjacent pagination today, a Gemfile and run bundle install a new gem. Let me quickly show how to use it. I will open the articles controller file, and here you can see that I have only one index action with two lines of code inside. It's rendering the surrealist version of the given collection. And the collection is defined above, and it stands for recent articles list. To paginate the results, I will need a paginated or instance which I can define below like so. And to fetch a single page of the collection of articles, I need to run these pollinator by passing three arguments in it. Our collection to paginate a pagination params hash to tell which page we will fetch. We will define that in a moment. And the base URL. This is used to properly generate links to the previous page, next page, and so on. I will pass a request dot URL into it. Now, let's define the pagination params method. According to the JSON API specification is just a page hash with two nested keys named, numbered and size. Down. Having a collection paginated, we can replace the argument inside of the serializer and the proper set of records will be delivered to the client. I can check how it looks in postwar 0. There is an error that rise cannot see the JSON constant. That's fine. We already saw it. We need to just restart the server as the constant defined by newly installed gems is not automatically loaded during the development. Let me quickly do it. And now I have got only the second article in the response. That's amazing. However, there are no pagination meta-information include that in their response, nor the links to the related pages. I will fix it in a moment. But first, let's check what our tests will return. O, it seems that I have made a typo in the expectation. Let me change that. Here. The expected value is of course the article id. This was a leftover from copied example above. Now, running tests return only one error that the JSON has no links attributes. To fix that, in the JSON API serializer, we need to provide an options perimeter. With JSON pagination. We have everything we need already. So let me define it here to get metadata and just need to call Meta methods on the pagination object and do the same for links. That's all. When I will go back to the Postman, you can see that pagination meta-information and the related links are now both included. You can play around with this if you want by changing the parameters here. But now, if I will run my tests, they should all pass without any issues. Oh, there is one more error in the test example. I forgot that instead of strings here, I should use symbols. Just replace all those keys. And our tests will finally pass. Here. They do. That's awesome. Everything is working nice. But if you don't mind, I would like to do a tiny refactoring. The methods related to resources will probably be used in other controllers tool. So it makes sense to extract them out into a shirt module. The obvious thing would be the application controller. But I will have contrast in the system that complete pagination. So a much better place would be a simple module to be included, the one needed. So in the controllers can turn directory. I'm going to add a new file named paginated or a B. Here, I will define the new module named imaginable and paste the methods from the articles controller into it. Then they also can extract the perinatal call into a paginate method, passing a collection as the argument. Here I pass article dot recent into the method. So the first line can be removed completely. Then I paste the copied code into the body and replace the articles we've collection. Now I need to include the model into the articles controller. And that's all. Be sure everything works well. Let's run the tests. Again. Everything seems to be working quite. The final tweak I want to apply is this options generation. It's the same no matter where I will use the pagination in the future. So it's also a nice candidate to be extracted. I will replace those two lines with a single render collection hyper passing a paginated object as an argument. Then in the patch enable module, I defined the render collection method and paste the copied lines inside. Let me format it in a nice way so it's easier for you to read. Now, the controller nulls almost nothing about how to budget collections. And we can easily use this feature whenever we want. Keeping our classes skinny and easy to manage. Congratulations, you have finished listing the articles. Your application works. It's a huge milestone and I hope you enjoyed it so far. Let me take a break and you should do one 2. As soon we will come back with the next big feature, which is a Session Management. See you soon. 21. 2.10 handling not found error: At this point, we have two working endpoints, studies the articles. And to find the specific one. There is a little issue, though. If there is no article found, we will get an error that it should be handled if you have hunted during the implementation of the challenge in the previous lesson, that's great. Chances are however, that you have manually rescued the active record, record, not found error, and returned there sterilized output to the client in their rescue block. That will work. But when your application will grow, repeating the same code over and over can be tedious. I would like to show you quickly my approach to handle errors in rights applications. I have written at the tiled article about it on my blog. And as it appears in, a lot of people were interested in this concept. I have decided to extract this functionality to our little RubyGem. I strongly encourage you to check out those articles as I have attached them to the resources of this lesson. But going back to the topic, I will add adjacent API errors handler gem to our Gemfile and run the Bundler. Then I will copy this from the gems documentation and paste them in the applications controller. This will map the active record recording found error to Assyria desirable error object and return the nicely formatted response to the client without me needing to repeat the same code over and over in all controllers I have. This gem is very simple to use and well-tested. So I use it in all the projects I work on at the moment that needs the JSON API support. Now, when I will send a request to the article that does not exist, I would get a 404 HTTP status code with an error JSON. Matching the JSON API standards may simply adding more mappings. The mapper in application controller, we can automatically handle all the errors we expect to appear with. Keeping all our consumers slim and cream. For me, it's a big win. I hope you will like it. And if you do and you have an idea how to improve the gym, I invite you to collaboration to make it even greater. Now, when we have it covered, let's move on to the next lesson. 22. 3.0 creating github application: In the previous lesson, explained you how the outflow works. Now, we want to do the first step which is configuring GitHub account to allow authentication via our new application. Greeting the kick hypo of that mutation is pretty easy. We just need to visit our profit setting page and click Developer settings. Here we can click on register new application button and fill the name of the application and the URL you will use to connect from github allows us to use localhost just for development purposes, so we will make use of it. Next, I need to type some short description and field authorization column mature. It's a URL that application or direct to after a successful authorization. And that's all. After submitting the form, will have a client ID and client secret generated. And we can use those to connect to our GitHub API. Now we can start with the implementation. 23. 3.1 create user model: In the previous lesson, we integrated the octagon jam and played around with it to get the feeling what it actually does. We also got detailed user information from GitHub about my GitHub profile. So we know how our user object could look like. In this section, we will go with defining the user model to be able to use it in the authenticator service later on. Just a quick note here. I don't go very fast through this episode as there won't be any new topics covered. We will create a basic user object the same way we did for articles. I'll also use the same validation there. So if the episode feels too fast for you, just pause it whenever you want. Or refer to the lesson about creating article model. That's being said, let's go back to the topic. When they know how our user data looks like and which attributes it contains, I can choose necessary attributes and define the user model. Same as before. I'll use the standard Ryan's monitoring writer and create a new model named user with attributes, login, name, URL, a batter URL, and provider. All of them being type of string provider is not really needed as we will hook up only the GitHub provider. But if you want to make it working with other social media, it will be useful. Here you can see that it created the model, the model test fire the users factory so we can initiate new objects in the test examples. And also on immigration for adding new table into our database. It's quite useful to have those files being generated automatically, so, so it can save some time. Before I run the migrations, I would like to add few tweaks in the create users migration just generated in the editor. I go to the TP mid-range directory and open the file. Here. I'm going to add some database level validations. So we want a low empty values for logging, no matter what happens. Now, let's run the migrations and our user model is created. As I added validations on database level, if we open the rise console and we try to save the empty user, it will rise database error. So let me sure that we also happen Dacians set on the model level. And if they work as we expect by writing few test examples, our generator already created the empty user spec file. Let go the spec models directory and open that file. Here I put the describe block named hash validations. And inside create the test example which should validate presence of attributes. Then in the first line, I build a user using factor generated by the generator. And then I expect that the factory generates the fight object. This is perfect moment to check out the factory and update the data inside. So I open the user factory fire. Here. You can see that only static strings are assigned to newly created objects. I want this factory to create unique logins for each user. You should remember how we did that for articles, just replace the attribute name with a second cyber and pass that attribute as a parameter into it. Then open unblock with one parameter and update the static text to include the sequence number in it. Other fields, I live static to keep things simple, but I'll replace the name with John Smith URL with example.com, uh, vata with example.com slash avatar and provider with GitHub. Actually, when I think about it, instead of user and dynamic number in the login field, I'll use J Smith with the number appended. Now, when I go back to the test, I can finish the example. Next. I build a new object with empty login and provider and Jack few things. First, that this object is invalid. The second thing is that it contains the proper error messages. Expectation looks like this. I expect that user error messages for login includes that can't be blank string. For provider. I can just copy this line and replace the login string with provider. Now, you can see that we actually have two tests in 1. First part checks if factory creates valid user. And second, partials tests what happens if we provide empty attributes, fields logical for me to separate those expectations. So let me extract the first part to a new test named should have varied factory. That's all about testing the presence of attributes, but I need to track the uniqueness yet. The second example in the user spec file then is to track uniqueness of the user login. Test is extremely easy. I just need to create first user and save it in the database. After that, I build a new user with the same login as the first one and test if the other user is invalid. Next, I'll assign a new login to this tested model, for example. And you load them. At the end. I add an expectation that it should be valid now. Oh, and let me fix the typo period. Of course, if we run it now, it will fail because I haven't added any validations on the model evaluate either run those tests. Though, even if a node in fail, to be sure that there are no more typhus hidden in the code. The result looks fine, valid factory check past. But to test related to the validation failed as object we created having no validation specified. Let me visit the model now. I hope you remember. I can jump between related files directly. If you feel confused, just take a look on the bottom of the stream to see at which fire we are right now. So in the user model file, I add validate login with presence set to true and uniqueness also to draw. Then for provider, I just said the presence. Having these validations should make our test passing. I'm switching now to the terminal and run our tests to be sure. Nice. That's all for now. To summarize. Now you have a user object prepared to be used in our application. And you know how to use Octave gem to authorize requests against GitHub API. In the next lessons, I'll create a service which uses the GitHub application to exchange code for access tokens. And we will create the proper authorization. 24. 3.2 octokit integration: In this episode, we'll start integrating out indications and Janie with our application. We could write this, Keith, how about indication from scratch? But there is a RubyGem that does all the stuff for us named octo kit. It allows us to communicate with keeps up in a super simple way. So let's start from integrating Okta. Keep jam with our application by adding it to gem file like so. And then in the terminal shell running compounded common. When installation of new dependencies finishes, we can open the console, try out how the gym works. I will need my GitHub password to show you how it works, but I would not like to share it publicly while screen-sharing. This is why I run the console to environment variables gives a plugin's admin login and a password. Here, I typed some fake password just to show you how to set up it properly. And then I'll do a little clip that thanks to this, we can use these variables to communicate our science with GitHub API as a logged in user. In the console, we can use them as normal environment variables. Now, Let's try it out as a client variable and assign new octagon client instance passing in a GitHub login said to environment GitHub login and a password set to environment GitHub password in order to log in my user. Now, when I call the user method on this client, and it'll get all information about the current user, including logging unit, keeps up with the fatter proper URLs and much, much more. It's hilarious how easy it is. Thanks to the gym. This time we did login user using our GitHub login and password. But we could do the same for our GitHub, client ID and client secret. We had set up our ethical to do this. I need to create new client exactly the same as before. But instead of username and password, I need to pass our API glaciers. Here. I can just copy those from our GitHub page. Now, the user method will return an error as we only authenticated the application. So we are logged out from user point of view to login. We would need a valid code we could use to exchange for access token. And to do it, we will make use of exchange code for a token method provided by the gym. But for now, we can return back to the standard authentication. Having those user data, we can now create our object as we already know which attributes it means. First, let's take a quick break. And if you want to play more with this sharing the console, It's totally fine. Now it's perfect time to do this. And we will cover the user creation process in the next lesson. 25. 3.3 authentication service failure: For the last few lessons, we talked a lot about authentication and the capital of important configuration step to go through it as easily as possible. Now we start the actual implementation of the authentication process. As it's pretty intense. We will also need several lessons to call trait. In the last lesson, we created the user object with some basic validation Smith. Now, we will start the service that will take care of the authentication process. As you may remember from the diagram. If not, here I show it to you again. The first part of oil though, is the exchanging the onetime usable code for an access token that can be used multiple times. So our first goal is to implement the code exchange system. And this is what I do right now. I'll start by creating a new file. It will be stored in the lib directory and I will name it user Authenticator or be. It will be a service that handles the whole authentication logic and wraps in the easy-to-use method. Inside of the file. I define the class user authenticator and initialized method in it. So I will be able to use new on the user authenticate requests. The initialized method will accept code as an argument which we'll use to exchange for access token. Next, I need a testfile. Yes, I know that I should create a style. But for me, really, test-driven development is to help developers write code faster and without unnecessary hidden. But if I know that class is not yet defined or the fire is not yet existing, running a test tells me it does not give me anything valuing them and actually consumes my time. So I often write a file or a class definition with a reverse order and start the test when it's all about defining specific methods. Because having tests for that actually helps a lot of designing the architecture. And the doLogin. That's being said. Inside of the tests. I add standards require with rice hacker and describe block when I can place my test examples. Inside of the general describe block, I would like to have Smile blocks. All test examples related to a single method. Let's call the main method in our service peripheral. Next, I want to add a context. When the code is incorrect. A word of explanation here, contexts is just a block grouping a set of tests exactly the same as described below, that there is not really a difference between them other than the naming. Why are those two years then? Well, just to help us read the test files, when there are a lot of cases to test. Fires can easily get very big in no time. Structuring your tests properly is really good way to not be enclosed in that growing mess. You know that I am separate describe blocks for each method items inside of them, I often use contexts box for each case I described. For example, every conditional statement should contain on case block. Those I often start a war when in this case, it would be when code is invalid. Inside of those keys books. I place my actual test examples. I like to start those names from should do something As a method that does find out metal test is named it. The whole test tree. You could read like describe an instance method performed in the context when code is invalid, it should not register the user. I found it very convenient and I really like this approach. So let write the test. The first example tests that calling method with an appropriate code should rise and error and it does not include their user. It's really simple. I just need to initialize the authenticator with some simple code and expect that calling performance rises in there. As addition, I will check if the user attributes for authenticator is near 01. More thing instead of general error, either rise air specific for this case, so it won't be called anywhere else in the project. You can run this now to see how it fares. The error says that we don't have the proper class defined it. I forgot about that. In the new version, the lib folder in the root directory of our project is not loaded by default when application changes. To solve it, we could update the application configuration to load it by default. But I'll just move the outer locator service into the newly created lib directory inside of the app folder. It just easier as all folders inside of the updater are loaded by default. Now, when they are in tests, it just says that we don't have the performed method defined. Now, I can visit my service implementation file. Here, I add a performed method. And for now the only thing I'll do is rising a custom error of class, authentication error. Then I define that arrow class at the top of the file. Plus authentication error that inherits from the standard error. I also don't have a user attribute on my authenticator yet. So let's add the read-only attribute named user, which by default is not. Now the first test passes, but the service isn't finished. Of course, we need to improve the test coverage in the next iteration. And that's the spirit of TDD. Second test example will be for the case when the code to exchange is correct. It will be a little bit more complicated, but don't worry, we will make IT pro for now. Let's take a quick break, however. So we can go back to it with fresh minds. 26. 3.4 authentication service success: In the previous lesson, we started the implementation of our authentication service by implementing the case when the cold we got from the front end to exchange for token is invalid. Now I do the opposite. I visit the authenticator test file again. And here I'm adding similar content block to the one I already have, but this time I name it when code is correct so I can group tests for my new case. Next, I add a new test and name. It should save the user when does not exist. In this test, I also need delta indicator, same as in the previous example. So I could copy that line and place it in the new test. But actually extracting it to a variable accessible in the old test examples will be much better idea. Let me cut that and wrap the variable name in the lead helper and put the body inside of the dock. And now I can write only an expectation here. I expect that the authenticators perform a method called with the proper code, change the total amount of users in our database by one. You probably noticed deprecated perform call here. I can extract it the subject same way we did before. Now, it's much better, but obviously it can't pass because at the beginning, both tests are completely the same and the only difference in the expectation. The second example will fail because the performer method always rises an error. To solve this, we'll need to mark the cold to act as the correct one in the second example and as bad in the first one. To do this, we need to know more details about how the performing method look like. As you remember from previous lessons, we can authorize the GitHub application by creating new Okta, keep clients with client ID and secret params. Having that, we can use bunch of methods to communicate with GitHub API. One of which is exchanged code for a token which accepts the authorization code and returns GitHub access token as a result. Based of their truth value, we can then check if the coal we passed is valid or not and rise an error only in case of failure. Now when we finally make use of code here, let's make it available in all methods in the class. But how can we know that the code is invalid? Well, you could refer to the article gender augmentation, but I'll show you the other way to validate that. Let me feed it the console workweek. When you initialize the GitHub client with proper ID and secret instead of the login and password, you can call the exchange code for a token method and see what it returns. For invite code, it returns hash with arrow name, description and the euro. But it's not a regular Ruby hash, but rather the object of class named Sawyer razors. That's all we need for now. Now I can back to the editor and visit my service implementation file. Here I rise an error only when the arrow key is present. Otherwise, I'll play with the user registration. When will now run the RSpec comment, it will fade with a lot of federal messages because the octave gem returns not found error. Instead of what we expect. That happens because we initialize the client with empty GitHub ID and secret. So when we want to call anything on the invalid client, you can say that the GitHub application we want to authorize is not found. So do we need to create another good CUP application for tests? Sure we could, but there is one important note to mention about tests. Whenever possible, our tests should work independently of other external surfaces. For example, if you run your tests without Internet connection, they ideally should all pass. Having that in mind, we would like to avoid the October gem to send the real requests to the GitHub API when runs in that test environment. I trust the gym works while when I provide it with proper arguments. So based on the documentation, I can just stop the gems methods to return what I expect them to return without sending any kind of relay requests. In the first test, I want a bad verification code error. So before the test, I add a before block. And inside of it, I assume that any instance of octo kid client can be called with a method named exchange code for a token and return the proper error. If you're not familiar with this, treated as overriding the method in the brackets. What this code does is just telling our test engine. So whatever It will see this exchange code for a token method called octal kit client class. Then instead of going through the real metals body, just skip it and return the error object I define. The error is a mocked Sawyer reserves object with arguments copied from the rice console. I only add the error attribute as I don't need others for now. So now let's run the test. It passed. Great, great. So let's jump to the second one. Again. It fails because of not found error. So it's the same problem. In this case. However, we want to stop the exchange code for a token method in similar way, but allow it to return a valid access token. Oh, it fails saying that there is no error method on the returned string. Let me fix that really quick current test. We mark the result so it returns valid string. And obviously there is no method error on the string. This is why I add a conditional method call here. If the returned object has no error method, instead of rising and error, it will return nil. Writing kipp now solves the problem of not found error, but the test won't pass yet. It fails with expected message though, as we haven't implemented creating the user yet. So this failure is not bad because it tells us that we are going in the right direction. Again, let's go back to the implementation. When we have the access token, we want now log in the user using it. As you remember, access token is a replacement for user's username and password. So we can create a new client with this token and act with it exactly the same as I would do it using username and password. I want to create a user with data received from GitHub API. So I can call user on the user client to receive the current user's data. I'm going to figure out how to extract only the proper attributes from the hash received from GitHub. To get immediate feedback, I will again use arise console for that. Here. Calling user on the user client will return a soil resource object with a lot of data I don't need. I don't really know the soil resource class in details. So it's much more convenient for me to work with regular hash. Let's check out what the two h method returns. Okay? That's a hash with just extra parameters. Now, I can use a slice method to get only attributes required by my application. Those will be login, URL, a battery, weather, and name. Naive. Now I'll copy that line I figured out to the editor. Then I can create the user with prepared data. I also need to set a provider here to give up as we require it in our user validations. Oh, there's assignment missing here. Now, let's go back to the test. Until now, we only mocked the application client to return a token. Now, what do we have the token? We use it to simulate logged in user is de facto the new client. And we also need to mock it through a tune what we expect. I add another line to the before block, allowing any instance of octo, keep client to receive user method and return the user data. Now, let's define the data. It will be a hash similar to what factor creates. It will contain login set to J Smith URL being example.com, a battery URL. Also example.com with our string upended, and the name is set to John Smith. Now, running the tests should pass. Nice. I can jump now to the next iteration. But before I do that, and quickly ensure that saved user has the same attributes as data provided. Okay? Okay, we've finished the first part, but there are some more or less obvious problems yet to be solved. Currently, we always try to create a new user. In the next lesson, we'll try to reuse one that had already been saved in here and create one only in case that the one is not registered before. 27. 3.5 fetching existing user: At this point, we have our service which communicates with GitHub and registers the new user. If doubt indication succeeds. Let's go back to our test now. Now I can write the next example for the case when users already been registered before. In that case, I don't want to create a new object, but reuse the one that's already been saved in our database. To check that I will write a new test named should reuse already registered user. Here I create a sample user with the properly prepared attributes being exactly the same as what we expect from GitHub serotonin. And then I will check if authenticators performed method reuses this user. It fairs as expected. As our method always tried to create new user. It's easy to fix by adding a condition. If the user with GitHub login exists in our database, find existing one, and otherwise create the new one. Then the result will be assigned to the user instance variable. Quite straightforward. Our user authenticator service is almost complete. There is one more thing to add, but the performance is already very long and complicated. So let me refactor it a little bit to make it easier to read and change later. First, I will extract application client to the separate method with the same name. Then assign a new octane object to the instance variable named Client only in case it wasn't assigned yet. Next, I would like to do the same for the user data, but this makes use of GitHub token, so a neat to make our token available for methods. First, I move the token assignment to a method. And only then I do the same for user data. I can merge those two lines. Now. Finally, I can also extract the conditional user fetch to the prepare a user method as I have already user data accessible. Now, our method is much cleaner. Let us verify if it works properly stood by running old tests. Everything is green. So we can jump to the last part of the service, which is that token preparation. 28. 3.6 create access token: In the previous lesson, we implemented the method responsible for completing users logging in and registration. The problem is that currently we only made use of the GitHub access token to fetch some userData. Having that token, we can act as user against ePub API. Now it's time to add the same for our API. So, so we want to create another token that front and we'll use the authorize requests against our API. In the same way we do with keeping upon the rule is the same. Create a falling test, which would be green after implementing the feature. And this test will be named, should create and set users access token. I expect that calling the perform method on authenticator changes the token count by one. Then in the next exploitation, I test if the access token on alkalinity Jeter's object is present. Now let's jump to the implementation of the surface, to the performance. At the end of it, I assign a user's access token in case the user already has a token present and otherwise create a new one. I also need to set access token attributes available for read. The problem is of course, that there is no object like access token Nadir, the association on the user model. I need the token object now, which I can generate using cries generator in the shell, right? Rails generate model access token, which is a name of the object with attributes token and user object connected with belongs to a relationship. Before I ran migration, let's verify if files have been properly initialized in the token model that belongs to a relationship with user is set, which is nice. After switching to create tokens migration, I can see that on attribute types are correct. The only thing I would like to do here is adding the same rule I did before for users to not allow null values for token string. Now, I can run migrations and implemented token generation launch. Usually I would start by writing tests for our object validation, but we did it twice already. So in this case, a strongly encourage you to do it on your own. And I'll show you the complete solution in the next lesson. So in the token spec, you'd have a blank tests to implement both inside and in the token model. I write validations in a moment. Let's check what happens if we now run our authenticator tests. Seems most of them are failing because there is no access token method in user model. It's quite clear what should we do now, isn't it? I opened the user model file and add a relationship named token. But that won't solve our problems. Running tests, again, returns error message that looks scary at first glance, but actually it's quite expected. We have updation on the database level to disallow saving token with null value. But we don't have any validations on the Ruby levels yet. In our authenticator service, we create the new unified token so the database returns an error. You should be able to easily add those validations for token attributes, presence and uniqueness without any problems now, so I'll skip it and move directly to the token generation implementation. To make this test passing, I want the token to always have a unique value when is generated. So let me open the token spec file and write a new test example. It should have token present after initialization. To test the token initialization, I need to use access token. This test will fail as we don't have any callback running after initializing the object. I can fix that by adding in the model after uninitialized callback, calling a method named generate token, which will be defined in the private section. This method will include an infinity loop, which will set the token attribute using Ruby's random string generator. This loop will break if the token is set and we don't have the same access token present in our database yet. Now, all our tests pass. At this point, they authenticate or service is finished. Congratulations. Now you can authorize requests to allow users creating comments and articles which will cover during the next lessons. 29. 3.7 create session route: And with this point, we already figured out the complete logic for our Anthony location service. The last part of our dedicating our users is to provide endpoints to actually manage sessions. We'll cover it in the next few lessons, starting with creating sessions, we had a post request that will cover both the login and registering new answers. We would like the users to be able to send a request under a slash login URL with the code attribute. And as a response, we want to give them the token they will be able to use for authorizing or future requests. As always, when I create a new endpoint, I start from adding a routing test. So I'm sure that proper URLs are served by right controllers and actions. I already have the articles routing spec. So my new file will be pretty similar. I have named the new test file access token spec. And here I add a required class, WAV files hyper and general describe block named access tokens roads. Now I'll add a test that should route to access tokens. Create action. Here. I expect that the post request under the login URL will be served by Tolkien's controller create action. This won't work as we don't have the login URL defined yet. So I visit the roads are py file and update it by adding the line with my login €1.1. More thing to make our tests passing is to create an access tokens controller, as it's missing here. As I want also the test file to be created, I'll use derives conflict generator to create the proper controller. Now my test file with path, so I can jump to the controller implementation. 30. 3.8 create sesssion controller failure: We have our routing for creating sessions prepared. So now I would like to add the controller for that. At this point, it shouldn't be a surprise that I'm starting from writing few automatic tests to describe the expected behavior, right? Will need quite a few tests. So I will split them further using context blocks for Invite requests and success one. It's easier to start from invite requests. So let's do it. We'll name the first example should have four or one status code. If no code provided, I just send a request and expect that the response has HTTP status code of four or one. Running the test, show us that we don't have create actions specified yet. So let's go to the controller and added. Next. Let's run the test again. Now the status code in the response is not modified because we returned empty response. Fixing this test is quite easy as we only need to render empty JSON with specific status code. This line obviously doesn't work as the feature assumes, but it already makes artistry. This is good example to show you that the fact you do test-driven development doesn't mean you don't make mistakes. We need to add more iterations and write more examples which fail to improve our implementation. First of all, we don't want the empty JSON. When you visit the JSON API documentation. In the example section, you can see that they suggest the preferable error format. And we do want to be sure that we meet those requirements. I'll copy the error message from the permutation and paste it here. A new test example in which I can easily adjust it to my needs by changing values of all fields while keeping the structure and touched. I change the code to four or one source to slash code and title to authentication code is invalid. Finally, a change details. So you must provide valid code in order to exchange it for a token. There's this obviously red, so I can go to the creation action. But first, let's update this hash. We will need strings as keys in the restaurant hash, not symbols. So we should update it here. Same in the expectation. And as the result is an RI, we want to check in collision instead. Now I visit the controller and here I'd render exactly the same code I wrote in the test. And now run RSpec file will show us Rinne results. We don't want to always return an error TO, but only when the authentication service will say we should. So now and finally, make use of our authenticator service. As an authenticator, I assign a new instance of the user authenticated class and pass as cold, the parameter is sent to the controller. Then I call the perform on this authenticator. We would like to return the error only when performed call fails. So we could wrap this code in the conditional statement. But I will show you cleaner solution. When we visit our service. In the performed method definition, you can see that it rises an error whenever the GitHub API payloads. As you all know, as you all know, when exception is reason, the code breaks on that line and no line below error is fired. This way, we can get rid of this if else statement and add the shortened version of the conditional to rise an error if the code is bank or the Token error is present. If any of those conditions are met. Error is reason and no code below is called. Having that in mind, let's go back to the controller. If we know that the perform method rises and error in case of Vader, we can handle that by wrapping the code in the begin rescue block. This way, whenever perform call rises the user authenticator authentication error. Instead of breaking the application, the content of the rescue block is called. Now we can easily refactor it even further by extracting the error handling to a separate method, let's say authentication error. This is already pretty clean, but we will do even better. And because we have the error handling in the method, we can now use the rescue from helper passing as a first argument. The error class you want to handle. A second, the option hash. I've used the option with as a value specifying a name of a method to call if the error appears. Now, I can get rid of all of this crap. Oh, and need to fix a typo here. It needs to be a symbol or a string with a method name, not the actual method call. Now I can run the test and everything should pass, like there was nothing changed. Awesome. There is only one little thing to do yet. All our contours will behave in the same away, cutting our errors with no difference. This is why we should move the call to the more shadow place. We could create a module or hyper class. But for our little application, it's good enough to move it to the application controller and just copy and paste all the code responsible for the error handling. And now, not only we have completed the authentication error handling for the controller, but each controller in our application can easily use it. Wherever in our application, the authentication error is reason. The application controller will handle the error in the same way. We can now run our tests to be sure that we didn't break anything. Let's take a break for now and we'll go back to this session conflict in the next lesson. 31. 3.9 shared examples: In this lesson, we could directly jump to the sectors block call, but I want to show you the one thing. Last time. We move the short code, the application controller, so we can easily reuse it. And the point duplications in the code. But the same applies for tests. We want to check that request with empty code and invalid code behaves exactly the same. So normally it would be a lot of code duplication here. We want to avoid that. So it's time to refactor this a little bit. First, I'll replace the request calls with subject method that can be easily overridden. Then I'll prepare the shirt examples block. Fortunately, RSpec provides us a helper when we can extract all test examples that behave the same way for multiple cases. For now, I'll add it in this controller test file. But if necessary, they can be easily extracted two separate pile and re-used in other test files as well as the helper is named shirt examples forum and accepts an identifier as an argument. This is used in context blocks to specify which chart example set we want to use. I named them an authorized the request. And next move, everything that should be shared. Insight. So for sure the authorisation, error definition, and also both test examples related to the error response. Nothing changed. But in the context block, I was left with only subject definition. Now is the best part. I can just add that it behaves like helper with identifier for our shared examples book. And now all our shared a test will be called with the subject, the fine in the contexts, like it working with invite code parameter, I just need to copy the contexts. Change the name of the first 12 when no code provided, and the second two when invariant called providers. Lastly, I just update the subject definition and all of my shirt tests will be called in different subject in the second contexts. That's crazy. So let's run it to see what happens. You can see that tooth first tests pass same as previously. But if we passing valid code as a parameter, we receive octo key not found error. It's familiar, isn't it? We already solved it while testing data indicator service. So let me open the user authenticator spec file. And here we are interested with before block and invalidate request to tap a GitHub API requests. Here. Let me copy that. In the controller file. We already have an error define, avoid any surprises, will change the variable name of the GitHub one to GitHub error. In this little fix, make all of our tests passing amazing. So in this lecture, you'll learn how to extract chart examples in RSpec to avoid cold applications and a lot of unnecessary work when your application grows. In the next lesson, I will go to the success part of this endpoint. 32. 3.10 create session controller success: In the previous lesson, we renamed to handle the authentication error and return nice error message to the front. And we also prepared the shirt test examples and two contexts blocks that calls them. Now, I can jump this axis book to test the case whether the proper code is passed in the params. I name the test, it should return 201 status code and it will call the subject requests and then compare the HTTP status code to check if it's created. Next, painting to define the request call, to send a post request into the create action, passing a valid code as a parameter. Let me add an empty line here as it hurts my eyes. The problem is that the RSpec does not know if that code is valid or not. So when we run tests, we will receive the familiar occupied error. You probably know what to do with it, don't you? We need to mark our GitHub client to accept our arguments in the way we want. So as we covered the problem already, without deeper explanations, I am visiting the authenticator spec file and copy the code, mocking our GitHub Service. Now, test should return expected error message, saying that status differs from what we expect. It's fine. We don't return anything. So the response is no content. Adding one line in the controller will fix it and just render empty JSON with status defined tool created. Now it's green. So let's write another example for gradient compression. I name it should return proper Jason body, same as before. I just call our request. But this time I compare the attributes of the return JSON to be a hash with attribute token set to our API access token. I hope you remember why I don't use varied access token string here. The token we want to check here is the one that is saved in our database. While the varied access token string is a token that our API receives from GitHub. It's irrelevant from front-end perspective. So we know that calling the request creates new user with a token. We can injure it's a thing by adding expectation that calling a subject changes the user can buy one. We also know that newly created user is created based on the user data hash that we pretend to be received from GitHub. Then I can use those data to find a user by login J Smith one. Having that, I can change the access token variable to user access token. Token. Of course it will fail. As in the controller, we were to always the empty JSON message. Instead, we want to return our access token properly sterilized. I now go to the terminal and generate the act is to consider the iser, same as we did for articles before. Now, let's check out this file. And here I add a token attribute to be accessible in the JSON responses. Then going back to the controller, I can replace the empty JSON here with the authenticators access token object, and it should solve all our problems. The red seems we found a bug in the code. That's fine. We'll debug it in a moment, but let's take a closer look. The test says that the token value differs from what we expect, but the JSON structure is exactly like we want. We made a big step forward and thanks to practicing TDD, we detected a back with a code generation. Let's check it out. I'm not sure what the problem, but it seems that either we create to access tokens or just generated twice. I'll start the backlink from adding few console logs in the test example. First, I assign access token to our variable and then puts it on the screen. Next, I reload the object, lock the token again, and run the test. Okay? Hearing logs, you can clearly see that each time we reload the object token is regenerated for some reason. Before I'll visit the model implementation. As it's a bug related to the model. I would like to add a model test to cover that problem. So we'll be sure that it's never happened again. This is what advanced developers usually do. They write a test to reproduce the problem so they know when it's fixed just by running the test again. So in the model, I'll add a test. It should generate token once inside, I could create a user insights. I quickly create a user assigned as access token, newly-created access token on user object. And then expect that the token is exactly the same before and after reload. Let's run it. Okay, it's failing. So we covered are back with dedicated tests. Now, it's time to fix it. I'm switching into the access token modifier. And here, let me see. Oh, I see the problem. Whenever we instantiate the object. So in they're created or load from DB, that doesn't matter. We will call the generate token method. This means that if we save the token in database, then it's present, but it already exists in our database. So the second part of the condition will never met. I'll add a little filter to not include the object with ID of the current token when checking uniqueness. And now it should solve everything. Seems it did. Model tests look fine. If we call the Conqueror tests for access token, they also pass amazing. Let's call all our test examples written so far to be sure everything worked nights or green. This is amazing. Because of test-driven development, we detected a bug in the code, but not only that, we also managed to solve it and ensure that will never break in the future. That's the spirit of TDD and this is why it's so awesome. I hope you like it as it's the best way to create software. So far, this was a huge success at the registration and logging processes for user are now complete. Congratulations. Now let's take a quick break and see you in the next chapter when we'll cover the session remover. 33. 3.11 authorization error handler: In the previous lesson, we implemented the whole registration and logging in users processes. So now we will proceed with session removal and go back to the access tokens roots spec. And here I can add a new route expectation that should check if there is a root two tokens controller destroy action. I name it should route to talk as destroying. Inside, I expect a delete request underdog neural will be served by Tolkien's hash destroy action. Then I need to add the DV truth in the routes.rb file to make test passing. Now, when roots are doing fine, I can work with the controller. Let me visit the axis contour spec file. At the end of it. I add another describe luck with delete method and destroy action. Here. Then I need the context block 200 cases when authorization header is not properly set up. I need to test examples. First one checks the status of the header. I name, it should have four or three status cold. You probably noticed that the status code differs here. This is because we use Forbidden error. There should be distinguished between the error related to authenticating the user and the 100 situations when already authenticated user tries to access resources that one has no access to. This time, we want to allow users only remove their own access tokens to logout themselves. This is why we need to add a test for authorizing requests and deliver forbidden responses. It's completely analogic to the profit situation. We call the subject and expect that response have HTTP status code forbidden. Then we add another test example that should return proper error body. And here check the JSON response to be exactly as Forbidden error we didn't define yet. Let's go to the top of the file and change this general area variable to be more specific. Let's say authentication error. Then I can copy it to the bottom of the file and transform it to be forbidden error. First, I change the name to the Forbidden error. And status 2, 4, 0, 3 pointer will be headers authorization. The title I would change to not authorized. And details. You are not authorized to access this resource. And then at the top, I define this object to be delete request calling the destroy action on the controller. Now it's finally done. I can run it now, allowing test failures to guide me through the implementation. It looks familiar, doesn't it? In the counter? I need to implement the destroy action and rise the proper error inside. You probably notice that here we also use authorization anthro class that differs from dogs indication error. We already had, we have our error handling in a general application controller. So let me visit that file. And here I just create a class authorization error and add a rescue from luck with authorization, enter as a first argument and a method to call named authorization error, then it's time to define it as an error. I paste a hash from the test we just wrote. Then I render JSON with errors key, same as above. Now, rank tests should give us green results, nines. We could end up here. But there is one little thing to do in Forbidden error will be used everywhere in creating articles, comments, updating everything. And even here in Logan out. This is why we need to once again make use of shared examples, but also extract that error related code to a separate file that will be accessible by other controller tests. We'll do that in the next lesson. So be prepared. 34. 3.12 refactoring error tests: As I mentioned in the previous lesson, will need to test error responses across the whole application. It would be nice than to not repeat the same over and over to not waste your time. To avoid it. I extract our error related examples to another file when they will be easily accessible for all tests files. I'll start from extracting our new Forbidden error tests to A-sharp examples as we did once before, named them shared examples for Forbidden error. Then I'll copy the code related to the error response inside and paste them in it. In the context doc. Now, I need to type on the one line saying that it behaves like Forbidden error. Actually, when I think about it. So keep things consistent. I'll rename our shared examples to forbidden requests. And it should be underscore instead of space here. Now let's ensure that there is no typo here. And we can run our tests again to be sure that we did everything right. They all passed like there was nothing happened. That's great. So it's time for the next step. So we'll work on managing articles and comments, and then we'll be also need to have access to those shirt examples so we could easily test authorisation failures. And this is why we'll create another pile in the spec SAP or directory and add another directory for shared examples and name the file, let's say JSON errors RP. Now I'll just copy our shirt example in sight. I probably need arrives helper here. So let me add it and then copy the other block for the authentication error. Believe me or not. But that's all. If we go to the terminal and run our tests, they will all pass. It happens because in the rise helper, we load all fires in the support directory by default. So until now, in our tests and just typing this one line allows us to easily check the whole error handling behavior. We can also extended in one place without need to change all tests across the whole application. Let me demonstrate that. Here we send a request without any authorization header set. Better name for this context will be then when no authorization header provided, then we can add another context for the case when invite authorization header is provided. Inside, I need to add a before block. So before each test IN set direct list header named authorization to invalidate token string. I need a subject method available here. And as it's the same as in the previous example, I can just move it up one nesting clever. Then I only need to check whether it behaves like the forbidden requests. Now, all our shirts test examples will be called with updated conditions. Now running tests results with ten examples passing with almost no effort to add two new ones. I hope you liked this optimization as it allows us to easily check every failure action in the future. Let's pause here in the next video and go with the successful authorization and logging out processes. So see you there. 35. 3.13 logout and authorize: Last time I covered the unauthorized requests and refactor the code to make all shared examples are viable for every feature test file. Now, we want to also test the case when user passed proper authorization header in their requests. That'll be scared TO. We already figured out almost everything. Authentication and authorization in general is a lot of work. But it's the last lesson related to that topic. So let's go on. Inside of our contents doc. For requests. I'll type few more automatic tests. First, as usually tests or response status. I won't even comment that as it's pretty obvious, it should return to o for HTTP status, which has corresponding helper of no content. Then another test should check if the proper token is destroyed. So inside of it, I'll send a request to the server by calling the subject. And then I explained that the request call will change the access tokens count by minus one. The subject is the same. So I only need to define a user and access token variables. And then in the before block, first, I said the authorization header the same way as few lines above. But instead of that string, and use a bearer type of authorization appended with our access token. If you want to know what the better authorizations and put an article about it in the resources section. Feel free to check it out. Even if I know that we're all seeing proper error messages shows us that there are no typos in the code and that tests are properly set up? Yeah. When I say typos, I mean exactly that. There is, of course, no HTTP status code. The metal. It should be just have HTTP status instead. Now running it logs expected results. We have four or three error code instead of what we need. Now it's time to implement or feature in the destroy action. I don't want to always rise and error, but only if there is no current user defined. We don't have the current user at all yet. We note though, that front-end will send as the access token. And we want to get user based on that. So as current user, I assign access tokens user. Now, how can we find the proper access token in the database? Well, in all our contour, we have an access to the request object, which has a method named authorization. It returns the value of the request header with the same name. In this case, it should contain the access token from front-end. Before I go further though, I would like to be sure that we said this header properly in the test. So let me comment this out and lock direct cost optimization on the screen. Then ran one test again. At the top, you can see our LOC, including barrier appended with empty string. And that means everything we did so far is correct and good sign. But we don't want to take this better under consideration, at least not in our legal application. So let me extract it. I will use g sub method on the string which accepts our regular expression to match a substring and replace it with the second argument. Here I need to check if our string starts from better. This is what this backslash capital a. And if there is an empty character, next, backslash S looks for our spaces and other empty characters. Then I replace the founder result with an empty string. The end result will be that if the provided token starts from better upended by a space, remove that much and only considered the rest of the authorization header. Having that, I can just get my access token variable by finding the axis token in our database using the extracted token attribute. Next, I'll call the user on that token and assign it to the current user variants. There is only one problem here. When we want set the authorization header at all. It could be nil. So there won't be at G sub method defined and our application crashed. This is why I use here as safe navigation operator, which just says, if the variable is just return null instead of rising and error and go on. The same applies for current user here. Now, we can safely remove our token if the error is not reason and checkout the result. Our tests are green. Awesome. So now there is a refactoring time. Let me go back to the continent. We just wrote a part of the code that would be required by every controller and each action that requires authorization. This is why I moved at all to the application controller. Then I define the access token method and do the same for current user. Finally, I change the normal variables, two instance variables to avoid circular dependency. Then I can also extract the line with rising and Arab dye method and application through there. Let name it out arise with exclamation mark. So it's clear that in case of failure, it would rise an error. Having that in the tokens controller, we could just call the before action and check if the user is present or not. As you can see, all our tests are staggering. That is completely fine solution and very common one. But when we talk about authorization, there are two approaches to take care of it. First is what we just did, allow everything by default and restrict access when needed. I don't really like the solution TO, as it's very easy to forget about something entered, then users get too much actors in our application. I decided to show it to you as it's widely used, but my preferable approach is the opposite. Though. By default, I restrict everything and allow only necessary resources. Let me show it to you. In the application controller, I add the before action call to authorize everything always. Then in the corresponding contours. I just skip that before action. If the specific endpoint should be public. As we have also articles controller, we've public endpoints. I need to include this scheme before action. Also there. The amount of work is comparable, but the level of App Security is much, much higher. Now if we run our tests, all of them will pass. But removing the line with skipping the before action for outright method will result with few failures related the articles coupler tests. I didn't know what to say. Now, congratulations again. We just finished the complete authorization and authentication flows. Now our application is safe and we have prepared the end Jain to handle all errors in our API. In the next section, we'll start articles management. So see you there. 36. 4.0 create articles routes and failure: In this lesson, we'll cover the article creation may locked in user. We did listing and showing particles the beginning of the course, but this is our first endpoint that requires authorization. This is why I decided to do the whole user authentication between listing the articles in this lesson. So let's start. I create each new endpoint by starting with implementing the routing test. You probably remember they're rooting articles Packer beefier, where we already have tests for listing and showing articles. Now, we need to focus on the endpoint to add an article. We'll name our test should route to articles create. And inside I add an expectation that the post request under slash articles URL will route to articles controller create action. It's very similar to the example testing the index section also that tests for update wrote will be analogic to the show above. Having that we can visit the router. I'm going quite fast for this part as we already did it before. So there is not much to explain. In the roots are beefier, we need to add the create and point to the root least definition. Now, we can run our tests to ensure everything works fine. Good. Having that, it's time to play with controller files. Let's jump to the articles conference back for now. Here we have to describe blocks. One for index section which lists articles. And second for show to get specific one. Those are public endpoints that don't require authorization, so are not complicated. But articles creation will need a bit more tests examples for creating articles. I'll add another. Describe luck with few contexts blocks. One for our case when user is not authorized and another one user is authorized. In this lesson, we will take care of only the unauthorized requests. So inside of it, I implement the test coverage for that context. Thanks to what we did before. And now authorized context is extremely easy. I just need to define the subject requests, which in this case will be post to create action. Then the only thing I need to check is if the response behaves like forbidden requests. In this case, we don't provide the authorization code at all. We'll want to test also the context when invalid code is provided. So let me rename it for now. Now, of course, it will fail as we don't have the create action defined in the container. But if I just visit the controller and add the create method there, I can run our new tests and enjoy the green report. Next, as I mentioned before, I want also cover a case when invalid code is provided. It's all about adding new context with the same subject defined. But this time I'll add a before block. So before each test inside of this context, the content of the before block will be called. Then inside I said the header on the request named authorization to some invalid access token string. Here you can see that subject is completely the same in both contexts. So I can safely move the definition one level up. So it will be accessible in both test groups. Being defined on nuance called application is just bad. Lastly, I just add align. It behaves like forbidden requests to the second context dock, and we are ready to go. Now when we run our tests, we can see that two more tests having added without almost no additional effort to write them. It happens because all new endpoints by default require a polarization and behaves the same way for all unauthorized requests. Okay, we're moving forward pretty fast, but there is more to do it. Let's take a quick break for now, however. And in the next lesson, we'll take care of serving the request. We've invited parameters provided, and delivering the invalid error messages. 37. 4.1 create invalid articles: In the previous lesson, we tested the unauthorized requests to the end point for creating new articles. Now it's time to handle validation errors. Here I add a test that check if response returns validation error, HTTP status code. Let's name it should return for 22 status code insight. I just call this object and then add an explanation. I expect response to have HTTP status of unprocessable entity. Then in the next example, I check if response returns proper error basin. Again, I call direct West and expect that error key in the Jason include the validation error hash. Just quick notice, I don't really remember the exact validation error format. I trust that gem I use covers that case in the correct way. So for now, I paste the standard error format and I adjusted if needed in the future. In the adjacent areas, heavy fire we prepared before, we have the authentication error. I just copy that and change the body to match my expectations. Here, I need the status of 42 tool, which corresponds to validation error. The source should be set to data attributes title. Then I need to adjust my title and content. And this is the tough part. I change it to. Can't be blank and to the title you provide. It cannot be blank. But I would probably need to adjust it in a moment to what the server responds with. Anyway, having that, I just need to specify my subject method. It will be a post request with params set to invite attributes variable, okay, but it will be hashed, so there should not be additional curly brackets around the variable name. Then I defined the invalid attributes hash. It will contain a data key with attributes inside I play's title set to empty string and content as well. Now, close our brackets and we are almost ready to go. The problem is that if I run test now, it will fail with Forbidden error. This happens because we have no authorization header is set in the context. So let me wrap tests for Invite requests into another contexts named when outer rise. Here. I add before block. When I said the header to the valid access token. I don't have the access token variable defined, so let me add here. Now save the file. Oh, and my editor complaining that I forgot to close the block with end keyword. Now it's fine, and I can finish it up. First. I call the token method on the access token object and rapid into the stream prepended with bearer keyword. Finally, we can run our tests. The reported message seems fine. It says that we have no content status code. Instead of 4, 2, 2. It's expected as we have an empty method defined in the controller. Let me jump there to implement the feature. In the first line, I build a new articles with proper article parameters sent to the server. Then I add a condition that if this article is valid, I will save it. We will handle that in the next lesson, but for now, we'll take care of the else case. When the article is not valid. Here, I want to render the JSON passing article as a body and specify the status to be unprocessable entity. We are almost there. The only thing left for now is that article params variable, which is not defined yet. Let me add a private method named articles, poems, which for now we'll just return an empty instance of ActionController parameter glass. If you wonder where that came from, try to call a class method params object in your controller. You will get exactly this glass as a result. Now, let's run this test again. The first test passes. As you can see here, the problem is that return JSON is invalid. We pass the article objects to the JSON. So rice things that we want to use the default serializer to format the response. If we want to return the JSON API formatted validation error, we need to do a little trick here. First, specify which adapter we want to use to generate error. In this case, It's JSON API. And the next tell rise that we want to use error serializer, not the article 1. And the active model serializer dram has built in solution for that. It's active model serializer, error, serializer. Now let's try it out again. Okay, something happened. That comparison always looks carrying test results. So don't worry, I don't like it either. But they say what we need. Our test detected that we got three validation errors in the response. They have source and detail keys, but no status, neither the title. It's fine. I told you before that will probably need to adjust our test I took bit later. Now it's time for doing that. In our failing test example, I just copy the title to the details section and remove the title completely. Then I also removed the status scheme. It makes sense the whole response has four to 20 status code, so there is no need to add it in the, each element of the array. Now, when I adjust the content of single element, I can duplicate it twice and replace the attribute name in deprecated objects with content and Slack. Now, if I run our tests, they'll pass correctly. That means our application properly handled invite request, the server. In the next lesson, we'll cover this access request coal and finally, create our articles. But for now, quick break. So you and me kinda refresh with a nice coffee. 38. 4.2 create articles success: In the previous lesson, we handled the invite article, and now we are ready to go with the final part of actual article creation. First, we want to copy the access token and authorization method from the block above. Then we will need also the valid attributes cash. It's easiest to go back to invite attributes definition, copy that, and transform to valid ones. First, change the variable name to varied attributes, and then fill the attributes with some sample data. Let's say this is some typo, some supercontinent. Here. We also named as lag, by the way, the mold. And there is a typo here. Let me fix that here. And in the environment attributes above, sorry for that. Another example. Why TDD is so awesome. Even if validation failure rate examples did not catch the type of the Success Blog, definitely would not pass without fixing kid. So, okay, let's go back to the coding. We need to add a slug here. As you remember, is the title with dashes instead of spaces. Actually, let me change that. Again. I want a little bit shorter strings here so I won't have problems with remembering them. So let judges to awesome article, super content and awesome article with dash in the middle. Okay? Then I only need to define the subject, which would be a post request to the create action with valid attributes in the params. The block preparation is now finished. Now it's time to add our tests. First. Of course, we'll test that server response has 21 status code. Then I call the synaptic and expect the response to have HTTP status exactly created. Next test, validate the format of the JSON about. It expects that JSon data includes valid attributes. Let me check if there is no typo here. They aren't mad. I forgot again about the keys of the hash being symbols. Jason returns strings in the response keys, so I need to change that or the test all pass. Finally, I can add the third example named should create the article. Here, I check calling the subject actually changes the article count by one. Let's run them now to see where we are. Okay, Since fine. No articles created for 22 status code instead of created everything as expected. Now, we need to proceed with the implementation. In the controller. We always assign the empty parameters into the newly created object. Instead, what we want to do is track the params object and required to have data attributes. In sign, we also required to have attributes key, which will contain some values. We don't want to allow everything but only take under consideration the title content in the Slack. So this is what the permit method does. Only in case that it will return nil. We will proceed with the empty parameters object. Having that, we can visit the create action model. Here. If the article is valid, we want to save it. And then render JSON with article as an object and status being two or one, or if you like it more created. Now, let's run our tests again, as they should be green now, oh, only two of three examples past. And one returns are very bad looking error with hash comparison. So there is a problem with our tests when check that hash, including data key is the same as the hash inside of data key. Let me try the task of, yeah, here it is. They want to check is the attributes hash inside of the JSON data and compare it with the proper part of valid attributes hash. Now, our tests are green and we could end up here. But I would like to improve our implementation a little bit. In the controller. In the first line, we check the validation and then we save the opposite. But save method actually cause the valid method under the hood and also returns true or false. So we can safely replace the validation check with safe to make our method one line shorter. The next improvement makes use of error handling. If we add an exclamation mark to the save method, instead of returning false in case of failure, it will rise an error. Then we need to wrap it in the Pickin rescue block instead of if else. Why is better? Well, it depends of developers preferences. The smell advantage of rescuing reason error is that it works this way. If the first part of the block rises and error, then the content of the rescue is called bat. The whole method is a block. So we can actually get rid of the begin wrapper here and start the ad or check when method begins. This way we reduced our method by one indentation level and one and underline much, but I like it more. The final thing I could change here is that super long ad or serializer class that comes from the gem. It's very hard to remember. So what I'll do is replace it with our internal EDR serializer class. Then I just add a new file in the app serializers folder named error serializer. And there I make it inherited from the gems enter serializer. That makes our controller action even nicer. Now, let's run our tests again to ensure that we did not break anything. Everything is nice and green. Congratulations. You just implemented the whole article creation endpoint. Here, I have another challenge for you based on what you learned so far. And especially in this lesson, try to implement the endpoint for updating articles. Most of the code is analogic, so you should not have too many problems with that. If there will be any hard parts. Don't hesitate to ask me anything. I'm glad if I could help. Also, also remember that you'll have access to the repository of our application where we have code snippets for each lesson. In the next episodes, I will quickly show you my approach and proceed with article removal. 39. 4.3 articles update showcase: In the previous lesson, we prepared the articles creation. And I've said the challenge for you to implement updating articles without my help. I hope you have been succeeded. I'll do a quick showcase of how I finished that part. First, of course, I started from routing test where I added another test for amplitude. Inside, I have two expectations for put and patch HTTP requests. Other than that, both are the same. And it looks really similar to the show action test above. Then in the roots are beefier. I added the update action to the root 3s. After that, I continued with controller tests. Here we have the describe block for create action. What I did was just copying everything inside and adjust it a little bit. First of all, I renamed them describe block and added an article object inside. We always need an article to update here. Then I updated all the subject methods to test patch update request to the server and at that article ID in the parameters, except that the whole unauthorized block is the same. Here I also changed the subject by replacing the request type action and perameters. I just merged the invalid parameters hash with article ID. And below, I did exactly the same for valid ones. Here in the validation errors, I removed the slack from the ARs least. I did it because we create vital articles using factory. And in the invite attributes definition, we only change the title and content completely, not touching the slag. Then in the stacks is called. I also just updated the subject and replaced the last example with one that checks if article is properly updated. Here I just compare the title of reloaded object with value provided by the valid attributes hash. That's all from the testing part. Then I moved to the implementation. Here. In the contrary, I added the public method and filled it with the content almost identical if what we did for create action. The only thing that differs our first two lines. In the first line, I find the article in the database based on the ID passed in the params. And then I use update attributes on that object With article params object passed as an argument. Please notice an exclamation mark in the method which allows me to handle the validation error in the same way we did for create actionable. And that's all. Here are some problems yet though. For example, we don't want users to update all articles, but only those created by themselves. We also would like to handle the case if user tries to update article which does not exist yet, this is what we will do in the next lesson. So see you there. 40. 4.4 update only owned articles: As I mentioned in the previous lesson, we have not finished the app detection yet. Currently, each user can update each other's user article, which obviously is not ideal. So in the test file, at a new context though, to check how application behaves when user trying to update not owned article. I quickly set the authorization header same as before and check if it behaves like forbidden requests. But this time, the subject will be quite different. Here the request type is the same. But in the params, I pass the other article as an ID, not the one owned by an authorized user, then I set the other article variable to be the new article. I don't pass a user here, so factor creates a new user for this article by default. Next, I'll jump to the old article definition. Here. I need to be sure that we have the user related to articles specified and that we use access token connected with the chooser. So let's find the access token and move it here. Okay, Maybe I'll define the user here as well. Cause maybe I'll need it later. Having that figured out, I cut out this access token definition from this context block and move it up. But instead of creating new access token, I will create the one related to R defined user. There is a problem. We don't have user relationship set on article object yet. So now almost all tests will fail. All of them fails with the same error that there is no user assignment specified on the article. That's fine, because it usually means that one peaks will affect all those tests. So now we need to add this relationship. In the terminal. I add a new migration. Yet again, making use of rise built-in generator. I named immigration and user two articles and set the user attributes as a reference. Then a random migrations to update the schema. And finally, in the articles model, I said that belongs to a relationship to the user. I need to do the opposite from the user model file. Let me physically user model and here I add has many articles relationship. Now those objects are connected. But the problem is, if we specify belongs to a relationship, then writes require to set the relation by default. That means all our articles created, my factories are invalid now as they don't set the users. I can show it to you. Running tests now, want fixed too much. So let's visit the articles factor. Here. I just defined association to the users and can run tests again. Now most of our tests are green again, the five examples are still red though. And that means that those few examples detected. And once the behavior in our application, let me check that the first test is related to articles creation process. The server returns validation error for what we expect to be correct requests. It happens because in the file, let me open that. In both update and create action, we purchased the article without setting related user object. To solve it. I need to be sure that instead of creating articles without user, I get it the current users articles and build one related to this user. At this point, I am sure that current user exists because the outright method handles checking that. I also apply the same change to the AB detection here. Now we can run tests. Again. Still read. There are three examples still failing. It's fine because we just fix two of them, but there is still work to do. If I scroll up, you can see that those tests fail because of authorization problem. What I think happens is that as we return acts at night when Article 2 update is not found in the current user's collection. Some of our already written tests don't outright users properly. Let me check it out. Here. There is access token created without any user assignment. That means we can't update articles using this access token anymore. I can remove it as we have the proper access token defined the very top of the describe dogs liked it to the update action. I hope that solved the problem. Yes, it does. So let me run all our tests to be sure everything is fixed. To summarize, in this episode, we restricted rights of all our users to be able to update only their own articles. Now, there is only one thing related to articles management and that's the objects removal. There is nothing to creative in that feature if we already implemented other actions. So I strongly encourage you to practice my implementing that on your own. In the next episode, I'll just do another quick showcase for articles from mobile. And our articles management will be finished. But let me take yet another short break now. 41. 4.5 destroy articles: Welcome back. I hope you succeeded with your challenge, but don't worry, here, I will show you my approach. Again. I started from the routing test by adding the test to destroy road. I want to match as accept the delete method used here. There is nothing new. Next, let's revisit the routes file. Here. You can see that I got rid of the whole only option. And ruthless had been left with articles, resources definition. It happened Because if we add destroy to our roots list, we will end up with complete list of roads. And that's exactly what resources method provides by default. And this is why we can get rid of that to clean up our code. Next, let's visit the counselor testfile. What I did here was just going to the ABA block above and copy that here. Then I added a few minor tweaks to make all examples behaving in the way we want. Most of the things we're untouched. As I still need the user article access token to be said the same way as a bold. I only changed the subject to call delete method and destroy action for invalid code. Nothing changed. Then in the next context, I changed the name to the case when trying to remove not only the article, instead of updating kid. Again, the only line changed here was the one with the subject definition. Then when I reached this access call, it was all about simplification. When we remove article, there are no validation errors to be handled, so I just remove the whole context. I also don't use the varied attributes hash in the subject. So I also removed it completely. Then I instead the 200, 400 status code to be returned when we successfully removed article and expect the return JSON to me empty. And the last thing and only test I really wrote was the one that check if sending a request actually removes the article from our database. Here, I expect that calling the subject changes the user articles count by minus1. One thing to mention here, I call the article before calling a subject here. This is because we define the article in the lead wrapper. So it creates article when it's called for the first time. If I want call the article here, the first call of that object would be inside of the subject matter. Next, the subject sends the request that actually removes the articles. That means, after all of that, we would create and remove the article in the same method call and the overall count would not be changed. This fixed prevents that. And I thought that it might be useful for you to know about it. But that's all for our tests. Now, let me visit the controller implementation. Here. There is also not much philosophy. I created that destroy method. And inside of it, I found the article based on providers ID in the current users articles collection. If I find one, I destroy it and return no content header to the front-end. No body here as there is no object anymore. In case when current user does not obtain article with proper ID, the find method returns an error that we handle using our optimization method from application controller. I can run all our tests examples. So you can see that all of them pass without problems. Okay, So the articles management is completely done now. So congratulations. Take a break here. As in the next section, we will cover commenting them. 42. 5.0 commenting scaffolds cleanup: Congratulations for joining this point. In the previous section, we manage to complete the very big part of the application related to articles management. Now it's almost finished and the only thing to add is actually a way to list articles, comments, and add new ones. So let's go on with that. Until now, we used rise building generators only to add new resources or migrations. But we always worked with empty vials or we even created files from scratch. This is my preferred method as I don't like to leave unused scaffolding code and working with scaffolds isn't faster for me at all. Some people, however, like to work with scaffolded files. So in the next three lessons we will do that. We are going to implement commenting system using arise scaffold generator. First, I'm going to add a new scaffolds for comments with continent type of tax and article and the user as references. When I submitted, you can see that lot of files had been created. Basically everything you need for simple crud for resource management, for example, immigration and the modal class with all attributes and durations are already there. You can check those files if you want. When I visit the credit Commons migration, you can see that everything is automatically generated as we would expect. However, as we want to have comments always being created two articles and outer, we will need to add few tweaks and remove all unnecessary cold from the scaffolded fires. But for now, let's just run the migrations. Then. Of course, I check the routing tests. Now you can get the first idea of how much extra code had been generated. Scaffolds work well, only when you have completely standard resources. But even then, I found that lot of code usually need to be changed or removed. Here, for example, except the fact that we only need two endpoints to list and create comments. By default, those RSpec examples test wrong URLs. We want comments to be accessible under Articles session ID slash comments, not just comments. I need to update the URL then and expected to grow the proper action with article ID set to one here. The same thing applies to the second example. Those tests would not pass if I would run them right now. The problem is that rise scaffold generator generated standardized roads for comments. You could preview it by running rake Rod's comment to get list of all roads, the finding your application. As it lists a lot of things on the screen. Let me filter those results in decreased only those that contains commons. To do it, I run the rake routes again, but then I'll use the pipe operator and the grep method with common string as an argument. If you are not familiar with shadow, just remember this little tip here. It's really useful, especially with bigger projects. What it does is that this pipe operator here just redirects the output from the screen and injects it as an input argument into the comment we specified. Next. It's a mini program in shall use to find the given string in the text files. So if we type grep comments, it will get the whole result of the rake routes command. So that is all routes in our application. And then return only lines that contain the common strings. Let's check it out. Here. Only common created routes are listed. And you can see that we have all crude actions here. Listing comments, creating, getting specific one, updating and destroying ones. Also none of them has relation with the article visible in the euro. To fix that, let's visit the roots fire. Here. I just kept the common throat from top and place them below articles wrapping that line with the dark. When I go back to the terminal and run their roots command again, I will get all roads transform to include the article string and articles ID inside. Now, to get rid of all unnecessary roads and just add an only option specifying, index and create actions in it. Now, finally, I have only necessary roles and all of them are valid. So we can visit the controller test file. Let me just remove all those comments as they don't need them here. Oh, and my editor complaints that there is an unused variable defined somewhere here in the index section. If I want to test only if response succeeded, I don't need a comma to be created, so I remove it as well. Then we will implement only two of those five actions. All those blocks related to show, update and destroying actions can also be safely removed. It's much cleaner now, but we still haven't finished yet. There is a cleanup here to do yet. But to know exactly what should be changed, the best way is just run those tests examples that are left and read the failure messages. Let me run the RSpec common with only the comments controller file specified. There is interesting thing here. We have run for examples, but there is only one failure with three tests marked as spending. That means those three other examples also fed, but the failure message was ignored by RSpec. It happened because in the valid and invalid attributes, we have the skip method used. Wherever this method is called, it just skips the test it cold from and tells RSpec to go to the next one. All those pending examples are related to creating articles. So we will cover that in the next lesson. For now, we will focus with that one failure we received. It says that there is no root matches. The action index is because all our roots now requires article id as a parameter. So to make valid request, I always need to include that parameter in it. So let me go back to the test and fix that. Here in the Parliament section, I just add the article ID parameter set to articles. And now of course I need to find the articles object and can run the test again. It's still failing. And the failure message seems to be much worse than it was. Did we make things worse? Of course not. If you're closer, you will see that the message says that our test tries to call success method and the ActionDispatch test response object. We expect that this method returns true, but it seems to be opposite. So let's go back to the test. Here. We expect the response to be success, but it seems, it's not that be sexes mater, always return those bad looking error messages in case of failure. And this is why I never use them. But instead, I use have HTTP status mater, we've expected status code as an argument. This will tell us not only that the requisite failed, but also what exactly went wrong. Here. Now, you can clearly see that as you probably expected, it's the authorization error. We want the index action to be accessible without me to authorize users. So to do it, we need to visit the controller. The scaffold generator already created the comments controller for us. But it has the same problems we experienced with other files. There is a lot of unused code here, and also it's not fully functional in the way we need. So let me have a great IT to make our test passing. First of all, I need some cleanup. First line sets, a method set common to be called before each of actions defined here. Our application won't allow for updating, destroying, or throwing comments. So I can completely remove this line. Then I can also get rid of show action as well as update and destroy us, we want to use them. Then finally, I also removed a set common method as it's not called anywhere anymore. Let me change that in here and we are ready for actual improvements. I want the index action to be publicly accessible. So I added this cubic before action block without rise method in it, setting the only option to index action. That should be all for now. I can run the test again. And finally, finally it passed. So we managed to clean up the scaffold fires. For the starting point of our index section. There are three failures yet to be solved, and we will take care of them in the next lesson. 43. 5.1 creating comments scaffolds cleanup: In the previous lesson, we managed to fix automatic tests for a distinct articles. However, there is also a block related to creating new articles yet to be solved. So this is what we will do in this lesson. Here we have three fanning examples. And as you remember, they are all ignored because of the skip method used wherever the valid or invalid attributes are called. Instead of skipping those tests, I would like to use common factory to set valid attributes. First though, I need to be sure that we have valid factor regenerated. Let me check that by visiting the comment models test file and write a validation test very quick. I add here a described block named validations and insight. I place the test checking if the comment has abide factory. Inside of this test, I only need to expect that calling the common helper from factory bot is valid and then run the tests. As you can see, it's varying because the user and articulate relationships are not set. So let me open the commons factory file and check it out. The default scaffold generator had defined all properties, but by default all relationships are. Let me change this first. I'll update the content of the newly built comments to be more descriptive, Let's say my comment. And then instead of setting new for article end-user relationships, I'll use Association helper to use the default factor is for articles and users when nothing is specified. Now running, the model test should pass. Nice. So next, I'll add the second example to ensure that our common object requires all necessary attributes to be said. I name it should validate the presence of attributes. And inside I instantiate the empty object. Then a check if it's invite. After this check, the validations are called under the hood. So all error messages should be added to our comment object. This is why I can also check if common error messages include expected objects inside. It should include the user with a string must exist and article with the same string. Finally, the content should be with a message. Can't be black. It's all about presence of attributes, but article and user, our relationships, not the standard attributes. And this is why the error message differs here. If we run the test now, it will fail. Of course. The message says, we only return two errors for our user and article. This is set by rise by default on all belongs to relationships, but we also expect the content to be required. However, we never define the validation rule. To fix it. I'll visit the common smother, the fire. And here I will just add the validation for the content attribute specifying presence to be true. Now, our validations are completely implemented in the working world. So as I exactly know which attributes are required and which aren't to create new common. I can go back to the conflict or test to solve my skipped examples. In the valid attributes. I just said the content to be a string containing capex, my awesome comment for an article. Then in the invite attributes, I always set the content to be done. As those variables are completely irrelevant from the perspective of index section, I will move them into the describe block for creative action. Below. You can see now that there is only valid session variables specified here, which we also want US as we have token-based authorization setup. So let me remove all calls of the valid session from this file. Then let's delete this locality. There is only one attribute being editable for comments and it's a constant variable. But as we know, we also need an information about the article and the outer of the comment. The outdoor will always be a current logged in user. So we don't need to pass in the parameter. We pass an ID of the related articles. As you remember from our root definition, the ID of the article is required in the Euro. So it won't be inside of attributes hash, but I need to include it directly in the same way we did for index actionable. Let me do that for all the request goes. Now we need the article. At this point. We clearly see that all our test examples, we'll use the article object so we can move its definition that we always accessible instead of nesting kid in the index action block. Of course, in those tests will fail. Again, it's because of authorization that is required. Let me add a quick context doc where requests is not authorized. Here. I just need to define a simple subject record, setting ID of the article in their parameters, and then just add align with it behaves like forbidden a request to call our shirt test example we defined before. Then I add another context for outright requests where I place all are automatically generated examples in a moment. Here, I just had the day before block to set the authorization header bearer appended with the valid access token. I don't have the token object yet, so let me define it here. Let access token to be user, create access token. We need the user object here yet. And we can move. All are auto-generated tests into the authorized context. Now, when we run our tests, you will see that we have six examples running and only two of them are failing. So we added two passing tests for unauthorized milk and fixed one failing before. But there is no more optimization issue here. Those two failing tests are saying that we try to create invalid common when we expect them to be valid. Now, it's time to improve our implementation. When I visit the Kotler and see several problems here. First of all, the default file assumes will always provide an article ID and user ID in the attributes list for the new comment. That's not a case here. We only want a content to be taken into account. So I'll remove two relations, specific attributes from the list. For now, I'll take care of the user and I'll go back to the article in the second. If we don't pass user ID in the parameters, we need to merge the common parallels with the current user. If we want to create a valid object, then we also want the article to be associated. So let me add a private method named load article, where I'll find the article based on the article id extracted from the request. Then instead of creating a comment without an article, I'll just get this article and build a new comment as a part of the collection for that article. Of course, having the metal that loads the article is nothing if we never call it. So at the top of the container, I'll add a load article method call to the before action. Either said that the only method for creative action, just because our goal for this lesson is make all automatically generated tests passing, not finishing the feature. And fortunately, our tests won't pass straight away. When we run them. They will say that article has no comment, might not specified. If because they all arise, generators only specify the belongs to relationships on one side. If we want, has one or has many relationships, we need to add them manually. Let me first visit the articles model. Here, I just add has many comments with dependency set to destroy. Then I'll open the user file and apply the same change here. Let's run our test to see what they will return now to read. But it's the last change we need to apply to solve all our problems. The test says that we are trying to call the comment URL somewhere in the consular. It also says that it's in the create method at line 19 of the comments controller. So let me check that. Here, the controller in the way is generated, always includes the location key into their response, passing the newly created object as an argument. If we do that, if translated to the default URL of that object. And of course, in the common era, however, as we don't have the show action specified, that URL does not exist at all and rises an adder. This is why for now, I'll just replace the common variable with the article 1 here. Then I also need to apply this change into the test. And it will be here. Instead of calling the comment URL, with the last comment, I will call it with article URL, passing our specific article as an argument. Now finally, all our controller tests should pass without problems. As we just did a lot of changes. I run all our test examples to see if we have them still all green. There is one more test failing, but it's also automatically generated file placed under the specs request folder. When I visit that file, you will see that the only example here checks if request to the comments URL returns proper HTTP status code. I leave it to you. If you want to pick this test or just remove it from here. I usually write only my contour of tests, but I do it in the way they cover also HTTP status codes. This is why I can safely remove this file, which I'll do right now. If you prefer to work with requisite, that's that's also fine. Now, as it was the only failing tests. All our examples written so far are nice and green. To summarize this lesson, we just use the scaffold generator that a lot of predefined files. But we needed to update them and clean them up so they match our applications explanation. There are still a few things to improve and we will take care of them in the next lesson. But for now, take a quick break and we'll see you in the next episode. 44. 5.2 listing comments improvements: In the last episode, we managed to fix all automatically generated tests, so they are passing hand. However, automatic generators does not cover all cases we want. For example, when user passes and articles heavy in a request, we only want to list these articles comments, but currently we list all of them. Also, there are problems like not proper format of the JSON responses and few more nephrotic cases. So let me improve our test coverage to cover all use cases that are important and then improve their current feature implementation. I'll start from the test named. It should only return comments belonging to an article. Inside of this test, I need two comments. First one should be connected to Article Views. So as a comment, I assign a new comment created by factor about specifying article there. Then I create another comment without any article to be set. So by default, factory will create new article for that comment object. Then I will call the subject that will be defined in a second. And at the end, I place our expectations. I expect the JSON data to be an array with one element. And also, I expect that this only element of the JSon data has an ID key with value being exactly our comments id. Now, as I mentioned, I need to set the subject. I will send the identical requests to the previous example so I can just replace the direct call here. We have the subject called, then specify the subject in the wrapping describe block. Now we can run these tests and in the response as expected, we get two results instead of one. That's because in the controller, we always return all articles and don't even care about passing parallel. It's easy to fix as we did the most of the work in the cleaner part of this section. Now we only need to change this line and load articles, comments instead of all of them. And remove the only option from the before action method call. We can also remove the ad character from those variables. These comments collection won't be used in the views nor in other files or method. So it doesn't need to be an instance variable. This little improvement already made our test passes. Then the next thing to improve is the pagination. If the article will get thousands of comments, we don't want to return all of them at once. Remember, in the lesson related to the articles listing we already added at as tricking pagination. So it should not be a problem for you to write the similar test for comments. Let me visited via here you can see it will just need to create few articles and specify that germination parameters to ensure that virginity and resources are working well. Going back to the common test file, let's try the test. I'll name it showed paginate results. Then a quick three comments belonging to the same article and send a request, the wrist those comments passing article id as a parameter together with pagination ones. Then I can copy the expectations from the testable as a want their turn JSON to have only one result. And also that the idea of the first object matches the commutating. I don't have the commit object defined, however, so let me do this. I will need the second object from the commons collection and assign it to the common variable. Oh, sorry. I should use Craigslist hybrid here, not just to create one. Without the List keyword, I wouldn't be allowed to create several objects at once. Now, we can run tests to see the failure. As expected, the pagination parameters are ignored by our application and we return own comments instead of filtering them her page. The fixed is extremely easy and it's the same as in the articles controller we did before. I just need to add a page method to be called with proper parameter. And also the permitted to specify how much objects will be listed on every page. And that's it. Running tests. Now we'll end up with the green results. So now when pagination works, I can jump to the next improvement. I want to be sure that the response is properly sterilized. So I'll add another test for that. Let name it should have proper Greece and body. Then inside I create the comment, call the subject, and then write the explanation. I expect the first object of their list to have attributes hash with a content key set to common content. The good thing is that this should pass straight away at the scaffold generator created a common serializer that uses JSON API format pulled from our default configuration. We can take this file, so let me open it. Here you can see that only ID and content are specified as attributes, which is awesome. The serializer also contains information about related user and article. So we can go back to the test fire. And at another example, checking that the response should have information about related objects. I would like to show you how this information look like. So let me create the articles object and call the subject. And then before I'll write an explanation, I'll just put the return, the response on the screen so we can preview it. When I go back to the terminal and rerun the tests, you will see a response hash there. It's exactly what it means to be adjacent object with data key containing an array of objects. Each object contains the type set to comments, id, and listed attributes. The new things however, is this relationship section that comes from the has one method called in the serializer. You can see two objects here, article end user. The problem is that they are formatted differently from each other. And our digital objects only includes the ID of the article and the type. But user object, instead of type lists all attributes directly in data key. In the serializer TO there is no difference. So what's going on here? We will figure it out in a second. But for now, let's finish off this. So first, I set up the relationships variable by extracting the relationships hash from their return Jason. Then I add an expectation that their relationships has an article object with ID being set to our articles IV. Then I add another similar expectation for user. I don't have the user in this test, so let me add it and assign it to the comment. Oh, I need to fix those expectations yet, each of these relationships has their own data. So I need to add it here. And hero, unfortunately, this test will pass yet because of that difference in the article and user objects we saw before. Explaining better, I'll put the relationships on the screen and run the test again. There during the message says that we expect the user ID to a string, but it received an integer. The reason why it happens is identical with why the user differs from article here. If we don't specify sterilizers for the object, the default serializers have chosen to translate our objects into the JSON. We have already set up our application in the way that default serializers format our objects using JSON API recommendations. The problem is that if we don't have any serializer defined for the object, then the object translation files back to the default ri serializer. That doesn't use the JSON API at all. So to solve it, we just need to add the user solubilizer that is missing. Let me show it to you. In the app serializers folder, we have several serializers, but the user one is missing as we never created it. It wasn't needed until this point. So let me copy the articles serializers File and Save the copy as a user serializer RB. And then I just change the class name to the user supervisor and specify proper list of attributes. If I remember correctly, it should list ID, logging of other URL, Raphael URL and a name. Now, when we save the file and run the test again, they will all paths. You can also clearly see the changes that happened in the return JSON. Congratulations. You've just finished a listing comments for any article in your application. In the next lesson, I'll fix all problems related to commenting articles. And after that, our application will be fully functional and ready for the first race. Take a breath and a quick break, and we'll see you in the moment. I can't wait for the next episode. 45. 5.3 create comments: In the previous lesson, we manage the finished listing or comments. It is extremely exciting to tell you that our application is almost finished and will be completely done in this episode. Let's make it real. In this episode, we will finish adding new comments for our articles. We already have quite a lot finished here, but there are few things to be improved getting this topic. So let's visit a controller spec file. The context for an authorized request doesn't need to be taught, but it doesn't need to have valid or invalid attributes variable accessible. So let me move them few lines below for more clear view. First of all, we have this success.com. When post request is sent with valid attributes, I'll use the same request called several times here. So let me extract it to a subject really quick. We have a test that checks if the comedies created, but we have no dedicated test taking the proper status code to be returned in the response. So let me change it. I add one example named should return to one's status code. Then I call the subject and expect the response. So have HTTP status code to be exactly traded. Then I would also like that this test checking if the comment has been created to be more specific. Instead of just checking if any common is created, I'll check if our articles comment count had been changed. After that, I can go to the last example that is here. I'll change the direct record coal to use the subject instead and then remove the checking HTTP status code from here. We just covered that in the separate example. About this remaining lines. We will just get rid of them. This test is about JSON response, but it does not test what we want. It checks the Content-Type header, the location, but not the body. So let me get rid of that and write it again. I expect that the JSON data attributes K includes the content which is set to what we had specified in the valid attributes hashable. It's my awesome comment for article. Now, we can run our tests. As you can see, all our tests passed right away. How honestly, I didn't expect that it will go smoothly. But it's reasonable as we pretty well job by implementing the success case in the controller. I expect some vendors in the next context, doctor, for invite request. Let me work on this now to be sure. I'll add several more examples here using this request call. So let me first extract it out into the subject matter. Then I quickly split these two expectations, setting separate test examples for checking the status code. Again, this isn't necessary. I just like to have small tests tracking one thing if possible. Next, in the test checking the error format. I replace that line to be sure that JSON has an error ski containing an arm of errors. I don't remember the exact error format, but we already figured it out while working on articles. So let me open the articles control test file and look for validation errors there to there. So I'll copy this one error object and go back to the commons test, where I'll put it down. It looks the same except the attribute name present in the pointer key. So let me change that to the content. And we need only one layer of curly braces here. Now we are ready to learn those tests. That should definitely fail. And it did. The error message says that we expect to contain a hash with source and pointer. But as we did not specify the error serializer in the controller that uses the default rights era serializer. So let's visit the Kotler and fixing this, we also figured out already, let me then open the articles controller and copy the validation error handling from there. Now, a quick refactoring in the same way we did before. I get rid of this conditional statement and add an exclamation mark at the end of saved method to rise an error in case of failure that can be handled. Then I rescue from that error by rendering the comments error using our error sterilizer. Seems that would be all. Oh, no. I can see there is one more thing to do yet. Here. The default generator assumes that we pass attributes for comments using the standard format, including resource name to be passed, and attributes listed directly. We do want to ensure that client uses JSON API format we use across the whole application. So let me visit the test fire. When we send the attributes, we want the valid attributes to be in JSon data format and then merge them with article ID. I'll repeat the same for Invite attributes. Now, having that, Let's go through these variables definitions and set them up properly. We want the value attributes to be nested in the data and attributes Keats. Then I need to do the same for invalid attributes. And now I can run all tests in the describe block for the create action. The block starts on line 48, so I will go to the terminal and run RSpec commons conference specifying the line to be exactly 48. Now, all our tests are failing because in the controller, we require the common key to be present. I can open the articles controller again to recall you how it should look like. Instead, we want to acquire the data key in the attributes inside. So let me do that now. Only if that's a valid hash, we will permit the content as the only editable attribute. If the result is new, we will return the new instance of action controller parameters class. Now, finally, our tests are green, so we can run all our test examples to see the summary of our war. Congratulations, you've just finished the core of our API application and it's ready for the first release. 46. 6.0 creating heroku account: Hello again and congratulations. Your application is quite finished already and it's ready for the first trees. In this video, I'll go through the whole process of deploying complication. As you can see on the screen, I visited the heroku.com website. It's really popular hosting service to deploy applications of all kinds. And setting up their rise application is extremely easy. Her, if you already have the Heroku account, feel free to skip this episode and jump directly to the next lesson. Also, it's completely free for the limited user, but this usage will be more than enough for our simple test application. So first, let me quickly set up the new account. I click the Sign Up button here, and I get these nice form to fill with my data. I'm going to type my name and last name together with my company image address being info trigger.com. Then I chose the rule, Let's say the professional their country and set the default. And last but not least, I'll choose the mind programming language I'm working with. Then pallidus robot tests, and we are ready to go. The next screen shows you info about the confirmation email being sent to the email address you provided. Because of the privacy reasons, I want to go to my mailbox, But just cut out clicking on the link from the video and show you the next page. Okay, Now we are here. Just set up the password and confirm it. And then I'm going to check the newsletter subscription to because why not? After 17 the former we are done. They account is completely setup and our application is deployed. I'll cover the actual deployment process in the next episode. See you there. 47. 6.1 deploying to heroku: In the previous lesson, I created the Heroku account. So now we are able to actually deploy arrives application. So it will be available for the public. If you are new to Heroku. When you login for the first time, you will see this list of the most popular languages used by their users. You can click on one of them to track the detailed quiet and tips. But our application is quite simple and we can draw it out it. So let me just click decrease your app and choose the proper name. I'll name it Udemy rise, APA course. Then I can choose the region for the server. It will be hosted on. As the most of my students are from us. I will keep it here. Then we could add a pipeline for our project to hookups on continuous integration tools. But we want needed here. So let me just click Create and we are redirected to the newly created application page. Here you have several ways to actually deploy the application. The default is by using the Heroku CLI tool, which I often use when I start new applications. But later, I usually hook up pipelines and use the continuous integrations to deploy apps for me automatically. Heroku CLI is what it's named for. The common line interface, a little program that you can install on any operation system and deploy applications from the terminal by typing only single command. To install it on your Mac. Just use brew, install a set in documentation. And if you are on the other Unix systems or even a Windows, you can choose appropriate installation type from here. I'm a Mac, so I would copy this command and paste it in the terminal. But I want hit Enter because I already installed it before. So it wants to do anything for me. But when you install it, you can now use Heroku login method. Let me find it in the documentation here and type that in the terminal tool. Now, we can login into our Heroku account from the terminal using credential we've just created. So the image is info at Google.com. And I'm going to type my super secret password here. Now, when I type the Heroku apps, I will get the list of all applications that I have access to. Here I have only one application and it's the one I just created. Let's the next step. We already have the repository because dries created the one automatically for us. So I just need to copy the last line to add a remote server to our existing Git repository. Let me paste it in the terminal. Now, this common just added the remote host named Heroku next to our default. Originally. If you didn't set up the region before and used only the local repository, you will see only two lines here with Heroku as the name. Anyway, the documentation says that there is only one more step and we are all done. Git, push heroku master. My typing this common. We push our repository changes into the nervous during hosted on Heroku, not on Gibeon. And that triggers the whole deployment process with installing Ruby version with honest sorry, gems and so on. But unfortunately, this will fail in a moment. You can see it now. We got an error that the gem SQL light can be installed. Heroku does not support the SQLite database for protection products, but Rights uses it as the default. I didn't want to force you to set up the Postgres database on your local machine. So I used the default configuration in the course. But to make deepest passing, we need to change it. Now. I'm going to open my code editor and visit the Gemfile. Here is the line with installing the SQLite gem. I still want to use it locally, but not on Heroku. So I'm going to move it down into the group development and test environments. Then I just add another group for production environment and installed pg gem inside. Then I can save the file, go back to the terminal, and run the bundler. So all Gem dependencies are installed correctly. Finally, I need to commit the changes. I'm going to add the files to the repository by using git, add a comment with patch flag so I can review and confirm that each change, everything seems to be fine. So when I check the status of the Keq change, I'll see all files being added to tracker. And I can come in and now I'm going to add the commit with a message, let's say char, because it doesn't have the impact on the end-user. And name it, add up pg gem for heroku to a 100 and deploy smartly. Then click Enter and push our changes to hurricane. As you can see, the whole process is started again. The environment is recreated in the new version of the application is deployed. This time. It passed without problems, however. Now the only thing to do is to ensure that we have the last version of our database in the production server. The current production application had been created with empty database. So we need to apply all our migrations written so far. It's really simple. Locally, you would just write their command rise db migrate. But to run it in Heroku, we need to prefix it with Heroku run. And only then the name of the command that have run. All our migrations and our production application has up-to-date database schema. We can now visit the application dashboard page and click the Open button on the top right corner to visit application. This notice that the URL is the same as the name of your application appended with the herokuapp.com domain. Don't be afraid because of the fact that browser says that the page can be found. We have never setTab the root of our page to render anything. So we need to visit some of our defined URLs to actually see the application working. First, let me visit articles URL. It's working. It renders the empty article list, but it's the working class. You can also access it by typing Udemy rise API calls splitted with dashes, appended with dot herokuapp.com. Now, let me fill this application with some data. As you probably remember, we have written the seeds file before, which we can run too easily feed application with sample data. Let me show it to you. Here. This file contains the instruction to create a user and three articles belonging to that user. In the terminal, I can just type heroku run rake db seed common to run the content of this file on production server. If you visit the browser and L, you will see that the server response isn't empty anymore. That's super amazing. Now, you can check out the Postman application to test all endpoints in our project, or even hook up your own front-end to use this production data without problems. I hope you'll find it useful. 48. 7.0 section plan: Welcome back In the new section of the API implementation, where we will take our current application and implement the standard way to logged in users using their login and passwords. And also in the next session through history new ones. I added this section because a lot of you requested most of real applications need to login via login and password. And outflow is often only the addition to that feature. The OJT with GitHub as a provider, however, is kind of an edge case. And I need to admit that. This is why in the next few lessons, we will go through the process of implementing standards to login and password flow. Here I prepared the postman collection for all authentication endpoints in our application and make it public and attach it to the lesson resources. The first example here is for sending the request without any data in the parameters. Let me send the request to show you the results. By the way, the quick notes about what you can see in the URL. I use environment variables for all my applications. Thanks to this, I can easily copy and manage multiple Postman collections for a lot of applications. That's really convenient. Here I have a host variable, which in my dev environment is just local host on port 3000. This is appended with a namespace. And namespace is emptying this application, but I always have it here in case my application will support multiple versions. So you can read this URL as localhost on port 3000 slash login. That being said, I can click the Send button and server responded with and now to rise response. Please notice that details section. It says that the code parameter is invalid. In the next few episodes, we will change that. So the application will use login and password flow as a default. Therefore, when you will send a request without any parameters and the server will say that login or password is wrong, not the code. Anyway, let's quickly go through the rest of requests for authentication. Next one is for invalid code. Here in the body, I send the JSON message, including coat being set to the string invalid. If you don't see that, be sure that you have a row body type selected here and the Content-Type header set to application JSON here. When we will send the request, will also get a now to write response with cold related details. We want to keep that hero. Then the next request is for invalid password, similar to what we had before. In the body of the request, we will have the JSON including data key with attributes included, I login, and passwords. Currently, we get completely the same message as before. But what we want to achieve, our details related to invalid login or password. Finally, we have the last request, the success one. The body is almost identical to what we had before, but the value of the password changed here and is set to the secret. Now, this request should return the success response with the token object in the response body. And that's all for now. This is the plan for our whole authentication flow. So let's switch to the editor and write this stuff. 49. 7.1 standard login multiple authentication handlers: We just prepared the controller to be easily extended for asthma, the authentication flows as we want. And the next thing is reviewing the user authenticate through service so we can extend it in the same way. Here is the tough part. We did a great job implementing this whole logic already. And we don't want to redo that for sure. This is why I plan to move all this logic into another file and do the same for tests later on. Here, I'm adding a new file. Let's start in the user authenticated folder and name it out, or B. That will be the subclass of user of the indicator. And it will be responsible only for outflow. And then I'll add yet another file for standard passwords stored in the mine user authenticator. We will take all those subclass and call them depending of what arguments were passed in the parents. But one thing at a time, first I go to the user of the indicator file and copy all the code inside of the oil RB file. I just need to rename the class to user authenticator double colon, which inherits from the standard user of indicator class. There is nothing to change here anymore. What we don't need to do is adjusting the parallel class. So it will be more clean and it will call the proper trial when needed. In the parent class, the main user profile. We don't want the code string being the only parameter acceptable. What we do and is supporting a hash of named attributes. And for now, we'll just support the code attribute setting the default value. Then instead of setting the code instance variable, I'll create the authenticator instance variable. Having that, I added this out indicator to the reader section. This simple trick allows us to clear out most of the logic from this glass and delegated into the proper authentication handler. For example. Now in the performance, I can remove everything and just call the authenticators performed method inside. As we have the authenticator listed in the act trigger. I can get rid of this, add character to. Finally, I'm going to clear out the rest of those leftovers. And now it's all we had been left with. The only thing we need to do it is those user and access token methods. We don't have them anymore. So instead of listing them as readers, I will define a method for them. And inside, i will cause those methods from inside of the trial. We could use to allocate keyword here. But I'm not sure when we will end up. So I'll keep it this way for now. Now, it's time to define the standard flow out indication handler, a drum into the standard RB file. And here inside I type the className, which is user out indicators standards. And it inherits from my user authenticate or glass exactly the same way that one does. Then we need the authentication error class defined here. There is not too much to say about just an error that inherits from standard Ruby error. And then I define delta indicators are initialized method. It will accept the login and password, but it will do nothing for now. Next, we need to define the performance in just for now, let's always arise the authorization error. Oh, actually I just realized that the error class name can be even simpler here. This error is defined locally in the standard authenticator. So it's namespaced already with standard keywords. No need to append the authentication error. Standard error here. The same thing we did in the outer beefier just a minute ago. Now we have almost finished. There is one more thing to do. In the authenticator class. We want to call the 0 outflow when the code parameter is provided. When not, we want to call the standard flow by default. Now, as the base authenticator has no proper error anymore, we need to go to the application controller when we handle all the errors by delivering properties and the responses. Here, we want to rescue from user Authenticator or error with a method name out indication of the error. Then we do the same for standard authentication error. Finally, I can go to the error handler and rename it to include the word. Next, I'm going to copy all its content and the rename it to the standard error here in the actual message will be different. I can safely remove it from here and copy the JSON objects from the test we've wrote before. Let me very quickly. And now I can run artists. When I run the access token contour spec file, all of 12 examples paths. That's amazing. I can also, going back to the Postman application and send requests from there. You can see that the old message sent by default that the code is invalid, but now it's handled by standard authentication flow. And the message says that login or password needs to be changed. When we specify code in the parameters, the flow remains unchanged. How cool is that? That's all for now, but there is much more to do yet. Let's take a quick break and I will go back to the next lesson to continue with password authentication flow. 50. 7.2 standard login controller preparation: In the previous lesson, I explained this session plan using the postman showcase. Now is the first part of the implementation. And to do this, well, let's check out what we have written so far and addressed our current code. And it'll be to make changes easier later. In the tokens controller spec file. We already have a lot of test-driven already. First of which is for empty parameters in the login request. Here, we said that it should behave as an outrageous requests, but as our unauthorized message will be different for all low and for standard passwords. So we need to be more specific here. So let me visit adjacent error helper file. When we have shirt examples for an outro and requests defined. Here they are. I need to rename it to, let's say, an outright out requests. Then and copy the contents of this block and rename the duplicate examples into. And now to rise standards records, probably you can name it better, but if the first thing that comes to my mind, Having that, I can change the arrow details. First of all, the source pointer will be set to data attributes password field, as this will be the part of the request that is involved. Then I update the title to invite login or password. And the details, I just replace the code with credentials as front-end won't know which attribute exactly what's wrong. Next, we can go back to the tokens converter spec file. In this file, we have two uses of unauthorized requests. Shirt examples. First is for a request without any parameters sent, and the second for actual invalid code. This way, let me rename the first context to be more descriptive. There are no authentication data, provide it at all. So the name should say exactly that. Then we want this to behave like the standard. And now to write requests showing front and to change provided e-mail or password. Finally, I renamed the other shirt. Examples go to use an outright or ultra requests. I can run those tests now by running RSpec common with the file path spec controllers, access token controller spec or B. I expect the first of them to fail as this is exactly what we saw in the Postman before. Yes, we expect the password related message in the controller response, but we got the old one related to the outcome. This is one of our fundamental tests that should pass when the feature is finished. However, we want, make it right away. For now, we will leave it and move to the conflict file so we can prepare it for standard login support. Currently, in the controller, we always expect parameters to have the code c0. We pass x value as a string. That's not ideal as we can't add support for other authentication flows easily. This is why instead of static string, I'm going to pass inside of the authenticator, the properly filtered collection of attributes extracted from params. Let's clear this out and pass here the authentication params instead. Then I'm going to create a private method with the same name and inside and use this code parameter we used before. The difference here is that a want this method to return a hash, not a string. So I can easily add parameters later on. So instead of calling a code key directly from the parallel, I'll use permit method, which will filter all parameters out and return the new parameters object, including only the scope parameter inside. Then I will transform this to standard Rumi hash and make all keys, symbols instead of strings. The reason why I'm doing it is that I don't want string in the arguments list of the advocator new method. Instead, I want to use named arguments with cold adding password and login later on. Okay, that's all for our controller for now. As we change the type of the argument in the authenticator initialized method, I'm going to jump to the user at indicators service, so I can update it to 100 arguments passed in the new format. But let me take care that after the short break. 51. 7.3 fix our tests: In the previous episodes, we manage to write new tests for our tokens controller. To get there, we're splitting our main Authenticator into two smaller pieces responsible for the each flow. However, even if we did adjust the implementation, we didn't touch the surface specs yet. Now, all our controller tests pass. But when we run our user of the inhibitor spec pile, all those tests will fail. That's because these tests are now not related to the authenticator, but rather to the old one. Fixing them is quite easy. We just need to visit out and heater spec file. And here in the leaf folder and an oil out spec or B file nested inside of the user authenticated corner. Inside, I require derives helper as given, and define the mind. Describe bloke with user on Hirohito, outclassed, described by tests inside. Then in that doc, I just need to copy the whole content of the mind of indicators spec file. It's almost done. Now. I just need to search for the authentication error class as this has been changed a little bit in the previous lesson. I need to add o up here, and now I can run all the tests. Again. I don't want to call this main authenticator file. Has all those tests were related to the ortho. So I call the file. I moved all tests into and all of them had passed. Let me now go back to the minus 19 eater and remove all the code from that fire. We won't need it anymore. What I want to do now is adding few tests. The reheater, just to ensure proper children are called when the authenticator is initialized with appropriate arguments. So I'll add two contexts for now. When authenticator is initialized with code and when it's initialized with login and password. Then I'll work with the first context a little bit. I need the mine out indicator being initialized with sample code. Then I'm going to set the class of child of Necatur being called into all one. And having that, I can write undescribed bloke with an initialized method being tested inside. Here, I just need to check if proper authenticator is initialized. All the detailed logic will be tested inside of proper tried file later on. So inside of this test, the only thing I need is to check if Out, Out of the keto Class, we'd have new method called with a string sample as an argument when we call the mind authenticator nucleus. Then let me copy this code below and do the analogic test for standard authenticator. The only difference here is that we're going to initialize the mine authenticator with login and password. And tried to authenticate your class needs to be changed to standards. Having that inside of the test, I expect that the child's authenticator class has a new method called with two arguments, J Smith and password. I want to keep things consistent with what we had for art so far. So let me go back to the standards of the reheater file and adjusted a little bit. Initially, I use named arguments here, but that won't be needed as we only have two arguments supported. I can run this. Now, see where we are. Oh, there is one test failing because in the parent class, I also call the standard of the heater. We've named parameters. Let me open that very quick. And here, when I initialized down indicator, I will just pass the login and password as strings. And in the mind authenticator, I will allow passing those values at the hash. Now, all our tests are green. The mine authenticator calls always proper child. They all flow is practically and torch. And we got the way to support the standard flow as well. Currently, however, all our endpoints behaves like invalid login. And in the next few lessons, we are going to change that. Let's grab a cup of coffee and we'll see you in a moment. 52. 7.4 standard authenticator specs: Welcome back. We already have everything prepared now for our standard authentication flow and our application is ready to be extended. Currently, the minute indicator of service is practically finished. It doesn't need to do much except juggling children and delegate methods to appropriate flow hundreds when needed. When we will visit the standard authenticator, however, we will see that it's far from being done. The initialized method does not think and perform methods always return the error. Let me change that. First of all, I would like to ensure that the whole public interface for all authenticators is exactly the same. By interface, I mean that all public methods are defined and accessible in the same way. Here at the top, I didn't have a user and access token defined, but the controller requires it in case of success message. So let me add that here. Both of them will return nil until we implement some logic inside. But that's for later. Before we dig into the application logic, I need a testfile we do to levy, remember. So inside of the speculum user declutter polar, I add the standard Spec, our beefier and inside i and as usual require rise Hooper with a general describe look. Inside. I'm going to add another describe block named perform. Here I will need the authenticator which will be described class I initialized with username and password, let's say passwords. Next, I'm going to add three contexts blocks. First is for the case when the login is invalid. Second for invalid password. And last but not least, covers the case for a success of Qishan. Now, let's add the subject yet, which will be calling them performance on our authenticator. Then I can finally add our tests. I name it should rise an error. Then inside, I just expect that calling the subject should rise and user authenticator, standard authentication error at the end. I can also check if the user inset on that authenticator. We don't have any user in our database yet, so it should pass right away. Then I could copy that whole test into the invalid password contexts. Because in both of those cases, our class should behave exactly the same, not authenticate user, but rather rise an arrow. However, we already know better way to write code than duplicating it. I will get this test out from the context to define the shared examples for invalid out indication and paste copied code inside. Now I can use it in both contexts by calling, it behaves like invalid authentication. There is one problem, however, we want to somehow distinguish both of these contacts as both of them are completely the same right now. In the first contexts, we want to have a user in the database with the same password as we used in the authenticator, but with different login. So I create a user with login, then IDO and password set the password. Now I can copy that line below and adjust user attributes. And, but wait a moment, there is a typo here. I believe it hurts your eyes since I did it. So let me remove it quickly. Then. I'm going to change the login to J Smith. So we will have the user with the same login used in the authenticator. And I will also update the password to invite one. Those tests should fail. Now, as we don't have the password attributes available in the user model yet, let me run them to ensure that they work as expected. Oh, okay. They fail but with the wrong message. Oh, I can see in the test, instead of checking if the error is reason, we actually arise it. And this is what happened. We used rise method. So the authentication error had been the reason and test failed on that line. I'm sorry for that. I will quickly go to the file and fix that. Here. Instead of writing the error, I should use rice error method, which actually handles that error and return true for our expectation. As we are in the file, I can see it. Another problem here. We define the user variable, of course, but we never call it in the test. So it's never actually created and both of these are still the same. So in the shirt example, I want to add the before block and cold the user before each test. Now we can run our tests again, and here they are, our expected failures. When I scrolled up, you can see that there is no password method on user object. So the next step is to add a support for that. 53. 7.5 standard login user password: Okay, Now we will cover the password encryption support for our users. When we talk about on the negation in rights, there are several James got let you implement that fairly easily. The most popular of course, is the Devise gem. We've almost 19 thousand stars on GitHub. It comes with easy to use generators, pre-installed views, compatibility with Bootstrap and several other styling frameworks. So it's probably the top choice when you start the new full-stack rise application. Then for API applications, there is an atom for device that supports the token authentication and authorization. So if you don't like typing, you can interest with this tagging to implement authentication for API, or it could be faster than from scratch. However, I used device and the device token out in countless projects, either big or small. I encountered several hard to solve issues, especially when it came to API application. Also, those gems are really tied to controllers and it's hard to extract authentication logic to independent objects. Then there is also our tyrant gem, a very small plug-in that allows you to extract authentication logic to separate model level classes, and covered authentication using unit tests without any problems. If you want to extend or change any of those gems, however, you will need to understand how they work and how the password authentication looks under the hood in general. This is why in this course, I won't use those plug-ins, but implement the authentication from scratch. And the only Jim I'll use is decrypt Ruby, which is a convenient tool to encrypt our passwords. So we won't save passwords as plain texts in our database. Here is the whole usage of this gem. In our case, we will need a column to store our encrypted password and the find method to return the password and assign new one. Let me do that. First. Let's open the jump higher at gem be crypt and from the terminal run bundle install. Now, when the gem is installed, let's play with it for a wire. You can see that there are new and create methods called on decrypted password object. I would like to check what they actually do. Console. I run secret password create, and pass the sample string as an argument. The result is the randomized string. By looking on it completely unrelated to the string I pass. Even better is that each time I call that, the result is different. This is how hashing function work. They get a string as an input and encrypt them. So there is no way to get the source argument. But if you notice source argument that was used to generate the hash, you have a way to check if it's correct based on the generic hash. If I type password new with some string, As a result, I can see something that looks like a string. But what it really is is the secret password instance. It has overridden equality operator. So you can compare this password object with any string and check if the one you compare was used to generate the password object before. So comparing the password with some string results we fall. When we compare it with the encrypted password. It also returns false. The only case it returns true is when you compare the password with the original password you use to generate the hash. That's amazing. We have a way to store passwords in a secure way and there is no risk to accidentally reveal them when rows in the database. Now when we have that covert, Let's open the user model. And here I'll pass the code from the gems documentation. One thing to notice here in the code you can see that there is password object code directly from console. I needed to call it with decrypt prefix. And this is what I would normally do here, either because this password class is defined inside of the crypt model. However, I can include be gripped model in the user class. And all methods and classes defined in this module are now accessible directory. That won't work immediately as we need yet and column in the user table to store our encrypted passwords. I'm going into the terminal window now. And here I use rise generating a great comment to generate integration named and encrypted password to users. Then I add the column name, which will be the type of string by default, and press Enter. This will add column encrypted password into the user's table. Of course, in the model we just copied the code from James documentation. And in that example, there was a password hash as a column name. I think encrypted password sounds better. So I'll change it here and go back to run gracious. Having that, we are ready to run our standard authenticator spec file and both of our tests examples should pass. Amazing. Let's open the rise consultants again and play with the user icon. I assign as user variable, the first user in our database. It comes with the login J Smith. We can now call the encrypted password and asked it's not set yet, it will return nil. And the problem is that the crypt hashing function require the argument to be present. So when we will call just password here, it will return an error. That's usually fine. As in general use case, you don't want to allow users without passwords being created. However, as we do support the outflow, we don't require users to setup the passwords right away. This is why we should support having empty passwords in our system. Let me fix that very quick. In the user object, I'll add a condition to call the password assignment on if the encrypted password is present. Otherwise, we do nothing. Now when we reload the console and fetch the user again, the password method call will return nil instead of rising and error. Now, I'll assign new password to my user, let's say secret. Now I'm going to check how the encrypted password is being set. Looks promising. So now I can compare this password with our secret shrink, and that should return true naives. So we feel the support for encrypted passwords in our user objects. In the next lesson, we will use that to allow our service process success authentication requests, instead of rising can narrow in every possible case. See you there after a short break. 54. 7.6 standard login user finder: Hello again. In the previous lesson, we managed to add the password support for our users. Now we have everything we need to 100 and success password authentication flow. At the very beginning, as you probably expected, we will visit the standard on theater spec file. Here. We'll need a few test examples. And the good thing is that it should behave similar to the outflow we did before. We will call it with different arguments set. But the end result should be the same, or at least very similar. So let me open the odd spec file. And there, Let's find this axis contexts. Here it is. We can scroll down the user data object and the whole mocking stuff we did before and go directly to the test examples. As this is what we are really interested with. There are three tests here. First of which is related to saving the user when it doesn't exist yet. However, we don't want to do that with the standard flow. Standard multiplication will contain only case when user exists in the database. For creating new user. We will need the registration endpoint later on. So there are two examples we are interested with. One that checks if we set up the user found in the database based on the provided parameters. And second, which creates the access token for this user. We will need exactly the same cases being covered. So let's go back to our standard test fire. First test I named should set the user found in database. Then the second one, it should create and set users access token. Now, let us define the user object. I will be using users factory with login sent to J Smith and password being set to password string. Then I expect that calling the subject won't change the user's count at all. After that, I add one more expectation, checking if the user setup on that and heaters object is exactly the user I defined. Now, I can jump to the next example, which also is very easy. Here I need to check if calling the subject changes the access tokens count by one and also adult indicators, access token is present. Simple stuff, right? Those tests will fail, of course, saying that the authentication error is reason. And that's expected as when we open the implementation file, there is nothing inside on the empty I initialized method and perform action always rising the error. So here, first, I'm going to set up some of the instance variables based on the parameters I get. As a login, I said the login variable, and as at password, I assign password argument. Then at the end I add the private section. And as those instance variables into attrit release. Thanks to this, I can use the login and password in whole object without prefixing it with character. And as it's in private section, no other class can access it. Having that, I'm going to take care of their performance. Here. I only rise authentication error. If login or password is blank, then we also want to rise it when there is no user in our database matching provided login. So do that, I need to add another line. We've rise authentication error. Unless user exists with logging being exactly the value we got in the login variable. Then if none of the conditions above, we can find the user based on the login variable. Please notice that I didn't set up the instance user variable here, but only the normal user variable, which will be visible only inside of this method. The reason for that is that I don't want to set up user unless I'm sure it's properly authenticated. Moving forward, having that user, we can rise authentication error again and let the users encrypted password matches the password provided. Finally, when code achieves this line, we can set up the user on the authenticator. Now when I run tests, I expect only 12, fair. But other being green, seems there is a problem here. Error message says that we don't have the proper user in our database. I bet if because we didn't even call the user before launching the test. Here of course, should also be the before block with a user called inside. So it's created before each test being launched. That should solve our problems. Now, as I mentioned, I got expected results with one test passing. So the user is properly set up, but there is no token being created yet. This is what we will do next. 55. 7.7 standard login token creation: Let me open the author beefier. As we already have this functionality implemented there, I need to scroll up to the perform action. And here it is. There is the whole user preparation logic called here. And after that, we do set up the access token. When you think about it, in our standard flow, it will look exactly the same. If user has an access token setup, just use it and otherwise create new one. I could copy that and pass it in the standard or beefier. But I don't like code duplication. So I look for the better place to pace that. As this logic is completely the same for all examples, we can just move it up to the parent class. Let me open it out indicator file. And here, after the child has performed method and write another method call which is set up the access token. Then at the end of the file, I will add the private section where I defined this metal and paste the copied lines of code inside. As this method now sets up the access token instance variable, I can get rid of this access token method and replace it with public at reader listed at the top of the file. Now I can remove those aqueducts from the children classes. So let me go to the all and remove the access token from here. Now, let's do the same for standard or indicator. And we are almost ready to go. One last thing to do is moving the test. When we switched to the test file, we can see that there is still an expectation that trying to class changes the access tokens count. But as we move the token assignment to the parent class, this test should also be moved. Let me visit that file and kept out the token rated tests and move it the parent class like this. As the whole logic of the perform action had been tested in the trunk class. I can just mock the Perform Action and force it to return true and not rising any error. Then I also need to mock the user method and return a proper user. And the reason for that is that setting the user is placed inside of the performance. So when we mock it, the logic inside stops being run. And I need to mark the things I wanted to do. That's being said. When trials performed method succeeded, the token should be created. Then I don't need the user object being defined, so I can use it here. Let the Find it at the very top of the file. So I will be able to use it in both contexts. We have, let's run this test and check it out now. Okay, it's still failing. Let's check why. It looks like we don't call the perform method inside of the test. Let me see. There is a subject called Yes. Okay. There is a subject, but it's never defined in this file. So it's just new. Okay, that's fair. As we have only one test related to the performance, I will replace the subject with just out indicators perform idle being called directly. Then I can run the test again. The final message changed, and that's promising. It says that we expect the user to be called exactly one time in the class, but it's called twice. I don't want this test to fail every time I change the tides performance. So let me tweak it up. So instead of expecting that user is called once, I will expect it to be called at least once. This way, no matter how many times the child method calls the user, as long as it's called at least once, the condition with paths. Now running, our tests should finally pass. And it did amazing. It's finally done. The only thing I would like to do yet is at the same test to the OAuth flow. Again, I could just copy that, but instead, I'll use the shared examples feature. So I will avoid code duplication. First, I cut out the content of the test and replace it with, it behaves like an indicator. Then I add the same line to the auth flow. And at the top of the file, I add the shared examples block named authenticator. Inside, I can paste the copied example. And it's all. There is one minor chord starting usually has to be fixed here. However, I accidentally placed the test related the preformatted inside of the block aggregating tests for I initialized method. And that's not ideal. Of course, when we move this test, the shirt example is how clearly visible so I can move it down. Finally, I need to move to the off spec or beefier. Here. There is also a test related to the access token creation, but we move that functionality to the parent class. So there is no need to let it here anymore. Let me remove it now and run our tests. Again. I will run all tests placed in the leap folder. So we will get nice overview of all tests we've wrote so far. All ten of them passed. So our authenticator service is completely done. It works. And outer rises users via the outflow and standard one. What is not finished yet though, is the tokens controller. We don't support accepting the login and password. And we do have only test coverage for failure messages. But don't worry, we will take care of all that in the next lesson. 56. 7.8 login with password endpoint tests: In the previous lesson, we finished our authentication service. That's amazing as we now have granted that if we only call delta indicator with proper arguments, it will properly authenticate the user using the appropriate flow. The only thing left is just updating the content in the way it gets login and password from the request and forward them into that theater itself. Here in the Postman application, we sent login set to G Smith and password being set up to Secret String. We assume that those are valid user authentication data. So let's go to the rise console and enjoy. It's a case. I'm going to fetch the first user in our database as I have only one for now. You can see that it's login is set up to G Smith already. So I just need to update the password and click Save. Now let me run the requisite. I got an error response with HTTP status code of 500, saying that there is no such a constant as decrypt. This error is very important because a lot of students reported arrows like that across the whole course. And most of them were related to the same thing. We added the new gem that defines the new classes or modules, and that often requires the server restarts. So if you don't see something that should be defined already, maybe you need to remove this error, and that's all. However, there is one hidden easily that usually when you run RSpec, Ryan's concern or any other rights common from the terminal. There is a shorter delay between hitting the Enter and printing results on the screen. And that's because each time you run the common that requires writes application to brining, it needs to put it up every single time, and that takes a moment to speed things up. New rice versions come with automatically loaded gem named spring. So the first time you run the server or RSpec command or any other arise related console commands. It boosts your application using the sprinkle and keeps running the app in the background using Spring server, even if the comet itself finishes up, that shorten the delay after running RSpec examples. But sometimes it generates problems with reloading application. That simply means even if you stop your local server and run it again in a moment, and the application is not fully restarted. And in some cases, you need to manually stop the spring server as well. Let me show it to you. I just stopped the server, but I still have spring server running. So I need to run spring stop command, and now it's stopped. Next time I'll run the server. The application will be fully reloaded. If you don't want to have the spring being used, you can always remove it from the Gemfile, but I found it more useful than baggy. So I didn't mind to restart it from time to time. If you think that you encountered a problem and rebuilding servers should help you with it. But restarting it didn't solve the issue. And just be sure that you also restart with this spring. It often helps. That's being said, let's run the server again and go back to the postman request. Now, when I run the requisite can allocate four or one status code with information about invalid login or password, which is great. I only need to tweak up the color so it will be able to accept new parameters and call the authenticator in the proper way. So to do this, I'm going to open the tokens controller spec file first. Here we have two contexts blocks for the request without any parameters and for invalid code. I'm going to add now the contexts for invalid login. Inside. I will define my subject code, which would be a post request to the create action. We've proper parameters passed. Next, let's define the parameter variable, which will be a hash with data key having attributes inside. In the attributes section, I least login set to J Smith and password set to secret. Now, I need to define the user object. I'll use the standard user factor we're specifying login and password. As you can see, this user has the same login as in the parameters. So I'll change it in a moment. But I want to finish the test first because I need one more contexts for invalid passwords in a moment. And I would like to have it unified for now. At the end of the context doc, I add our expectation, as we already wrote before, everything we need for that and placed it in the shared examples book. I can just type. It behaves like an outright standard requests and it will warp as a term. Now, I'm going to work on the invalid password contexts. And the same power was variable there. So I can just move it up one clever to make it available in the wider range instead of duplicating it. And then I can copy the contexts for invalid login and just change the name to have invalid password. Finally, to make both of those tests different, I will change the password to invalid in the second contexts and the login in the first one. Those tests are almost fine. But even if we define the user that differs for each test case, we never call it. So it's not persisted into the database when tests start to change it, I'm going to add the before block with calling the user inside for each context. Now, our failure tests are ready to be launched. But before I do that, I would like to finish it up. There is one more context needed to achieve complete test coverage for our tokens controller. And that's for success request. To speed things up, let me just copy the last contents dog from above and adjusted instead of typing everything from scratch. Here, I changed the name to when valid data provided. And then inside and going to replace the invite password with the correct one. The one we have defined in the params variable above. And I can now write our success tests. However, we did that already for our OAuth flow. So maybe it would be nice to go down few lines and just copy two examples from there. Here, I can just skip the user data definition and also the whole mocking staff and go directly to the test examples. Here, we have two tests for 21 HTTP status code and for proper adjacent body returned from the server. Let me copy them and jump back. When I paste it down, the first test will remain unchanged and just need to call the subject and expect the response to be created. In the second example, we need to add few weeks, however, are rather remove some of the unnecessary lines. For example, I don't want to change the user account when we call the subject, I can just replace this line. We've subject called them. Next. I don't want to have Jay Smith appended with one in the login. When we check the user, I would like to check the user we defined above. So this line I can completely get rid of and they can run our test file again. As expected. Two tests examples, fact, those are the success ones and that's expected because we need to adjust the contour yet. So it will take our new parameters and pass them forward into the authenticator. This is what we will take care of in the next lesson. Finally, completing the standard authentication flow. 57. 7.9 login with password success: In the last lesson, we covered the whole flow with automatic tests, but two of them related to the successful requests are still fairing. In this video, we will fix that by updating the counter, and therefore, we will finish the whole authentication flow using the user's login and password. Here in the counter. We have this authentication parameters method that we pass into those indicators object as an argument, believe it or not. But this is the only thing we need to improve to finish the whole feature. To do it, however, we need to figure out how to make this method transforming nested data hash with attributes listed inside into applying hash with only the login and password as a keys. Let me open the rise console when we can play around with the actual controller parameters class. Here I type the actin convert parameters new and assign it to a params variable. Then as an argument, I'm going to pass the hash including coat key set to sample string. I'm not sure if you are aware of that. But when you use params object in the controller, you are not working with a ruby hash. But the instance of this particular class. This is the simulation of what we have in our controller. Then this is the part of the code. If I pass the code parameter, the permit method will return the same object. However, if I don't have this parameter in the record params, the permit method will return the new action controller parameters object without any parameters listed as it only allows the code to be used. Now, let's try the second example. When we will send the request in JSON API format, we will need to figure out how to extract nested parameters. So let's check it out. As a parameters, I assign a new action controller parameters object with a hash including data key, attributes nested in it, and containing the list that consists of login and password. Now let's close all of this brackets and hit Enter. I have the parameters object I initialized with expected data now, so I can freely work with it in the console to test it out. I'll try to call the permit method passing as an argument then nested hash. What it means is just a low the request to pass a parameters including data key. This data key should contain a hash that the only key allowed is attributes. The last curly bracket says that the attributes should also be a hash. And everything inside is allowed. If I will hit Enter, oh, I forgot closing brackets. Now it's fine. When I hit Enter and get new ActionController parameters object with the flag permitted set to true. However, if I'll use that to h method on that, I will get the complete nested hash, which is hard to work with. I would love to have only one level hash, login and password that I can pass directly to the authenticator, same as with the code parameter before. So do this, I will make use of the EEG method that allows me to go deeper into the nested hash and work with a subgraph completely omitting the parent. Here is how it looks on my object. I'm calling the DQ method with a data and attributes keys. And that will go directly into attributes key and return the value of that as a result. As this is also an action called her parameters object, I can just call permit login and password. And as a result, I will get the expected object with plying key value pairs. Calling to age method on that will return an easy to use readable attributes list. There is one more thing I would like to mention here. If the key train, I want to dig into one be found in the perilous. The method is going to return nil, and that has no permit method defined. So our application will return an error like so. To prevent that, I will use the same navigation operator that calls right side. On the left side isn't know. Now, as we figured out everything, Let's go back to the code. Here we will need the new method named standard out params. And inside I'm going to type the line we just figured out in the console. So params dot dq with data and attributes case appended with save navigation operator. On the right side of the operator, I will call permit method haloing to process on login and password attributes. All others will be ignored. Then in the authentication params, I need to add the standard out Periscope and the logical OR operator for checking the code. So if the standard out params returns on action parameters, object, return the result. Otherwise, as it's near, check the code in the params. Now I'll wrap the whole condition in the brackets and call the method on the result. This is the step aspects very important. Without that you will get inconsistent results and probably the application will break. Anyway. Having that, I can just congratulate you again. You have just learned how the login your highest works in API applications in general, if you'll work with a project that makes use of device or other Authentication plugin. With this knowledge, you shouldn't have any problems with that. Now, let's run our conquered tests to be sure that they are fine and they are all green as you would probably expect. So let me just go back to the postpones collection now. Here in the valid login example, I can check the body to confirm that our data are fine. And click send request pattern before we got unauthorized error response. But this time we have successfully generated access token. That is awesome. However, we could do more. Next thing we will do is the user's registration. But that will be in the next session of this course, be prepared. 58. 8.0 registrations tests: At this point, we do have two ways to login users and thought we support creating new user by copying data from GitHub. There is no real way to register a user if we don't have a GitHub account. In the next few episodes, we will go through the process of implementing exactly that. You can think about redistricting new users as a complicated process. But in application, as simple as our registration is just an endpoint to add a new user. There shouldn't be too much logic involved in the process. So both implementation and test coverage should be quite straightforward at this point of the course. This is why in this episode, I will write all tests coverage for our endpoint, including routing and controller tests without too much explanation as we already covered all of that. But first things first, I need an endpoint to register users. So the natural thing is to visit the roots are BI file first to check where we stand for now. Here we have two roads for creating and destroying sessions. And a registration endpoint will look pretty similar. Let me create a new file placed in spectral routing folder named registrations spec RB. Inside, I would require a Rails helper file. And then I'm going to add the scaffolded describe block for registration rolls. Then I'll place my test example for routing named it should route to registrations controller create action. And inside of it, I expect that the post request to the slash sign-up URL will route to the expected controller and action, which in our case, our respectively registration and create. That's all from routing vessels. Of course, if I will run it now, it will fail saying that there is no root slash sign-up. Next thing is to add it. The roots are beefier, which I'm going to do right now. Right after decisions roots. I'm going to add post slash sign-up, being served by registrations controller create action. Now, if you remember from the previous lessons, even though I added that wrote, my test, still want pass, as there is no restrictions compared defined. To make this test green, I need to add a new controller file placed in AP confidence directory named registrations can where RB. And inside I need to define the registrations controller class, which inherits from the application based controller. That's all. When I would run a routine tests. Again, they will be all nicely green. So it's now at time to jump into the controller tests file. I'm creating a new file in spec conference directory named registrations can produce spec RB. And inside, I'm going to add the default require and default describe block. Then as we will test the create action, I will also add another describe block named from an action name prefixed with a hash, which will be a wrapper for all our test examples. For this specific section. After that, we will need two contexts. Box, first four requests, so I'll name it when invalid data provided. And second analogs for vide one. Now, finally, when the scaffolding is done, we can write our tests. First of all, I will specify the subject, which will be the postdoc was sent to the gradation. Then as a params, I will pass the params hash. I will define in a moment. Actually as the params hash will be the only thing that differs in all those examples. Let me just move it up to the marginal wrapper so it will be available everywhere. Now let's define the params for the invite contexts. It will be a hash with data and attributes keys. And inside of attributes SAP hash, I will leave the login and password as only required attributes. I will try to keep things simple, but of course, those attributes can be not enough for your application. So feel free to extend them if you need. Having that. I'm going to write a few tests examples. First of which is tricking the user creation. I expect that calling the subject will not change the user count at all. Then the next one will be for returning proper HTTP status code. And here inside we will place a line that we already wrote several times before. I call the subject and expect that the response objects have HTTP status code of unprocessable entity, or four to two if you prefer. The last test in this section is for checking the appropriate body format. I name it should return error messages in response body. And inside, after calling the subject, I expect that the JSON object has an arrow key and its content includes validation errors. Validation error for a login is a hash with a source including pointer to data slash attributes slash login. And we've detailed set two, can't be blank. Again, I'm going through all of that very quickly as all those things had been covered already in this course. But if that seems to be too fast for you, feel free to slow down the video or even pause whenever you want. But that being said, let's go back to the code. Having the first error has defined, I can copy it and replace the login with password string in the second example. And that's all invalid contexts. Test coverage is all done. We can now safely go into the other contexts when we will write few tests for the success request call. First test here is about returning to 0 1 status code. So again, so again, I just call the subject and expect the response to have HTTP status code exactly created. The next example is about creating a user. First of all, I expect the subject change user count by one. Next, I check if in the database there is a user with specific login, let's say J Smith. And if that did not exist before calling the request. Now we need to define the valid params object for this context, as we don't have any parameters defined yet. So let me just go up and copy the definition we already wrote. And now let's just fill those empty attribute values. Let's say J Smith and secret password. Amazing, since that's all done now. Now I can run those tests to check if everything is right. I know that all of them will fail, but I would like to be sure that there are no typos or damp mistakes that will take our time to fix later on. Oh, there is one problem here. The test says that there is no such key as data in the request code. And that's reasonable as when we define the subject, we did not pass the parameters hash inside of the params key, but rather pass it directly. And that caused the problem. Now, all our tests return expected messages saying that the action create in the registrations controller does not exist. This way, we feel the testing part and I will jump into the implementation of our illustration flow in the next lesson. So see you there. 59. 8.1 registration valid request: In the previous lesson, we quickly implemented the whole test coverage for our registration endpoint. And now it's time for making kit life. Our tests currently all say that the create action is missing. So let's jump to the controller and create that action. Just for now, let's leave it empty and run tests again. Now, when you will scroll up, you can see that most of those tests fail because of the unauthorized error. And that's fine as we do require authorization by default. So let me go to the Concur and add skip before action for outright method for action, create at the top of the file. Oh yeah, and fix the typo here. Now when we run our tests, we will get more meaningful information for each test example. And from this pond, we can write the actual logic. Still most of them fail however, and it will be annoying to go through all those error messages. Look for one specific thing we are working at the moment. This is why instead of running old tests at once, I will focus for now on success contexts. And only after fixing old tests inside, I will switch into handling validation errors. Let me run that test starting from line 42, which will launch all tests inside of that context rapper. As you can see, we have only two tests to concider, success message and user creation. So now I'm going back into the computer file and here I will proceed with the implementation. First of all, for successful was the controller should render adjacent with our user object and status created. Then of course, we need a user object. So I instantiate a new user passing registration params inside. The result of that, I'm going to assign into the user variable and then save that user objects. Please notice that I used a save method with an exclamation mark. So I will be able to handle validation failures via the rescue block later. Now of course, we need our registration parents railroad because we don't have such things yet. To do so I'm going to create a private method, name, registration params. And inside I just extract from the params object only their attributes and neat. So I require the parents to have data key and then nested attributes key. Next, I permit only login and password fields. And if none of those keys are present, I don't return empty ActionController parameters object. Now, let me run this test. Oh, there is no build method on the user. Of course there isn't, as we should use new when instantiating a new user. The build method is only available for has many relationships to create associated resources. In this case, however, we need to use new. Now it's fixed. So let's check out where we are. Both tests fail with a message that validation failed because of missing provider. That's fine. When I will visit their user model, you will see that we expect provider to be present. We implemented it to support multiple registration sources like GitHub, facebook, or our internal standard one. We don't want to allow this field being edited however. So I will had coded this provider in the control create metal. Here inside. I will merge them. Parameters I get we've provided are set to standard. Now we are all setup. And when I will run our tests, they should. All paths. Perfect. So at this point, you already can adding new users to your application. We need to properly handle the validations failures, of course. But let me take a quick break and we will come back to that in the next lesson. 60. 8.2 registration invalid request: Welcome back. I'm happy to say that in this episode, your registration feature will be completely functional. In the previous example, we implemented the logic to handle the valid request. But when user passes in very data, our application currently just breaks my rising the validation error and showing it to the user. Now we need to handle that. So instead of server error, client will get a nice information about what went wrong. We will start from visiting the controller and adding a rescue block, capturing only the error of class Active Record, Record invalid. Thanks to specify the error class. Every time something else we break our default arrow 100 pickup text section. And our application would be able to notify admins, for example. Inside of the rest block, I'm going to render the user. But as in previous lessons, I specified the adapter to be JSON API and serializer to be our default errors fertilizer. Finally, I'm going to add a status code to the response, setting it to unprocessable entity. Believe it or not. But that's almost everything. Thanks to all the work we did previously. Having a new counter ions is very simple as we reuse a lot of solutions defined before. Our error handling works well. And user will get error messages in appropriate format. When we will run our tests, however, not everything passes. The test fairs saying that we expect to validation errors to be returned, but we got with only the one. That's because we don't specify the password validation in the user model yet. As we didn't set any way to create users, there was no reason to add those radiations, but now it's definitely a need. So let me visit the user's model test file and add the proper validation tests inside. It already have a validation tests written. But in this case, we want a different one. As the abbreviation for password field will only happen if the user is registered from the standard password provider. Let me then name the test should validate presence of password for standard provider. Inside. I build a new user object, setting, It's login to J Smith, provider to standard and injuring the password is near. Then similar to the testable, I expect that this user is invalid. And that's a user's error messages hash includes the password key being an RA, including value a can't be blank. Now, let me run this test to check if it's fairing. As expected. It says that I want a user to be invalid, but at the addition rule for password is missing. No error has been added and user is completely correct for now. That means I need to visit the model file again and add the missing validation here. Here I am adding new line that user validates a password with presence set to true. Now, as I only want this validation to run when the provider is set to standard one. I'm going to add a simple condition. The syntax for that is by using if parameter with a proc object inside of the Prague. I just check if provider is exactly standard. Now, let's save the file. Oh, editor says that there is a syntax error. Oh yeah, I need a proc, not a hash here. Now it's fine. By the way, if you're not familiar with probes, they are just inline functions. It's completely the same as calling a method name here. Let's say standard provider suffix by a question mark. And then the find this method below like that. Both those syntaxes are completely fine. But my condition is so simple that I decided to save fuel lines by using a shorter version. Now, let's run our tests again. That's one test is still failing. But I'm sure I wrote everything right. Oh, here is the weirdo. If you look closer, you can see that the encrypted password is set on the user, even though I have set it to nil. So there is probably a bag with assigning passwords to the user. The easiest way for me to confirm that is by running the rise console and reproduce what we have in the test. First of all, I'm going to assign new user to the variable and press Enter. No attribute set, nothing. As you can see, the encrypted password field is blank here, which is correct. Now let's call the password and it returns nil as expected. Our test, however, tries to assign the password to the user object by setting the new value to it. So let's check out what happens then. For user password. Let's assign you and now check out what the password method returns. Yep. It's filled in even if it should be still blank. Now when we detected the source of the problem, I'm going to visit the user model file again and squashes back here in the password assignment. Before making use of the crypt password create method, I will just assign a new password as a password instance variable. If the new password is blank, in that case, validation won't allow the user to be saved. So it should not be a problem. Now, after applying this fix, our tests should all be green. Nice. I can also run our controller tests to see that this change also fix the previous failures. Amazing. So at this point, all is working well and you can freely celebrate. Before you do however, let me show you one more thing. I'm going to switch to the Postman application to show you how it works from their hearing. Our application collection, I have registrations folder with requisites for valid and invalid responses. In the invalid request. I only said the Login to be blank string and omit the password completely. When I click Send button as the response, I get exactly those areas we know from automatic tests. Now, let's check what happens for valid request. I also got an error, but this time saying that the login is already used. And that's because we have uniqueness validation added the user and I already clicked this button before to check it out. But when I go to the records body and haptic login to J Smith to instead of J Smith, I will go to the address bus with all necessary user data. For this course, I kept things simple, but you'd probably want to add something like a place holder for users without abattoirs are automatic graph after removing duration based on the e-mail. But that's up to you. I can just say congratulations again for doing so great job. As your registration endpoint is now completely finished.