One place for hosting & domains

      Application

      How To Make a Web Application Using Flask in Python 3


      The author selected the Free and Open Source Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Flask is a small and lightweight Python web framework that provides useful tools and features that make creating web applications in Python easier. It gives developers flexibility and is a more accessible framework for new developers since you can build a web application quickly using only a single Python file. Flask is also extensible and doesn’t force a particular directory structure or require complicated boilerplate code before getting started.

      As part of this tutorial, you’ll use the Bootstrap toolkit to style your application so it is more visually appealing. Bootstrap will help you incorporate responsive web pages in your web application so that it also works well on mobile browsers without writing your own HTML, CSS, and JavaScript code to achieve these goals. The toolkit will allow you to focus on learning how Flask works.

      Flask uses the Jinja template engine to dynamically build HTML pages using familiar Python concepts such as variables, loops, lists, and so on. You’ll use these templates as part of this project.

      In this tutorial, you’ll build a small web blog using Flask and SQLite in Python 3. Users of the application can view all the posts in your database and click on the title of a post to view its contents with the ability to add a new post to the database and edit or delete an existing post.

      Prerequisites

      Before you start following this guide, you will need:

      Step 1 — Installing Flask

      In this step, you’ll activate your Python environment and install Flask using the pip package installer.

      If you haven’t already activated your programming environment, make sure you’re in your project directory (flask_blog) and use the following command to activate the environment:

      Once your programming environment is activated, your prompt will now have an env prefix that may look as follows:

      This prefix is an indication that the environment env is currently active, which might have another name depending on how you named it during creation.

      Note: You can use Git, a version control system, to effectively manage and track the development process for your project. To learn how to use Git, you might want to check out our Introduction to Git Installation Usage and Branches article.

      If you are using Git, it is a good idea to ignore the newly created env directory in your .gitignore file to avoid tracking files not related to the project.

      Now you’ll install Python packages and isolate your project code away from the main Python system installation. You’ll do this using pip and python.

      To install Flask, run the following command:

      Once the installation is complete, run the following command to confirm the installation:

      • python -c "import flask; print(flask.__version__)"

      You use the python command line interface with the option -c to execute Python code. Next you import the flask package with import flask; then print the Flask version, which is provided via the flask.__version__ variable.

      The output will be a version number similar to the following:

      Output

      1.1.2

      You’ve created the project folder, a virtual environment, and installed Flask. You’re now ready to move on to setting up your base application.

      Step 2 — Creating a Base Application

      Now that you have your programming environment set up, you’ll start using Flask. In this step, you’ll make a small web application inside a Python file and run it to start the server, which will display some information on the browser.

      In your flask_blog directory, open a file named hello.py for editing, use nano or your favorite text editor:

      This hello.py file will serve as a minimal example of how to handle HTTP requests. Inside it, you’ll import the Flask object, and create a function that returns an HTTP response. Write the following code inside hello.py:

      flask_blog/hello.py

      from flask import Flask
      
      app = Flask(__name__)
      
      
      @app.route('/')
      def hello():
          return 'Hello, World!'
      

      In the preceding code block, you first import the Flask object from the flask package. You then use it to create your Flask application instance with the name app. You pass the special variable __name__ that holds the name of the current Python module. It’s used to tell the instance where it’s located—you need this because Flask sets up some paths behind the scenes.

      Once you create the app instance, you use it to handle incoming web requests and send responses to the user. @app.route is a decorator that turns a regular Python function into a Flask view function, which converts the function’s return value into an HTTP response to be displayed by an HTTP client, such as a web browser. You pass the value '/' to @app.route() to signify that this function will respond to web requests for the URL /, which is the main URL.

      The hello() view function returns the string 'Hello, World!' as a response.

      Save and close the file.

      To run your web application, you’ll first tell Flask where to find the application (the hello.py file in your case) with the FLASK_APP environment variable:

      Then run it in development mode with the FLASK_ENV environment variable:

      • export FLASK_ENV=development

      Lastly, run the application using the flask run command:

      Once the application is running the output will be something like this:

      Output

      * Serving Flask app "hello" (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 813-894-335

      The preceding output has several pieces of information, such as:

      • The name of the application you’re running.
      • The environment in which the application is being run.
      • Debug mode: on signifies that the Flask debugger is running. This is useful when developing because it gives us detailed error messages when things go wrong, which makes troubleshooting easier.
      • The application is running locally on the URL http://127.0.0.1:5000/, 127.0.0.1 is the IP that represents your machine’s localhost and :5000 is the port number.

      Open a browser and type in the URL http://127.0.0.1:5000/, you will receive the string Hello, World! as a response, this confirms that your application is successfully running.

      Warning Flask uses a simple web server to serve our application in a development environment, which also means that the Flask debugger is running to make catching errors easier. This development server should not be used in a production deployment. See the Deployment Options page on the Flask documentation for more information, you can also check out this Flask deployment tutorial.

      You can now leave the development server running in the terminal and open another terminal window. Move into the project folder where hello.py is located, activate the virtual environment, set the environment variables FLASK_ENV and FLASK_APP, and continue to the next steps. (These commands are listed earlier in this step.)

      Note: When opening a new terminal, it is important to remember activating the virtual environment and setting the environment variables FLASK_ENV and FLASK_APP.

      While a Flask application’s development server is already running, it is not possible to run another Flask application with the same flask run command. This is because flask run uses the port number 5000 by default, and once it is taken, it becomes unavailable to run another application on so you would receive an error similar to the following:

      Output

      OSError: [Errno 98] Address already in use

      To solve this problem, either stop the server that’s currently running via CTRL+C, then run flask run again, or if you want to run both at the same time, you can pass a different port number to the -p argument, for example, to run another application on port 5001 use the following command:

      You now have a small Flask web application. You’ve run your application and displayed information on the web browser. Next, you’ll use HTML files in your application.

      Step 3 — Using HTML templates

      Currently your application only displays a simple message without any HTML. Web applications mainly use HTML to display information for the visitor, so you’ll now work on incorporating HTML files in your app, which can be displayed on the web browser.

      Flask provides a render_template() helper function that allows use of the Jinja template engine. This will make managing HTML much easier by writing your HTML code in .html files as well as using logic in your HTML code. You’ll use these HTML files, (templates) to build all of your application pages, such as the main page where you’ll display the current blog posts, the page of the blog post, the page where the user can add a new post, and so on.

      In this step, you’ll create your main Flask application in a new file.

      First, in your flask_blog directory, use nano or your favorite editor to create and edit your app.py file. This will hold all the code you’ll use to create the blogging application:

      In this new file, you’ll import the Flask object to create a Flask application instance as you previously did. You’ll also import the render_template() helper function that lets you render HTML template files that exist in the templates folder you’re about to create. The file will have a single view function that will be responsible for handling requests to the main / route. Add the following content:

      flask_blog/app.py

      from flask import Flask, render_template
      
      app = Flask(__name__)
      
      @app.route('/')
      def index():
          return render_template('index.html')
      

      The index() view function returns the result of calling render_template() with index.html as an argument, this tells render_template() to look for a file called index.html in the templates folder. Both the folder and the file do not yet exist, you will get an error if you were to run the application at this point. You’ll run it nonetheless so you’re familiar with this commonly encountered exception. You’ll then fix it by creating the needed folder and file.

      Save and exit the file.

      Stop the development server in your other terminal that runs the hello application with CTRL+C.

      Before you run the application, make sure you correctly specify the value for the FLASK_APP environment variable, since you’re no longer using the application hello:

      • export FLASK_APP=app
      • flask run

      Opening the URL http://127.0.0.1:5000/ in your browser will result in the debugger page informing you that the index.html template was not found. The main line in the code that was responsible for this error will be highlighted. In this case, it is the line return render_template('index.html').

      If you click this line, the debugger will reveal more code so that you have more context to help you solve the problem.

      The Flask Debugger

      To fix this error, create a directory called templates inside your flask_blog directory. Then inside it, open a file called index.html for editing:

      • mkdir templates
      • nano templates/index.html

      Next, add the following HTML code inside index.html:

      flask_blog/templates/index.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>FlaskBlog</title>
      </head>
      <body>
         <h1>Welcome to FlaskBlog</h1>
      </body>
      </html>
      

      Save the file and use your browser to navigate to http://127.0.0.1:5000/ again, or refresh the page. This time the browser should display the text Welcome to FlaskBlog in an <h1> tag.

      In addition to the templates folder, Flask web applications also typically have a static folder for hosting static files, such as CSS files, JavaScript files, and images the application uses.

      You can create a style.css style sheet file to add CSS to your application. First, create a directory called static inside your main flask_blog directory:

      Then create another directory called css inside the static directory to host .css files. This is typically done to organize static files in dedicated folders, as such, JavaScript files typically live inside a directory called js, images are put in a directory called images (or img), and so on. The following command will create the css directory inside the static directory:

      Then open a style.css file inside the css directory for editing:

      • nano static/css/style.css

      Add the following CSS rule to your style.css file:

      flask_blog/static/css/style.css

      h1 {
          border: 2px #eee solid;
          color: brown;
          text-align: center;
          padding: 10px;
      }
      

      The CSS code will add a border, change the color to brown, center the text, and add a little padding to <h1> tags.

      Save and close the file.

      Next, open the index.html template file for editing:

      • nano templates/index.html

      You’ll add a link to the style.css file inside the <head> section of the index.html template file:

      flask_blog/templates/index.html

      . . .
      <head>
          <meta charset="UTF-8">
          <link rel="stylesheet" href="https://www.digitalocean.com/{{ url_for("static', filename= 'css/style.css') }}">
          <title>FlaskBlog</title>
      </head>
      . . .
      

      Here you use the url_for() helper function to generate the appropriate location of the file. The first argument specifies that you’re linking to a static file and the second argument is the path of the file inside the static directory.

      Save and close the file.

      Upon refreshing the index page of your application, you will notice that the text Welcome to FlaskBlog is now in brown, centered, and enclosed inside a border.

      You can use the CSS language to style the application and make it more appealing using your own design. However, if you’re not a web designer, or if you aren’t familiar with CSS, then you can use the Bootstrap toolkit, which provides easy-to-use components for styling your application. In this project, we’ll use Bootstrap.

      You might have guessed that making another HTML template would mean repeating most of the HTML code you already wrote in the index.html template. You can avoid unnecessary code repetition with the help of a base template file, which all of your HTML files will inherit from. See Template Inheritance in Jinja for more information.

      To make a base template, first create a file called base.html inside your templates directory:

      Type the following code in your base.html template:

      flask_blog/templates/base.html

      <!doctype html>
      <html lang="en">
        <head>
          <!-- Required meta tags -->
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
      
          <!-- Bootstrap CSS -->
          <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
      
          <title>{% block title %} {% endblock %}</title>
        </head>
        <body>
          <nav class="navbar navbar-expand-md navbar-light bg-light">
              <a class="navbar-brand" href="https://www.digitalocean.com/{{ url_for('index')}}">FlaskBlog</a>
              <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                  <span class="navbar-toggler-icon"></span>
              </button>
              <div class="collapse navbar-collapse" id="navbarNav">
                  <ul class="navbar-nav">
                  <li class="nav-item active">
                      <a class="nav-link" href="https://www.digitalocean.com/#">About</a>
                  </li>
                  </ul>
              </div>
          </nav>
          <div class="container">
              {% block content %} {% endblock %}
          </div>
      
          <!-- Optional JavaScript -->
          <!-- jQuery first, then Popper.js, then Bootstrap JS -->
          <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
          <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
          <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
        </body>
      </html>
      

      Save and close the file once you’re done editing it.

      Most of the code in the preceding block is standard HTML and code required for Bootstrap. The <meta> tags provide information for the web browser, the <link> tag links the Bootstrap CSS files, and the <script> tags are links to JavaScript code that allows some additional Bootstrap features, check out the Bootstrap documentation for more.

      However, the following highlighted parts are specific to the Jinja template engine:

      • {% block title %} {% endblock %}: A block that serves as a placeholder for a title, you’ll later use it in other templates to give a custom title for each page in your application without rewriting the entire <head> section each time.
      • {{ url_for('index')}}: A function call that will return the URL for the index() view function. This is different from the past url_for() call you used to link a static CSS file, because it only takes one argument, which is the view function’s name, and links to the route associated with the function instead of a static file.
      • {% block content %} {% endblock %}: Another block that will be replaced by content depending on the child template (templates that inherit from base.html) that will override it.

      Now that you have a base template, you can take advantage of it using inheritance. Open the index.html file:

      • nano templates/index.html

      Then replace its contents with the following:

      flask_blog/templates/index.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
      {% endblock %}
      

      In this new version of the index.html template, you use the {% extends %} tag to inherit from the base.html template. You then extend it via replacing the content block in the base template with what is inside the content block in the preceding code block.

      This content block contains an <h1> tag with the text Welcome to FlaskBlog inside a title block, which in turn replaces the original title block in the base.html template with the text Welcome to FlaskBlog. This way, you can avoid repeating the same text twice, as it works both as a title for the page and a heading that appears below the navigation bar inherited from the base template.

      Template inheritance also gives you the ability to reuse the HTML code you have in other templates (base.html in this case) without having to repeat it each time it is needed.

      Save and close the file and refresh the index page on your browser. You’ll see your page with a navigation bar and styled title.

      Index Page with Bootstrap

      You’ve used HTML templates and static files in Flask. You also used Bootstrap to start refining the look of your page and a base template to avoid code repetition. In the next step, you’ll set up a database that will store your application data.

      Step 4 — Setting up the Database

      In this step, you’ll set up a database to store data, that is, the blog posts for your application. You’ll also populate the database with a few example entries.

      You’ll use a SQLite database file to store your data because the sqlite3 module, which we will use to interact with the database, is readily available in the standard Python library. For more information about SQLite, check out this tutorial.

      First, because data in SQLite is stored in tables and columns, and since your data mainly consists of blog posts, you first need to create a table called posts with the necessary columns. You’ll create a .sql file that contains SQL commands to create the posts table with a few columns. You’ll then use this file to create the database.

      Open a file called schema.sql inside your flask_blog directory:

      Type the following SQL commands inside this file:

      flask_blog/schema.sql

      DROP TABLE IF EXISTS posts;
      
      CREATE TABLE posts (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
          title TEXT NOT NULL,
          content TEXT NOT NULL
      );
      

      Save and close the file.

      The first SQL command is DROP TABLE IF EXISTS posts;, this deletes any already existing tables named posts so you don’t get confusing behavior. Note that this will delete all of the content you have in the database whenever you use these SQL commands, so ensure you don’t write any important content in the web application until you finish this tutorial and experiment with the final result. Next, CREATE TABLE posts is used to create the posts table with the following columns:

      • id: An integer that represents a primary key, this will get assigned a unique value by the database for each entry (that is a blog post).
      • created: The time the blog post was created at. NOT NULL signifies that this column should not be empty and the DEFAULT value is the CURRENT_TIMESTAMP value, which is the time at which the post was added to the database. Just like id, you don’t need to specify a value for this column, as it will be automatically filled in.
      • title: The post title.
      • content: The post content.

      Now that you have a SQL schema in the schema.sql file, you’ll use it to create the database using a Python file that will generate an SQLite .db database file. Open a file named init_db.py inside the flask_blog directory using your preferred editor:

      And then add the following code.

      flask_blog/init_db.py

      import sqlite3
      
      connection = sqlite3.connect('database.db')
      
      
      with open('schema.sql') as f:
          connection.executescript(f.read())
      
      cur = connection.cursor()
      
      cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
                  ('First Post', 'Content for the first post')
                  )
      
      cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
                  ('Second Post', 'Content for the second post')
                  )
      
      connection.commit()
      connection.close()
      

      You first import the sqlite3 module and then open a connection to a database file named database.db, which will be created once you run the Python file. Then you use the open() function to open the schema.sql file. Next you execute its contents using the executescript() method that executes multiple SQL statements at once, which will create the posts table. You create a Cursor object that allows you to use its execute() method to execute two INSERT SQL statements to add two blog posts to your posts table. Finally, you commit the changes and close the connection.

      Save and close the file and then run it in the terminal using the python command:

      Once the file finishes execution, a new file called database.db will appear in your flask_blog directory. This means you’ve successfully set up your database.

      In the next step, you’ll retrieve the posts you inserted into your database and display them in your application’s homepage.

      Step 5 — Displaying All Posts

      Now that you’ve set up your database, you can now modify the index() view function to display all the posts you have in your database.

      Open the app.py file to make the following modifications:

      For your first modification, you’ll import the sqlite3 module at the top of the file:

      flask_blog/app.py

      import sqlite3
      from flask import Flask, render_template
      
      . . .
      

      Next, you’ll create a function that creates a database connection and return it. Add it directly after the imports:

      flask_blog/app.py

      . . .
      from flask import Flask, render_template
      
      def get_db_connection():
          conn = sqlite3.connect('database.db')
          conn.row_factory = sqlite3.Row
          return conn
      
      . . .
      

      This get_db_connection() function opens a connection to the database.db database file, and then sets the row_factory attribute to sqlite3.Row so you can have name-based access to columns. This means that the database connection will return rows that behave like regular Python dictionaries. Lastly, the function returns the conn connection object you’ll be using to access the database.

      After defining the get_db_connection() function, modify the index() function to look like the following:

      flask_blog/app.py

      . . .
      
      @app.route('/')
      def index():
          conn = get_db_connection()
          posts = conn.execute('SELECT * FROM posts').fetchall()
          conn.close()
          return render_template('index.html"https://www.digitalocean.com/, posts=posts)
      

      In this new version of the index() function, you first open a database connection using the get_db_connection() function you defined earlier. Then you execute an SQL query to select all entries from the posts table. You implement the fetchall() method to fetch all the rows of the query result, this will return a list of the posts you inserted into the database in the previous step.

      You close the database connection using the close() method and return the result of rendering the index.html template. You also pass the posts object as an argument, which contains the results you got from the database, this will allow you to access the blog posts in the index.html template.

      With these modifications in place, save and close the app.py file.

      Now that you’ve passed the posts you fetched from the database to the index.html template, you can use a for loop to display each post on your index page.

      Open the index.html file:

      • nano templates/index.html

      Then, modify it to look as follows:

      flask_blog/templates/index.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
          {% for post in posts %}
              <a href="https://www.digitalocean.com/#">
                  <h2>{{ post['title'] }}</h2>
              </a>
              <span class="badge badge-primary">{{ post['created'] }}</span>
              <hr>
          {% endfor %}
      {% endblock %}
      

      Here, the syntax {% for post in posts %} is a Jinja for loop, which is similar to a Python for loop except that it has to be later closed with the {% endfor %} syntax. You use this syntax to loop over each item in the posts list that was passed by the index() function in the line return render_template('index.html', posts=posts). Inside this for loop, you display the post title in an <h2> heading inside an <a> tag (you’ll later use this tag to link to each post individually).

      You display the title using a literal variable delimiter ({{ ... }}). Remember that post will be a dictionary-like object, so you can access the post title with post['title']. You also display the post creation date using the same method.

      Once you are done editing the file, save and close it. Then navigate to the index page in your browser. You’ll see the two posts you added to the database on your page.

      Index Page with Posts Displayed

      Now that you’ve modified the index() view function to display all the posts you have in the database on your application’s homepage, you’ll move on to display each post in a single page and allow users to link to each individual post.

      Step 6 — Displaying a Single Post

      In this step, you’ll create a new Flask route with a view function and a new HTML template to display an individual blog post by its ID.

      By the end of this step, the URL http://127.0.0.1:5000/1 will be a page that displays the first post (because it has the ID 1). The http://127.0.0.1:5000/ID URL will display the post with the associated ID number if it exists.

      Open app.py for editing:

      Since you’ll need to get a blog post by its ID from the database in multiple locations later in this project, you’ll create a standalone function called get_post(). You can call it by passing it an ID and receive back the blog post associated with the provided ID, or make Flask respond with a 404 Not Found message if the blog post does not exist.

      To respond with a 404 page, you need to import the abort() function from the Werkzeug library, which was installed along with Flask, at the top of the file:

      flask_blog/app.py

      import sqlite3
      from flask import Flask, render_template
      from werkzeug.exceptions import abort
      
      . . .
      

      Then, add the get_post() function right after the get_db_connection() function you created in the previous step:

      flask_blog/app.py

      . . .
      
      def get_db_connection():
          conn = sqlite3.connect('database.db')
          conn.row_factory = sqlite3.Row
          return conn
      
      
      def get_post(post_id):
          conn = get_db_connection()
          post = conn.execute('SELECT * FROM posts WHERE id = ?',
                              (post_id,)).fetchone()
          conn.close()
          if post is None:
              abort(404)
          return post
      
      . . .
      

      This new function has a post_id argument that determines what blog post to return.

      Inside the function, you use the get_db_connection() function to open a database connection and execute a SQL query to get the blog post associated with the given post_id value. You add the fetchone() method to get the result and store it in the post variable then close the connection. If the post variable has the value None, meaning no result was found in the database, you use the abort() function you imported earlier to respond with a 404 error code and the function will finish execution. If however, a post was found, you return the value of the post variable.

      Next, add the following view function at the end of the app.py file:

      flask_blog/app.py

      . . .
      
      @app.route('/<int:post_id>')
      def post(post_id):
          post = get_post(post_id)
          return render_template('post.html', post=post)
      

      In this new view function, you add a variable rule <int:post_id> to specify that the part after the slash (/) is a positive integer (marked with the int converter) that you need to access in your view function. Flask recognizes this and passes its value to the post_id keyword argument of your post() view function. You then use the get_post() function to get the blog post associated with the specified ID and store the result in the post variable, which you pass to a post.html template that you’ll soon create.

      Save the app.py file and open a new post.html template file for editing:

      Type the following code in this new post.html file. This will be similar to the index.html file, except that it will only display a single post, in addition to also displaying the contents of the post:

      flask_blog/templates/post.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h2>{% block title %} {{ post['title'] }} {% endblock %}</h2>
          <span class="badge badge-primary">{{ post['created'] }}</span>
          <p>{{ post['content'] }}</p>
      {% endblock %}
      

      You add the title block that you defined in the base.html template to make the title of the page reflect the post title that is displayed in an <h2> heading at the same time.

      Save and close the file.

      You can now navigate to the following URLs to see the two posts you have in your database, along with a page that tells the user that the requested blog post was not found (since there is no post with an ID number of 3 so far):

      http://127.0.0.1:5000/1
      http://127.0.0.1:5000/2
      http://127.0.0.1:5000/3
      

      Going back to the index page, you’ll make each post title link to its respective page. You’ll do this using the url_for() function. First, open the index.html template for editing:

      • nano templates/index.html

      Then change the value of the href attribute from # to {{ url_for('post', post_id=post['id']) }} so that the for loop will look exactly as follows:

      flask_blog/templates/index.html

      {% for post in posts %}
          <a href="https://www.digitalocean.com/{{ url_for('post', post_id=post['id']) }}">
              <h2>{{ post['title'] }}</h2>
          </a>
          <span class="badge badge-primary">{{ post['created'] }}</span>
          <hr>
      {% endfor %}
      

      Here, you pass 'post' to the url_for() function as a first argument. This is the name of the post() view function and since it accepts a post_id argument, you give it the value post['id']. The url_for() function will return the proper URL for each post based on its ID.

      Save and close the file.

      The links on the index page will now function as expected. With this, you’ve now finished building the part of the application responsible for displaying the blog posts in your database. Next, you’ll add the ability to create, edit, and delete blog posts to your application.

      Step 7 — Modifying Posts

      Now that you’ve finished displaying the blog posts that are present in the database on the web application, you need to allow the users of your application to write new blog posts and add them to the database, edit the existing ones, and delete unnecessary blog posts.

      Creating a New Post

      Up to this point, you have an application that displays the posts in your database but provides no way of adding a new post unless you directly connect to the SQLite database and add one manually. In this section, you’ll create a page on which you will be able to create a post by providing its title and content.

      Open the app.py file for editing:

      First, you’ll import the following from the Flask framework:

      • The global request object to access incoming request data that will be submitted via an HTML form.
      • The url_for() function to generate URLs.
      • The flash() function to flash a message when a request is processed.
      • The redirect() function to redirect the client to a different location.

      Add the imports to your file like the following:

      flask_blog/app.py

      import sqlite3
      from flask import Flask, render_template, request, url_for, flash, redirect
      from werkzeug.exceptions import abort
      
      . . .
      

      The flash() function stores flashed messages in the client’s browser session, which requires setting a secret key. This secret key is used to secure sessions, which allow Flask to remember information from one request to another, such as moving from the new post page to the index page. The user can access the information stored in the session, but cannot modify it unless they have the secret key, so you must never allow anyone to access your secret key. See the Flask documentation for sessions for more information.

      To set a secret key, you’ll add a SECRET_KEY configuration to your application via the app.config object. Add it directly following the app definition before defining the index() view function:

      flask_blog/app.py

      . . .
      app = Flask(__name__)
      app.config['SECRET_KEY'] = 'your secret key'
      
      
      @app.route('/')
      def index():
          conn = get_db_connection()
          posts = conn.execute('SELECT * FROM posts').fetchall()
          conn.close()
          return render_template('index.html', posts=posts)
      
      . . .
      

      Remember that the secret key should be a long random string.

      After setting a secret key, you’ll create a view function that will render a template that displays a form you can fill in to create a new blog post. Add this new function at the bottom of the file:

      flask_blog/app.py

      . . .
      
      @app.route('/create', methods=('GET', 'POST'))
      def create():
          return render_template('create.html')
      

      This creates a /create route that accepts both GET and POST requests. GET requests are accepted by default. To also accept POST requests, which are sent by the browser when submitting forms, you’ll pass a tuple with the accepted types of requests to the methods argument of the @app.route() decorator.

      Save and close the file.

      To create the template, open a file called create.html inside your templates folder:

      • nano templates/create.html

      Add the following code inside this new file:

      flask_blog/templates/create.html

      {% extends 'base.html' %}
      
      {% block content %}
      <h1>{% block title %} Create a New Post {% endblock %}</h1>
      
      <form method="post">
          <div class="form-group">
              <label for="title">Title</label>
              <input type="text" name="title"
                     placeholder="Post title" class="form-control"
                     value="{{ request.form['title'] }}"></input>
          </div>
      
          <div class="form-group">
              <label for="content">Content</label>
              <textarea name="content" placeholder="Post content"
                        class="form-control">{{ request.form['content'] }}</textarea>
          </div>
          <div class="form-group">
              <button type="submit" class="btn btn-primary">Submit</button>
          </div>
      </form>
      {% endblock %}
      

      Most of this code is standard HTML. It will display an input box for the post title, a text area for the post content, and a button to submit the form.

      The value of the post title input is {{ request.form['title'] }} and the text area has the value {{ request.form['content'] }}, this is done so that the data you enter does not get lost if something goes wrong. For example, if you write a long post and you forget to give it a title, a message will be displayed informing you that the title is required. This will happen without losing the post you wrote since it will be stored in the request global object that you have access to in your templates.

      Now, with the development server running, use your browser to navigate to the /create route:

      http://127.0.0.1:5000/create
      

      You will see a Create a New Post page with a box for a title and content.

      Create a New Post Page

      This form submits a POST request to your create() view function. However, there is no code to handle a POST request in the function yet, so nothing happens after filling in the form and submitting it.

      You’ll handle the incoming POST request when a form is submitted. You’ll do this inside the create() view function. You can separately handle the POST request by checking the value of request.method. When its value is set to 'POST' it means the request is a POST request, you’ll then proceed to extract submitted data, validate it, and insert it into your database.

      Open the app.py file for editing:

      Modify the create() view function to look exactly as follows:

      flask_blog/app.py

      . . .
      
      @app.route('/create', methods=('GET', 'POST'))
      def create():
          if request.method == 'POST':
              title = request.form['title']
              content = request.form['content']
      
              if not title:
                  flash('Title is required!')
              else:
                  conn = get_db_connection()
                  conn.execute('INSERT INTO posts (title, content) VALUES (?, ?)',
                               (title, content))
                  conn.commit()
                  conn.close()
                  return redirect(url_for('index'))
      
          return render_template('create.html')
      

      In the if statement you ensure that the code following it is only executed when the request is a POST request via the comparison request.method == 'POST'.

      You then extract the submitted title and content from the request.form object that gives you access to the form data in the request. If the title is not provided, the condition if not title would be fulfilled, displaying a message to the user informing them that the title is required. If, on the other hand, the title is provided, you open a connection with the get_db_connection() function and insert the title and the content you received into the posts table.

      You then commit the changes to the database and close the connection. After adding the blog post to the database, you redirect the client to the index page using the redirect() function passing it the URL generated by the url_for() function with the value 'index' as an argument.

      Save and close the file.

      Now, navigate to the /create route using your web browser:

      http://127.0.0.1:5000/create
      

      Fill in the form with a title of your choice and some content. Once you submit the form, you will see the new post listed on the index page.

      Lastly, you’ll display flashed messages and add a link to the navigation bar in the base.html template to have easy access to this new page. Open the template file:

      Edit the file by adding a new <li> tag following the About link inside the <nav> tag. Then add a new for loop directly above the content block to display the flashed messages below the navigation bar. These messages are available in the special get_flashed_messages() function Flask provides:

      flask_blog/templates/base.html

      <nav class="navbar navbar-expand-md navbar-light bg-light">
          <a class="navbar-brand" href="https://www.digitalocean.com/{{ url_for("index')}}">FlaskBlog</a>
          <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
              <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarNav">
              <ul class="navbar-nav">
              <li class="nav-item">
                  <a class="nav-link" href="https://www.digitalocean.com/#">About</a>
              </li>
              <li class="nav-item">
                  <a class="nav-link" href="https://www.digitalocean.com/{{url_for("create')}}">New Post</a>
              </li>
              </ul>
          </div>
      </nav>
      <div class="container">
          {% for message in get_flashed_messages() %}
              <div class="alert alert-danger">{{ message }}</div>
          {% endfor %}
          {% block content %} {% endblock %}
      </div>
      

      Save and close the file. The navigation bar will now have a New Post item that links to the /create route.

      Editing a Post

      For a blog to be up to date, you’ll need to be able to edit your existing posts. This section will guide you through creating a new page in your application to simplify the process of editing a post.

      First, you’ll add a new route to the app.py file. Its view function will receive the ID of the post that needs to be edited, the URL will be in the format /post_id/edit with the post_id variable being the ID of the post. Open the app.py file for editing:

      Next, add the following edit() view function at the end of the file. Editing an existing post is similar to creating a new one, so this view function will be similar to the create() view function:

      flask_blog/app.py

      . . .
      
      @app.route('/<int:id>/edit', methods=('GET', 'POST'))
      def edit(id):
          post = get_post(id)
      
          if request.method == 'POST':
              title = request.form['title']
              content = request.form['content']
      
              if not title:
                  flash('Title is required!')
              else:
                  conn = get_db_connection()
                  conn.execute('UPDATE posts SET title = ?, content = ?'
                               ' WHERE id = ?',
                               (title, content, id))
                  conn.commit()
                  conn.close()
                  return redirect(url_for('index'))
      
          return render_template('edit.html', post=post)
      

      The post you edit is determined by the URL and Flask will pass the ID number to the edit() function via the id argument. You add this value to the get_post() function to fetch the post associated with the provided ID from the database. The new data will come in a POST request, which is handled inside the if request.method == 'POST' condition.

      Just like when you create a new post, you first extract the data from the request.form object then flash a message if the title has an empty value, otherwise, you open a database connection. Then you update the posts table by setting a new title and new content where the ID of the post in the database is equal to the ID that was in the URL.

      In the case of a GET request, you render an edit.html template passing in the post variable that holds the returned value of the get_post() function. You’ll use this to display the existing title and content on the edit page.

      Save and close the file, then create a new edit.html template:

      Write the following code inside this new file:

      flask_blog/templates/edit.html

      {% extends 'base.html' %}
      
      {% block content %}
      <h1>{% block title %} Edit "{{ post['title'] }}" {% endblock %}</h1>
      
      <form method="post">
          <div class="form-group">
              <label for="title">Title</label>
              <input type="text" name="title" placeholder="Post title"
                     class="form-control"
                     value="{{ request.form['title'] or post['title'] }}">
              </input>
          </div>
      
          <div class="form-group">
              <label for="content">Content</label>
              <textarea name="content" placeholder="Post content"
                        class="form-control">{{ request.form['content'] or post['content'] }}</textarea>
          </div>
          <div class="form-group">
              <button type="submit" class="btn btn-primary">Submit</button>
          </div>
      </form>
      <hr>
      {% endblock %}
      

      Save and close the file.

      This code follows the same pattern except for the {{ request.form['title'] or post['title'] }} and {{ request.form['content'] or post['content'] }} syntax. This displays the data stored in the request if it exists, otherwise it displays the data from the post variable that was passed to the template containing current database data.

      Now, navigate to the following URL to edit the first post:

      http://127.0.0.1:5000/1/edit
      

      You will see an Edit “First Post” page.

      Edit a Post Page

      Edit the post and submit the form, then make sure the post was updated.

      You now need to add a link that points to the edit page for each post on the index page. Open the index.html template file:

      • nano templates/index.html

      Edit the file to look exactly like the following:

      flask_blog/templates/index.html

      {% extends 'base.html' %}
      
      {% block content %}
          <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
          {% for post in posts %}
              <a href="https://www.digitalocean.com/{{ url_for("post', post_id=post['id']) }}">
                  <h2>{{ post['title'] }}</h2>
              </a>
              <span class="badge badge-primary">{{ post['created'] }}</span>
              <a href="https://www.digitalocean.com/{{ url_for("edit', id=post['id']) }}">
                  <span class="badge badge-warning">Edit</span>
              </a>
              <hr>
          {% endfor %}
      {% endblock %}
      

      Save and close the file.

      Here you add an <a> tag to link to the edit() view function, passing in the post['id'] value to link to the edit page of each post with the Edit link.

      Deleting a Post

      Sometimes a post no longer needs to be publicly available, which is why the functionality of deleting a post is crucial. In this step you will add the delete functionality to your application.

      First, you’ll add a new /ID/delete route that accepts POST requests, similar to the edit() view function. Your new delete() view function will receive the ID of the post to be deleted from the URL. Open the app.py file:

      Add the following view function at the bottom of the file:

      flask_blog/app.py

      # ....
      
      @app.route('/<int:id>/delete', methods=('POST',))
      def delete(id):
          post = get_post(id)
          conn = get_db_connection()
          conn.execute('DELETE FROM posts WHERE id = ?', (id,))
          conn.commit()
          conn.close()
          flash('"{}" was successfully deleted!'.format(post['title']))
          return redirect(url_for('index'))
      

      This view function only accepts POST requests. This means that navigating to the /ID/delete route on your browser will return an error because web browsers default to GET requests.

      However you can access this route via a form that sends a POST request passing in the ID of the post you want to delete. The function will receive the ID value and use it to get the post from the database with the get_post() function.

      Then you open a database connection and execute a DELETE FROM SQL command to delete the post. You commit the change to the database and close the connection while flashing a message to inform the user that the post was successfully deleted and redirect them to the index page.

      Note that you don’t render a template file, this is because you’ll just add a Delete button to the edit page.

      Open the edit.html template file:

      Then add the following <form> tag after the <hr> tag and directly before the {% endblock %} line:

      flask_blog/templates/edit.html

      <hr>
      
      <form action="https://www.digitalocean.com/{{ url_for("delete', id=post['id']) }}" method="POST">
          <input type="submit" value="Delete Post"
                  class="btn btn-danger btn-sm"
                  onclick="return confirm('Are you sure you want to delete this post?')">
      </form>
      
      {% endblock %}
      

      You use the confirm() method to display a confirmation message before submitting the request.

      Now navigate again to the edit page of a blog post and try deleting it:

      http://127.0.0.1:5000/1/edit
      

      At the end of this step, the source code of your project will look like the code on this page.

      With this, the users of your application can now write new blog posts and add them to the database, edit, and delete existing posts.

      Conclusion

      This tutorial introduced essential concepts of the Flask Python framework. You learned how to make a small web application, run it in a development server, and allow the user to provide custom data via URL parameters and web forms. You also used the Jinja template engine to reuse HTML files and use logic in them. At the end of this tutorial, you now have a fully functioning web blog that interacts with an SQLite database to create, display, edit, and delete blog posts using the Python language and SQL queries.

      You can further develop this application by adding user authentication so that only registered users can create and modify blog posts, you may also add comments and tags for each blog post, and add file uploads to give users the ability to include images in the post. See the Flask documentation for more information.

      Flask has many community-made Flask extensions. The following is a list of extensions you might consider using to make your development process easier:

      • Flask-Login: manages the user session and handles logging in and logging out and remembering logged-in users.
      • Flask-SQLAlchemy: simplifies using Flask with SQLAlchemy, a Python SQL toolkit and Object Relational Mapper for interacting with SQL databases.
      • Flask-Mail: helps with the task of sending email messages in your Flask application.



      Source link

      Comment ajouter Sidekiq et Redis à une application Ruby on Rails


      Introduction

      Lors du développement d’une application Ruby on Rails, il se peut que certaines tâches d’application doivent être exécutées de manière asynchrone. Le traitement des données, l’envoi d’e-mails par lots ou l’interaction avec des API externes sont autant d’exemples de travaux qui peuvent être effectués de manière asynchrone avec des travaux en arrière-plan. L’utilisation de travaux en arrière-plan peut améliorer les performances de votre application en déchargeant des tâches potentiellement longues dans une file d’attente de traitement en arrière-plan, libérant ainsi le cycle original de requête/réponse.

      Sidekiq est l’un des frameworks de travail en arrière-plan les plus utilisés que vous pouvez implémenter dans une application Rails. Il est soutenu par Redis, un magasin clé-valeur en mémoire connu pour sa flexibilité et ses performances. Sidekiq utilise Redis comme un magasin de gestion de travaux pour traiter des milliers de travaux par seconde.

      Dans ce tutoriel, vous allez ajouter Redis et Sidekiq à une application Rails existante. Vous allez créer un ensemble de classes de travailleurs Sidekiq et de méthodes à manipuler :

      • Un téléchargement par lots d’informations sur les requins menacés dans la base de données de l’application à partir d’un fichier CSV dans le référentiel du projet.
      • La suppression de ces données.

      Lorsque vous aurez terminé, vous aurez une application de démonstration qui utilise les travailleurs et les travaux pour traiter les tâches de manière asynchrone. Ce sera une bonne base pour vous permettre d’ajouter des travailleurs et des travaux à votre propre application, en utilisant ce tutoriel comme point de départ.

      Conditions préalables

      Pour suivre ce tutoriel, vous aurez besoin de :

      Étape 1 – Clonage du projet et installation des dépendances

      Notre première étape consistera à cloner le référentiel rails-bootstrap à partir du compte GitHub de DigitalOcean Community. Ce référentiel comprend le code de la configuration décrite dans le tutoriel Comment ajouter Bootstrap à une application Ruby on Rails, qui explique comment ajouter Bootstrap à un projet Rails 5 existant.

      Clonez le référentiel dans un répertoire appelé rails-sidekiq :

      • git clone https://github.com/do-community/rails-bootstrap.git rails-sidekiq

      Naviguez vers le répertoire rails-sidekiq :

      Pour travailler avec le code, vous devrez d’abord installer les dépendances du projet, qui sont listées dans son Gemfile. Vous devrez également ajouter le gem sidekiq au projet pour travailler avec Sidekiq et Redis.

      Ouvrez le Gemfile du projet pour le modifier en utilisant nano ou votre éditeur préféré :

      Ajoutez le gem n’importe où dans les dépendances principales du projet (au-dessus des dépendances de développement) :

      ~/rails-sidekiq/Gemfile

      . . .
      # Reduces boot times through caching; required in config/boot.rb
      gem 'bootsnap', '>= 1.1.0', require: false
      gem 'sidekiq', '~>6.0.0'
      
      group :development, :test do
      . . .
      

      Enregistrez et fermez le fichier lorsque vous avez terminé d’ajouter le gem.

      Utilisez la commande suivante pour installer les gems :

      Vous verrez dans la sortie que le gem redis est également installé, cela étant exigé pour sidekiq.

      Ensuite, vous allez installer vos dépendances Yarn. Étant donné que ce projet Rails 5 a été modifié pour servir des ressources avec webpack, ses dépendances JavaScript sont maintenant gérées par Yarn. Cela signifie qu’il est nécessaire d’installer et de vérifier les dépendances listées dans le fichier package.json.

      Exécutez yarn install pour installer ces dépendances :

      Ensuite, exécutez vos migrations de base de données :

      Une fois vos migrations terminées, vous pouvez tester l’application pour vous assurer qu’elle fonctionne comme prévu. Démarrez votre serveur dans le contexte de votre bundle local avec la commande suivante si vous travaillez localement :

      Si vous travaillez sur un serveur de développement, vous pouvez démarrer l’application avec :

      • bundle exec rails s --binding=your_server_ip

      Naviguez vers localhost:3000 ou http://your_server_ip:3000. Vous verrez la page d’accueil suivante :

      Page d'accueil de l'application

      Pour créer un requin, cliquez sur le bouton Get Shark Info (Obtenir des informations sur les requins), qui vous amènera à la route sharks/index :

      Route sharks/index

      Pour vérifier que l’application fonctionne, nous pouvons y ajouter quelques informations de démonstration. Cliquez sur New Shark (Nouveau Requin). Un nom d’utilisateur (sammy) et un mot de passe (shark) vous seront demandés, grâce aux paramètres d’authentification du projet.

      Dans la page New Shark (Nouveau Requin), entrez « Great White » (Grand Blanc) dans le champ Name (Nom) et « Scary » (Effrayant) dans le champ Facts (Faits) :

      Créer un requin

      Cliquez sur le bouton Create Shark (Créer le requin) pour créer le requin. Une fois que vous voyez que votre requin a été créé, vous pouvez tuer le serveur avec CTRL+C.

      Vous avez désormais installé les dépendances nécessaires pour votre projet et testé sa fonctionnalité. Ensuite, vous pouvez apporter quelques modifications à l’application Rails pour travailler avec vos ressources concernant les requins menacés.

      Étape 2 – Génération d’un contrôleur pour les ressources concernant les requins menacés

      Pour travailler avec nos ressources sur les requins menacés, nous allons ajouter un nouveau modèle à l’application ainsi qu’un contrôleur qui contrôlera la manière dont les informations sur les requins menacés sont présentées aux utilisateurs. Notre objectif ultime est de permettre aux utilisateurs de télécharger vers le serveur un grand nombre d’informations sur les requins menacés sans bloquer la fonctionnalité générale de notre application, et de supprimer ces informations lorsqu’ils n’en ont plus besoin.

      D’abord, créons un modèle Endangered (Menacés) pour nos requins menacés. Nous allons inclure un champ de chaîne dans notre table de base de données pour le nom du requin, et un autre champ de chaîne pour les catégories de l’Union internationale pour la conservation de la nature (UICN) qui déterminent le degré de risque pour chaque requin.

      En fin de compte, la structure de notre modèle correspondra aux colonnes du fichier CSV que nous utiliserons pour créer notre téléchargement par lots. Ce fichier est situé dans le répertoire db, et vous pouvez vérifier son contenu avec la commande suivante :

      Le fichier contient une liste de 73 requins en voie de disparition et leurs statuts : vu pour vulnérables, en pour menacés et cr pour en voie de disparition.

      Notre modèle Endangered sera en corrélation avec ces données, ce qui nous permettra de créer de nouvelles instances Endangered à partir de ce fichier CSV. Créez le modèle avec la commande suivante :

      • rails generate model Endangered name:string iucn:string

      Ensuite, générez un contrôleur Endangered avec une action index :

      • rails generate controller endangered index

      Cela nous donnera un point de départ pour développer les fonctionnalités de notre application, mais nous devrons également ajouter des méthodes personnalisées au fichier de contrôleur que Rails a généré pour nous.

      Maintenant, ouvrez ce fichier :

      • nano app/controllers/endangered_controller.rb

      Rails nous a fourni un schéma de base que nous pouvons commencer à remplir.

      Tout d’abord, nous devons déterminer les routes nécessaires pour travailler avec nos données. Grâce à la commande generate controller, nous disposons d’une méthode index pour commencer. Cela correspondra à une vue index, où nous présenterons aux utilisateurs la possibilité de télécharger vers le serveur des requins menacés.

      Toutefois, nous voudrons également traiter les cas où les utilisateurs ont déjà téléchargé les requins et n’ont donc pas besoin d’une option de téléchargement. Nous devrons d’une manière ou d’une autre évaluer combien d’instances de la classe Endangered existent déjà, puisque plus d’une instance indique que le téléchargement par lots a déjà eu lieu.

      Commençons par créer une méthode set_endangered private qui récupérera chaque instance de notre classe Endangered dans la base de données. Ajoutez le code suivant au fichier :

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      class EndangeredController < ApplicationController
        before_action :set_endangered, only: [:index, :data]
      
        def index
        end
      
        private
      
          def set_endangered
            @endangered = Endangered.all
          end
      
      end
      

      Notez que le filtre before_action fera en sorte que la valeur de @endangered ne soit définie que pour les routes index et data, qui seront les endroits où nous traiterons les données sur les requins menacés.

      Ensuite, ajoutez le code suivant à la méthode index afin de déterminer le chemin correct pour les utilisateurs qui visitent cette partie de l’application :

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      class EndangeredController < ApplicationController
        before_action :set_endangered, only: [:index, :data]
      
        def index          
          if @endangered.length > 0
            redirect_to endangered_data_path
          else
            render 'index'
          end
        end
      . . .
      

      S’il y a plus de 0 instance de notre classe Endangered, nous redirigerons les utilisateurs vers la route data, où ils pourront consulter des informations sur les requins qu’ils ont créés. Sinon, ils verront la vue index.

      Ensuite, sous la méthode index, ajoutez une méthode data, qui correspondra à une vue data :

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      . . .
        def index          
          if @endangered.length > 0
            redirect_to endangered_data_path
          else
            render 'index'
          end
        end
      
        def data
        end
      . . .
      

      Ensuite, nous ajouterons une méthode pour gérer le téléchargement des données lui-même. Nous appellerons cette méthode upload, et elle fera appel à une classe de travailleurs Sidekiq et à une méthode pour effectuer le téléchargement des données à partir du fichier CSV. Nous allons créer la définition de cette classe de travailleurs, AddEndangeredWorker, dans la prochaine étape.

      Pour l’instant, ajoutez le code suivant au fichier pour appeler le travailleur Sidekiq afin d’effectuer le téléchargement :

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      . . .
        def data
        end
      
        def upload
          csv_file = File.join Rails.root, 'db', 'sharks.csv'   
          AddEndangeredWorker.perform_async(csv_file)
          redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!'
        end
      . . .
      

      En appelant la méthode perform_async sur la classe AddEndangeredWorker et en utilisant le fichier CSV comme argument, ce code garantit que les données du requin et le travail de téléchargement sont transmis à Redis. Les travailleurs de Sidekiq que nous mettrons en place surveilleront la file d’attente des travaux et réagiront lorsque de nouveaux travaux se présenteront.

      Après avoir appelé perform_async, notre méthode upload redirige vers le chemin data, où les utilisateurs pourront voir les requins téléchargés.

      Ensuite, nous ajouterons une méthode destroy pour détruire les données. Ajoutez le code suivant sous la méthode upload :

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      . . .
        def upload
          csv_file = File.join Rails.root, 'db', 'sharks.csv'   
          AddEndangeredWorker.perform_async(csv_file)
          redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!'
        end
      
        def destroy
          RemoveEndangeredWorker.perform_async
          redirect_to root_path
        end
      . . .
      

      Comme notre méthode upload, notre méthode destroy comprend un appel à perform_async sur une classe RemoveEndangeredWorker – l’autre travailleur Sidekiq que nous allons créer. Après avoir appelé cette méthode, elle redirige les utilisateurs vers le chemin root de l’application.

      Le fichier terminé ressemblera à ceci :

      ~/rails-sidekiq/app/controllers/endangered_controller.rb

      class EndangeredController < ApplicationController
        before_action :set_endangered, only: [:index, :data]
      
        def index          
          if @endangered.length > 0
            redirect_to endangered_data_path
          else
            render 'index'
          end
        end
      
        def data
        end
      
        def upload
          csv_file = File.join Rails.root, 'db', 'sharks.csv'   
          AddEndangeredWorker.perform_async(csv_file)
          redirect_to endangered_data_path, notice: 'Endangered sharks have been uploaded!'
        end
      
        def destroy
          RemoveEndangeredWorker.perform_async
          redirect_to root_path
        end
      
        private
      
          def set_endangered
            @endangered = Endangered.all
          end
      
      end
      

      Enregistrez et fermez le fichier lorsque vous avez terminé de le modifier.

      Pour terminer la consolidation des routes de notre application, nous allons modifier le code dans config/routes.rb, le fichier où se trouvent nos déclarations de routes.

      Maintenant, ouvrez ce fichier :

      Actuellement, le fichier ressemble à ceci :

      ~/rails-sidekiq/config/routes.rb

      Rails.application.routes.draw do
        get 'endangered/index'
        get 'home/index'
        resources :sharks do
                resources :posts
        end
        root 'home#index'
        # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
      end
      

      Nous devrons mettre à jour le fichier pour inclure les routes que nous avons définies dans notre contrôleur : data, upload et destroy. Notre route data correspondra à une requête GET pour récupérer les données sur les requins, tandis que nos itinéraires upload et destroy redirigeront vers des requêtes POST qui téléchargeront et détruiront ces données.

      Ajoutez le code suivant au fichier pour définir ces routes :

      ~/rails-sidekiq/config/routes.rb

      Rails.application.routes.draw do
        get 'endangered/index'
        get 'endangered/data', to: 'endangered#data'
        post 'endangered/upload', to: 'endangered#upload'
        post 'endangered/destroy', to: 'endangered#destroy'
        get 'home/index'
        resources :sharks do
                resources :posts
        end
        root 'home#index'
        # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
      end
      

      Enregistrez et fermez le fichier lorsque vous avez terminé de le modifier.

      Maintenant que vous avez mis en place votre modèle Endangered et votre contrôleur, vous pouvez passer à l’étape de définition des classes de travailleurs Sidekiq.

      Étape 3 – Définition des travailleurs Sidekiq

      Nous avons appelé des méthodes perform_async sur nos travailleurs Sidekiq dans notre contrôleur, mais nous devons encore créer les travailleurs eux-mêmes.

      Tout d’abord, créez un répertoire workers pour les travailleurs :

      Ouvrez un fichier pour le travailleur AddEndangeredWorker :

      • nano app/workers/add_endangered_worker.rb

      Dans ce fichier, nous ajouterons un code qui nous permettra de travailler avec les données dans notre fichier CSV. Premièrement, ajoutez du code au fichier qui créera la classe, incluez la bibliothèque CSV Ruby et assurez-vous que cette classe fonctionne comme un travailleur Sidekiq :

      ~/rails-sidekiq/app/workers/add_endangered_worker.rb

      class AddEndangeredWorker
        require 'csv'
        include Sidekiq::Worker
        sidekiq_options retry: false
      
      end
      

      Nous incluons également l’option retry: false pour nous assurer que Sidekiq ne réessaie pas de relancer le téléchargement si celui-ci échoue.

      Ensuite, ajoutez le code pour la fonction perform :

      ~/rails-sidekiq/app/workers/add_endangered_worker.rb

      class AddEndangeredWorker
        require 'csv'
        include Sidekiq::Worker
        sidekiq_options retry: false
      
        def perform(csv_file)
          CSV.foreach(csv_file, headers: true) do |shark|
          Endangered.create(name: shark[0], iucn: shark[1])
        end
       end
      
      end
      

      La méthode perform reçoit des arguments de la méthode perform_async définie dans le contrôleur, il est donc important que les valeurs d’argument correspondent. Ici, nous transmettons csv_file, la variable que nous avons définie dans le contrôleur, et nous utilisons la méthode foreach à partir de la bibliothèque CSV pour lire les valeurs dans le fichier. Définir headers:true pour cette boucle vous garantit que la première ligne du fichier sera traitée comme une ligne d’en-têtes.

      Le bloc lit ensuite les valeurs du fichier dans les colonnes que nous avons définies pour notre modèle Endangered : name et iucn. Exécuter cette boucle créera des instances Endangered pour chacune des entrées dans notre fichier CSV.

      Une fois que vous avez terminé de le modifier, enregistrez et fermez le fichier.

      Ensuite, nous allons créer un travailleur pour gérer la suppression de ces données. Ouvrez un fichier pour la classe RemoveEndangeredWorker :

      • nano app/workers/remove_endangered_worker.rb

      Ajoutez le code pour définir la classe, et pour vous assurer qu’il utilise la bibliothèque CSV et fonctionne comme un travailler Sidekiq :

      ~/rails-sidekiq/app/workers/remove_endangered_worker.rb

      class RemoveEndangeredWorker
        include Sidekiq::Worker
        sidekiq_options retry: false
      
      end
      

      Ensuite, ajoutez une méthode perform pour gérer la destruction des données sur les requins menacés :

      ~/rails-sidekiq/app/workers/remove_endangered_worker.rb

      class RemoveEndangeredWorker
        include Sidekiq::Worker
        sidekiq_options retry: false
      
        def perform
          Endangered.destroy_all
        end
      
      end
      

      La méthode perform appelle destroy_all sur la classe Endangered, elle supprimera toutes les instances de cette classe de la base de données.

      Enregistrez et fermez le fichier lorsque vous avez terminé de le modifier.

      Une fois vos travailleurs en place, vous pouvez passer à la création d’une mise en page pour vos vues endangered, et de modèles pour vos vues index et data, afin que les utilisateurs puissent télécharger et visualiser les requins menacés.

      Étape 4 – Ajout de mises en page et de modèles de vues

      Pour que les utilisateurs puissent profiter de leurs informations sur les requins menacés, nous devrons nous occuper de deux choses : la présentation des vues définies dans notre contrôleur endangered, et les modèles de vue pour les vues index et data.

      Actuellement, notre application utilise une mise en page pour l’ensemble de l’application, située à l’adresse app/views/layouts/application.html.erb, un fichier partiel pour la navigation et une mise en page pour les vues sharks. La mise en page de l’application vérifie la présence d’un bloc de contenu, ce qui nous permet de charger différentes mises en page en fonction de la partie de l’application à laquelle notre utilisateur s’intéresse : pour la page home index, il verra une mise en page, et pour toute vue relative à un requin en particulier, il en verra une autre.

      Nous pouvons réadapter la mise en page sharks à nos vues endangered, car ce format permettra également de présenter les données sur les requins en vrac.

      Copiez le fichier de configuration sharks pour créer une mise en page endangered :

      • cp app/views/layouts/sharks.html.erb app/views/layouts/endangered.html.erb

      Ensuite, nous allons travailler à créer les modèles de vue pour nos vues index et data.

      Ouvrez le modèle index en premier :

      • nano app/views/endangered/index.html.erb

      Supprimez le code standard et ajoutez à la place le code suivant, qui donnera aux utilisateurs des informations générales sur les catégories menacées et leur offrira la possibilité de télécharger des informations sur les requins menacés :

      ~/rails-sidekiq/app/views/endangered/index.html.erb

      <p id="notice"><%= notice %></p>
      
      <h1>Endangered Sharks</h1>
      
      <p>International Union for Conservation of Nature (ICUN) statuses: <b>vu:</b> Vulnerable, <b>en:</b> Endangered, <b>cr:</b> Critically Endangered </p>
      
      <br>
      
        <%= form_tag endangered_upload_path do %>
        <%= submit_tag "Import Endangered Sharks" %>
        <% end %>
      
        <br>
      
      <%= link_to 'New Shark', new_shark_path, :class => "btn btn-primary btn-sm" %> <%= link_to 'Home', home_index_path, :class => "btn btn-primary btn-sm" %>
      

      Un form_tag rend possible le téléchargement de données en pointant une action post sur endangered_upload_path – la route que nous avons définie pour nos téléchargements. Un bouton créé avec submit_tag invite les utilisateurs à "Import Endangered Sharks" (Importer les requins menacés).

      En plus de ce code, nous avons inclus quelques informations générales sur les codes ICUN, afin que les utilisateurs puissent interpréter les données qu’ils verront.

      Enregistrez et fermez le fichier lorsque vous avez terminé de le modifier.

      Ensuite, ouvrez un fichier pour la vue data :

      • nano app/views/endangered/data.html.erb

      Ajoutez le code suivant, qui ajoutera un tableau avec les données sur les requins menacés :

      ~/rails-sidekiq/app/views/endangered/data.html.erb

      <p id="notice"><%= notice %></p>
      
      <h1>Endangered Sharks</h1>
      
      <p>International Union for Conservation of Nature (ICUN) statuses: <b>vu:</b> Vulnerable, <b>en:</b> Endangered, <b>cr:</b> Critically Endangered </p>
      
      <div class="table-responsive">
      <table class="table table-striped table-dark">
        <thead>
          <tr>
            <th>Name</th>
            <th>IUCN Status</th>
            <th colspan="3"></th>
          </tr>
        </thead>
      
        <tbody>
          <% @endangered.each do |shark| %>
            <tr>
              <td><%= shark.name %></td>
              <td><%= shark.iucn %></td>
            </tr>
          <% end %>
        </tbody>
      </table>
      </div>
      
      <br>
      
        <%= form_tag endangered_destroy_path do %>
        <%= submit_tag "Delete Endangered Sharks" %>
        <% end %>
      
        <br>
      
      <%= link_to 'New Shark', new_shark_path, :class => "btn btn-primary btn-sm" %> <%= link_to 'Home', home_index_path, :class => "btn btn-primary btn-sm" %>
      

      Ce code comprend les codes de statut ICUN, une fois de plus, et un tableau Bootstrap pour les données produites. En bouclant notre variable @endangered, nous affichons le nom et le statut ICUN de chaque requin dans le tableau.

      Sous le tableau, nous avons un autre ensemble de form_tags et de submit_tags, qui s’affichent sur le chemin destroy en offrant aux utilisateurs la possibilité de "Delete Endangered Sharks" (Supprimer les requins menacés).

      Enregistrez et fermez le fichier lorsque vous avez terminé de le modifier.

      La dernière modification que nous apporterons à nos vues sera dans la vue index associée à notre contrôleur home. Vous vous souvenez peut-être que cette vue est définie comme la racine de l’application dans le fichier config/routes.rb.

      Ouvrez ce fichier pour le modifier :

      • nano app/views/home/index.html.erb

      Trouvez la colonne dans la ligne qui indique Sharks are ancient (les requins sont anciens) :

      ~/rails-sidekiq/app/views/home/index.html.erb

      . . .
              <div class="col-lg-6">
                  <h3>Sharks are ancient</h3>
                  <p>There is evidence to suggest that sharks lived up to 400 million years ago.
                  </p>
              </div>
          </div>
      </div>
      

      Ajoutez le code suivant au fichier :

      ~/rails-sidekiq/app/views/home/index.html.erb

      . . .
              <div class="col-lg-6">
                  <h3>Sharks are ancient and SOME are in danger</h3>
                  <p>There is evidence to suggest that sharks lived up to 400 million years ago. Without our help, some could disappear soon.</p>
                  <p><%= button_to 'Which Sharks Are in Danger?', endangered_index_path, :method => :get,  :class => "btn btn-primary btn-sm"%>
                  </p>
              </div>
          </div>
      </div>
      

      Nous avons inclus un appel à l’action pour que les utilisateurs en apprennent davantage sur les requins menacés, en partageant d’abord un message fort, puis en ajoutant un assistant button_to qui soumet une requête GET à notre route endangered index, donnant aux utilisateurs l’accès à cette partie de l’application. À partir de là, ils pourront télécharger et visualiser les informations sur les requins menacés.

      Enregistrez et fermez le fichier lorsque vous avez terminé de le modifier.

      Avec votre code en place, vous êtes prêt à démarrer l’application et à télécharger quelques requins vers le serveur !

      Étape 5 – Démarrage de Sidekiq et test de l’application

      Avant de démarrer l’application, nous devrons gérer les migrations sur notre base de données et démarrer Sidekiq pour activer nos travailleurs. Redis devrait déjà être en marche sur le serveur, mais nous pouvons vérifier pour en être sûr. Avec tout cela, nous serons prêts à tester l’application.

      D’abord, vérifiez que Redis fonctionne :

      Vous devriez voir une sortie similaire à la suivante :

      Output

      ● redis-server.service - Advanced key-value store Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2019-11-12 20:37:13 UTC; 1 weeks 0 days ago

      Ensuite, exécutez vos migrations de base de données :

      Vous pouvez maintenant démarrer Sidekiq dans le contexte de notre bundle de projet actuel en utilisant la commande bundle exec sidekiq :

      Vous verrez une sortie comme ceci, vous indiquant que Sidekiq est prêt à traiter les travaux :

      Output

      m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$b/md$$$P^' .d$$$$$$/$$$P' $$^' `"/$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ ___ | |/ _` |/ _ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|__,_|___|_|__|__, | .d$$ |_| 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Running in ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux] 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: See LICENSE and the LGPL-3.0 for licensing details. 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org 2019-11-19T21:43:00.540Z pid=17621 tid=gpiqiesdl INFO: Booting Sidekiq 6.0.3 with redis options {:id=>"Sidekiq-server-PID-17621", :url=>nil} 2019-11-19T21:43:00.543Z pid=17621 tid=gpiqiesdl INFO: Starting processing, hit Ctrl-C to stop

      Ouvrez une deuxième fenêtre de terminal, naviguez vers le répertoire rails-sidekiq, et démarrez votre serveur d’application.

      Si vous exécutez l’application localement, utilisez la commande suivante :

      Si vous travaillez avec un serveur de développement, exécutez ce qui suit :

      • bundle exec rails s --binding=your_server_ip

      Naviguez vers localhost:3000 ou http://your_server_ip:3000 dans le navigateur. Vous verrez la page d’accueil suivante :

      Accueil Sidekiq App

      Cliquez sur le bouton Which Sharks Are in Danger?​​​​​​ (Quels sont les requins menacés ?) . Comme vous n’avez pas téléchargé de requin menacé, cela vous amènera à la vue endangered index :

      Vue Endangered Index

      Cliquez sur Import Endangered Sharks​​​ (​​Importer des requins menacés) pour importer les requins. Vous verrez un message vous indiquant que les requins ont été importés :

      Commencer l'importation

      Vous verrez également le début de l’importation. Rafraîchissez votre page pour voir le tableau complet :

      Rafraîchir le tableau

      Grâce à Sidekiq, notre important téléchargement par lots de requins menacés a réussi sans verrouiller le navigateur ni interférer avec les autres fonctionnalités de l’application.

      Cliquez sur le bouton Home (Accueil) en bas de la page, ce qui vous ramènera à la page principale de l’application :

      Accueil Sidekiq App

      De là, cliquez à nouveau sur Which Sharks Are in Danger? . Cela vous amènera maintenant directement à la vue data, puisque vous avez déjà téléchargé les requins.

      Pour tester la fonctionnalité de suppression, cliquez sur le bouton Delete Endangered Sharks (Supprimer les requins menacés) sous le tableau. Vous devriez être redirigé vers la page d’accueil de l’application une fois encore. Cliquez sur Which Sharks Are in Danger?​​​​​ une dernière fois vous renverra à la vue index, où vous aurez la possibilité de télécharger à nouveau des requins :

      Vue Endangered Index

      Votre application fonctionne maintenant avec les travailleurs Sidekiq en place, qui sont prêts à traiter les travaux et à s’assurer que les utilisateurs ont une bonne expérience en travaillant avec votre application.

      Conclusion

      Vous disposez désormais d’une application Rails fonctionnelle avec Sidekiq activé, ce qui vous permettra de décharger des opérations coûteuses dans une file d’attente de travail gérée par Sidekiq et soutenue par Redis. Cela vous permettra d’améliorer la vitesse et la fonctionnalité de votre site au fur et à mesure de son développement.

      Si vous souhaitez en savoir plus sur Sidekiq, les documents sont un bon point de départ.

      Pour en savoir plus sur Redis, consultez notre bibliothèque de ressources Redis. Vous pouvez également en savoir plus sur le fonctionnement d’un cluster Redis géré sur DigitalOcean en consultant la documentation du produit.



      Source link

      Comment créer une application de citations en utilisant AdonisJs et MySQL


      L’auteur a choisi le Tech Education Fund pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      AdonisJs est un framework Web Node.js écrit en JavaScript qui fonctionne avec tous les principaux systèmes d’exploitation. Il utilise le célèbre modèle de conception MVC (Model – View – Controller) et offre un écosystème stable pour l’écriture d’applications Web côté serveur. Le framework comprend une authentification transparente, un mapping objet-relationnel (ORM) SQL, des migrations et l’ensemencement de bases de données. AdonisJs a une architecture similaire à celle du framework d’application Web PHP Laravel, dont la même structure de dossiers et plusieurs concepts de configuration partagée.

      Par défaut, AdonisJs utilise le moteur de modèles Edge qui est conçu pour une utilisation intuitive. Tout comme Laravel, AdonisJs est équipé d’un ORM appelé Lucid qui sert d’interface pour la communication entre les modèles d’une application et la base de données. Avec AdonisJs, les développeurs peuvent créer une application complète où le serveur back-end sera responsable de l’application de la logique du système, du routage et du rendu de toutes les pages de l’application. Il est également possible de créer une API de service Web pour renvoyer les réponses JSON d’un contrôleur ; ces services Web peuvent alors être consommés à l’aide de frameworks front-end tels que Vue.js, React et Angular.

      Dans ce tutoriel, vous allez construire une application avec AdonisJs en utilisant son interface en ligne de commande (CLI). Vous créerez des routes, des contrôleurs, des modèles et des vues dans votre application, et vous effectuerez des validations de formulaires. L’exemple présenté dans ce tutoriel sera une application de citations dans laquelle un utilisateur peut s’inscrire et se connecter pour créer une citation. Cette application de démonstration vous donnera la possibilité d’effectuer des opérations CRUD (Create, Read, Update, Delete).

      Conditions préalables

      Avant de commencer ce guide, vous aurez besoin de ce qui suit :

      Remarque : ce tutoriel utilise une machine macOS pour le développement. Si vous utilisez un autre système d’exploitation, vous devrez peut-être utiliser sudo pour les commandes npm lors des premières étapes.

      Étape 1 – Installation de la CLI Adonis

      Dans cette section, vous installerez la CLI Adonis et tous ses packages requis sur votre machine locale. La CLI vous permettra d’échafauder un nouveau projet AdonisJs, ainsi que de créer et de générer des codes standards pour les contrôleurs, les middlewares et les modèles de votre application. Vous créerez également votre base de données pour le projet.

      Exécutez la commande suivante pour installer la CLI AdonisJs globalement sur votre machine via npm :

      Une fois le processus d’installation terminé, tapez la commande suivante dans le terminal pour confirmer l’installation d’AdonisJs et visualiser la version actuelle :

      Vous verrez une sortie montrant la version actuelle d’AdonisJs :

      Output

      4.1.0

      En ayant installé la CLI AdonisJs, vous avez maintenant accès à la commande adonis et vous pouvez l’utiliser pour créer de nouvelles installations d’un projet AdonisJs, gérer votre projet et générer des fichiers pertinents tels que les contrôleurs, les modèles, etc.

      Maintenant, vous pouvez créer un nouveau projet AdonisJs en utilisant la commande adonis comme indiqué ici :

      • adonis new adonis-quotes-app

      La commande précédente va créer une application nommée adonis-quotes-app dans un nouveau répertoire portant le même nom dans votre répertoire de projet local, avec la structure MVC AdonisJs correspondante.

      Entrez dans le nouveau dossier d’application :

      Lancez ensuite votre application en exécutant :

      Cela démarrera le serveur de développement sur le port par défaut 3333 comme spécifié dans le fichier root .env de votre application. Naviguez jusqu’à http://localhost:3333 pour visualiser la page d’accueil d’AdonisJs.

      Page d'accueil d'AdonisJs

      Vous allez maintenant terminer la configuration de votre base de données. Ici, vous allez installer le pilote mysql pour vous connecter à votre serveur MySQL depuis votre application Node.js via npm. Pour commencer, retournez à votre terminal où l’application est en cours d’exécution, arrêtez le processus avec CTRL + C et exécutez la commande suivante :

      Maintenant que vous avez installé avec succès le pilote MySQL Node.js pour cette application, vous devez créer la base de données de l’application et établir la connexion appropriée à celle-ci.

      La dernière version de MySQL que vous avez installée à partir du tutoriel indiqué dans les conditions préalables utilise un plugin d’authentification par défaut nommé caching_sha2_password. Il n’est actuellement pas pris en charge par les pilotes Node.js pour MySQL. Pour éviter tout problème de connexion à la base de données depuis votre application, vous devrez créer un nouvel utilisateur MySQL et utiliser le plugin d’authentification actuellement pris en charge-mysql_native_password.

      Pour commencer, accédez au client MySQL en utilisant le compte root :

      Vous serez invité à saisir le mot de passe de votre compte root configuré lors de l’installation de MySQL.

      Ensuite, créez l’utilisateur et le mot de passe en utilisant le plugin mysql_native_password :

      • CREATE USER 'sammy'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';

      Vous verrez la sortie suivante :

      Output

      Query OK, 0 rows affected (0.02 sec)

      Ensuite, créez une base de données pour l’application avec :

      Vous verrez la sortie suivante :

      Output

      Query OK, 1 row affected (0.03 sec)

      Vous avez correctement créé la base de données pour cette application.

      Maintenant, activez l’accès à la base de données créée pour le nouvel utilisateur de MySQL. Exécutez la commande suivante pour accorder tous les privilèges à l’utilisateur dans la base de données :

      • GRANT ALL PRIVILEGES ON adonis.* TO 'sammy'@'localhost';

      Rechargez les tables de privilèges en exécutant la commande suivante pour appliquer les modifications que vous venez d’apporter :

      Vous verrez la sortie suivante :

      Output

      Query OK, 0 rows affected (0.00 sec)

      Quittez le client MySQL avec :

      Vous avez installé la CLI AdonisJs, créé un nouveau projet AdonisJs et installé mysql via npm. Vous avez également créé la base de données pour cette application et configuré un utilisateur MySQL avec les privilèges appropriés. C’est la configuration de base de votre application. Dans la section suivante, vous commencerez à créer les vues nécessaires pour votre application.

      Étape 2 – Utilisation du moteur de modèles Edge

      AdonisJs est livré avec son propre moteur de modèles appelé Edge. Il vous permet de créer un modèle HTML réutilisable et permet l’introduction d’une logique front-end dans votre application avec un minimum de code. Edge fournit aux développeurs JavaScript les outils nécessaires, lors du développement d’une application, pour construire une mise en page basée sur des composants, écrire des conditions, utiliser des itérations et créer des couches d’affichage pour maintenir la logique. Tous les fichiers modèles se terminent par l’extension .edge et sont stockés dans le répertoire resources/views.

      Voici les vues dont votre application aura besoin pour fonctionner correctement :

      • Master Layout : avec Edge, vous pouvez créer une page qui contiendra le CSS, les fichiers JavaScript communs, jQuery et les parties communes de l’interface utilisateur qui resteront les mêmes dans toute l’application (la barre de navigation, le logo, l’en-tête, etc.). Une fois que vous avez établi la mise en page master, les autres vues (pages) de votre application en hériteront.
      • Index view : cette page utilisera la mise en page master pour donner des fichiers communs et rendra également le contenu de la page d’accueil de l’application.
      • Login page : cette page utilisera également la mise en page master et affichera le formulaire avec les champs de saisie du nom d’utilisateur et du mot de passe, afin que les utilisateurs puissent se passe,
      • Register page : ici, les utilisateurs verront un formulaire d’inscription et leurs coordonnées seront enregistrées dans la base de données.
      • Create quote page : les utilisateurs utiliseront cette page pour créer une citation.
      • Edit quote page : les utilisateurs utiliseront cette page pour modifier une citation.
      • View quote page : les utilisateurs utiliseront cette page pour afficher une citation particulière.

      Pour commencer, utilisez la commande adonis pour créer la mise en page master en exécutant la commande suivante :

      • adonis make:view layouts/master

      Vous verrez une sortie semblable à ce qui suit :

      Output

      ✔ create resources/views/layouts/master.edge

      Cette commande créera automatiquement un fichier master.edge dans votre dossier resources/views/layouts. Ouvrez le nouveau fichier :

      • nano resources/views/layouts/master.edge

      Ajoutez le code suivant dans le fichier :

      /resources/views/layouts/master.edge

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <title>adonis-quotes-app</title>
          {{ style('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css') }}
          {{ style('style') }}
          {{ script('https://code.jquery.com/jquery-3.3.1.slim.min.js') }}
      </head>
      <body>
          <div class="container-fliud">
              @include('navbar')
              @!section('content')
          </div>
          {{ script('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js') }}
      
      </body>
      </html>
      

      Dans ce fichier, vous incluez les fichiers CDN pour Bootstrap CSS, Bootstrap JavaScript et jQuery. Vous ajoutez un nom de fichier CSS global de style.css et dans la div vous incluez un fichier partiel nommé navbar. Pour réutiliser des fragments de code HTML dont vous avez besoin sur plusieurs pages de votre application, comme nav ou footer, vous pouvez incorporer des fichiers partiels. Il s’agit de petits fichiers contenant le code répété, ce qui permet de mettre à jour plus rapidement le code de ces éléments en un seul endroit plutôt qu’à chaque fois que le code apparaît. La navbar contient des balises pour les boutons Login et Register, un logo et un lien vers l’accueil.

      Grâce à cela, toutes les pages qui seront créées ensuite pour cette application peuvent utiliser la mise en page master et faire apparaître la navbar sans qu’il soit nécessaire de réécrire le contenu. Vous créerez le fichier navbar plus tard dans le tutoriel.

      Enfin, vous définissez une balise de section @! section() pour inclure le contenu d’autres pages et les afficher dans la mise en page master. Pour que cela fonctionne comme prévu, toutes les nouvelles pages qui utiliseront la mise en page master doivent également définir une balise de section portant le même nom (c’est-à-dire @section('content')).

      Sauvegardez et quittez le fichier une fois que vous avez terminé de le modifier.

      Ensuite, vous utiliserez la commande adonis pour créer la barre de navigation :

      Vous verrez une sortie semblable à :

      Output

      ✔ create resources/views/navbar.edge

      Ouvrez le fichier qui vient d’être créé :

      • nano resources/views/navbar.edge

      Ensuite, ajoutez-y le code suivant :

      /resources/views/navbar.edge

      <nav class="navbar navbar-expand-lg navbar-dark text-white">
          <a class="navbar-brand" >LOGO</a>
          <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
              <span class="navbar-toggler-icon"></span>
          </button>
      
          <div class="collapse navbar-collapse" id="navbarNav">
              <ul class="navbar-nav">
                  <li class="nav-item active ">
                      <a class="btn text-white" href="https://www.digitalocean.com/">Home</a>
                  </li>
              </ul>
          </div>
          <div class="navbar-right" id="navbarNav">
              @loggedIn
                  <ul class="navbar-nav">
                          <li>
                              <div class="text-right">
                                   <a href="{{route('create.quote')}}" class="btn btn-outline-primary">Create Quote</a>
                              </div>
                          </li>
      
                      <li class="nav-item dropdown">
                          <a class="nav-link dropdown-toggle" href="https://www.digitalocean.com/#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                             {{ auth.user.username}}
                          </a>
                          <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
                              <form method="POST" action="{{route('logout')}}">
                                  {{ csrfField() }}
                                    <button  type="submit" class="dropdown-item" href="">logout</button>
                              </form>
                          </div>
                      </li>
                  </ul>
              @else
                  <ul class="navbar-nav">
                      <li class="nav-item active pr-2">
                          <a href="{{route('login.create')}}" class="btn btn-outline-danger">
                            login
                          </a>
                      </li>
                      <li class="nav-item active pr-2">
                          <a href="{{route('register.create')}}" class="btn btn-outline-primary">
                              Register
                          </a>
                      </li>
                  </ul>
              @endloggedIn
          </div>
      </nav>
      

      En plus de définir les liens vers la page d’accueil et un bouton pour s’inscrire et se connecter, vous ajoutez une balise @loggedIn. Grâce à cela, vous pouvez rédiger une instruction conditionnelle selon l’utilisateur authentifié et afficher le contenu approprié. Pour un utilisateur authentifié, l’application affichera son nom d’utilisateur et un bouton pour créer une nouvelle citation. Si un utilisateur n’est pas connecté, votre application affichera un bouton pour se connecter ou s’enregistrer. Cette page sera incluse en tant que fichier partiel de chaque page, comme elle l’était auparavant dans la mise en page master de cette application.

      Enregistrez et quittez le fichier.

      Maintenant, vous allez créer la page d’index que vous utiliserez pour la page d’accueil de l’application. Cet index rendra et affichera la liste de toutes les citations écrites par les utilisateurs :

      Vous verrez une sortie semblable à ce qui suit :

      Output

      ✔ create resources/views/index.edge

      Le fichier créé ici sera situé dans resources/views/index.edge. Ouvrez le fichier :

      • nano resources/views/index.edge

      Ensuite, ajoutez le code suivant :

      /resources/views/index.edge

      @layout('layouts/master')
      @section('content')
      
      <div class="container">
          <div class="text-center">
              @if(flashMessage('successmessage'))
                  <span class="alert alert-success p-1">{{ flashMessage('successmessage') }}</span>
              @endif
          </div>
          <div class="row">
              @each(quote in quotes)
                  <div class="col-md-4 mb-4 quote-wrapper">
                      <a href="https://www.digitalocean.com/view-quote/{{quote.id}}" class="w-100">
                          <div class="card shadow-lg bg-dark text-white">
                              <div class="card-body">
                                  <blockquote class="blockquote mb-0">
                                      <p>{{quote.body}}</p>
                                      <footer class="blockquote-footer">
                                          <cite title="Source Title"> {{quote.username}}</cite>
                                      </footer>
                                  </blockquote>
                                  @if(auth.user.id == quote.user_id)
                                    <div>
                                      <a  href="http://www.digitalocean.com/edit-quote/{{quote.id}}" class="btn btn-primary">edit</a>
                                      <a href="http://www.digitalocean.com/delete-quote/{{quote.id}}" class="btn btn-danger">delete</a>
                                    </div>
                                  @endif
                              </div>
                          </div>
                      </a>
                  </div>
              @else
               <div class="col-md-12 empty-quote text-center">
                      <p>No inspirational quote has been created</p>
               </div>
              @endeach
          </div>
      </div>
      @endsection
      

      Ici, vous indiquez que cette vue utilisera la mise en page master en l’étendant. Cette page peut maintenant avoir accès à la navbar et à toutes les bibliothèques et feuilles de style incluses dans la mise en page master. Ensuite, vous itérez sur une série de quotes (citations) en utilisant la balise @each intégrée. Le tableau quotes sera passé à cette vue à partir du QuoteController que vous créerez plus tard dans ce tutoriel. S’il n’y a pas de citations, un message approprié sera affiché.

      Enregistrez et quittez ce fichier.

      Maintenant, pour créer la page de connexion, exécutez la commande suivante depuis le terminal :

      • adonis make:view auth/login

      Vous verrez une sortie semblable à :

      Output

      ✔ create resources/views/auth/login.edge

      Cela créera automatiquement un dossier auth au sein de ressources/views et créera également un fichier login.edge à l’intérieur. Ouvrez le fichier login.edge :

      • nano resources/views/auth/login.edge

      Ajoutez le contenu suivant :

      /resources/views/auth/login.edge

      @layout('layouts/master')
      @section('content')
        <div class="container">
          <div class="row">
            <div class="col-md-4 shadow bg-white mt-5 rounded offset-md-4">
              <form method="POST" action="{{route('login.store')}}">
                {{ csrfField() }}
                  <div>
                    @if(flashMessage('successmessage'))
                      <span class="alert alert-success p-1">{{ flashMessage('successmessage') }}</span>
                    @endif
                  </div>
                  <div class="form-group">
                    <label for="email">Email address</label>
                    <input type="email" class="form-control" id="email" name="email" value="{{old('email','')}}"  placeholder="Enter email">
                    {{ elIf('<span class=text-danger>$self</span>', getErrorFor('email'), hasErrorFor('email')) }}
                  </div>
                  <div class="form-group">
                    <label for="pasword">Password</label>
                    <input type="password" class="form-control" id="password" name="password" value="{{old('password','')}}" placeholder="Password">
                    {{ elIf('<span class=text-danger>$self</span>', getErrorFor('password'), hasErrorFor('password')) }}
                  </div>
      
                  <div class="text-center">
                    <button type="submit" class="btn btn-primary">Submit</button>
                  </div>
              </form>
            </div>
          </div>
        </div>
      @endsection
      

      Ce fichier inclut un formulaire qui contient des éléments de saisie que vous utiliserez pour recueillir le nom d’utilisateur et le mot de passe d’un utilisateur enregistré afin qu’il puisse s’authentifier et commencer à créer des citations. La variable {{ csrfField() }} est un autre des éléments importants à noter sur cette page. Il s’agit d’une variable globale qu’AdonisJs utilisera pour passer le jeton d’accès CSRF lors de l’envoi d’une requête POST, PUT et DELETE depuis votre application.

      Ce système a été mis en place pour protéger votre application contre les attaques de type Cross-Site Request Forgery (CSRF). Un secret CSRF unique est généré pour chaque utilisateur visitant votre site Web et, une fois que vos utilisateurs envoient une requête HTTP depuis le front-end, un jeton correspondant est généré pour ce secret et transmis avec la requête. Cela permettra au middleware créé pour cette requête dans AdonisJs de vérifier que le jeton et le secret CSRF sont tous deux valides et appartiennent à l’utilisateur actuellement authentifié.

      Enregistrez et quittez le fichier une fois que vous avez terminé.

      Ensuite, vous allez créer la page d’inscription avec cette commande :

      • adonis make:view auth/register

      Vous obtiendrez une sortie semblable à ceci :

      Output

      ✔ create resources/views/auth/register.edge

      Localisez et ouvrez le fichier nouvellement créé dans resources/views/auth/register.edge :

      • nano resources/views/auth/register.edge

      Ajoutez le code suivant :

      resources/views/auth/register.edge

      @layout('layouts/master')
      @section('content')
        <div class="container ">
          <div class="row">
              <div class="col-md-4  bg-white p-3 mt-5 shadow no-border rounded offset-md-4">
                <form method="POST" action="{{route('register.store')}}">
                  {{ csrfField() }}
                    <div class="form-group">
                      <label for="name">Fullname</label>
                      <input type="text" class="form-control" id="name" name="name"  value="{{old('name','')}}" placeholder="Enter Fullname">
                      {{ elIf('<span class=text-danger>$self</span>', getErrorFor('name'), hasErrorFor('name')) }}
                    </div>
                    <div class="form-group">
                      <label for="email">Email address</label>
                      <input type="email" class="form-control" id="email"  name="email" value="{{old('email','')}}" placeholder="Enter email">
                      {{ elIf('<span class=text-danger>$self</span>', getErrorFor('email'), hasErrorFor('email')) }}
                    </div>
                    <div class="form-group">
                      <label for="pasword">Password</label>
                      <input type="password" class="form-control" id="password" name="password" placeholder="Password">
                      {{ elIf('<span class=text-danger>$self</span>', getErrorFor('password'), hasErrorFor('password')) }}
                    </div>
                    <div class="text-center">
                        <button type="submit" class="btn btn-primary">Submit</button>
                    </div>
                </form>
              </div>
          </div>
        </div>
      @endsection
      

      Tout comme la page de connexion, ce fichier contient un formulaire HTML avec des champs de saisie pour recueillir les informations name (nom), email (adresse e-mail) et password (mot de passe) d’un utilisateur pendant la procédure d’inscription. La variable {{ csrfField() }} est également incluse, car elle est requise pour chaque requête post pour une application AdonisJs.

      Enregistrez et quittez le fichier.

      Maintenant, vous allez générer un nouveau fichier pour créer une citation en exécutant la commande suivante depuis le terminal :

      • adonis make:view quotes/create-quote

      Vous verrez une sortie semblable à :

      Output

      ✔ create resources/views/quotes/create-quote.edge

      Ouvrez resources/views/quotes/create-quote.edge :

      • nano resources/views/quotes/create-quote.edge

      Et ajoutez-y le contenu suivant :

      /resources/views/quotes/create-quote.edge

      @layout('layouts/master')
      @section('content')
      <div class="container">
          <div class="row">
              <div class="col-md-3"></div>
              <div class="col-md-6 shadow bg-white mt-5 rounded p-3">
                  <div class="float-right">
                      <a href="https://www.digitalocean.com/" class="btn btn-outline-dark ">back</a>
                  </div>
                      <br>
      
                  <div class="clear-fix"></div>
                      <form method="POST" action="{{route('store.quote')}}">
                          {{ csrfField() }}
                          <div class="form-group">
                              <label for="quote">Create Quote</label>
                              <textarea type="text" rows="5"  name='body' id="body" class="form-control" id="quote" placeholder="Write an inspirational quote"></textarea>
                          </div>
      
                          <div class="text-center">
                              <button type="submit" class="btn btn-primary">Submit</button>
                          </div>
                      </form>
                  </div>
              </div>
              <div class="col-md-3"></div>
          </div>
      </div>
      @endsection
      

      Cette page étend la mise en page master et contient un formulaire HTML avec un élément de zone de texte qui permet à un utilisateur de saisir du texte sur plusieurs lignes avant d’être affiché et traité par la route appropriée.

      Enregistrez et quittez le fichier une fois que vous avez terminé.

      Ensuite, vous allez créer une page pour modifier une citation particulière. Exécutez la commande suivante depuis le terminal :

      • adonis make:view quotes/edit-quote

      Vous verrez la sortie suivante :

      Output

      ✔ create resources/views/quotes/edit-quote.edge

      Ouvrez le fichier avec :

      • nano resources/views/quotes/edit-quote.edge

      Ajoutez le contenu suivant à resources/views/quotes/edit-quote :

      /resources/views/quotes/edit-quote.edge

      @layout('layouts/master')
      @section('content')
      <div class="container">
          <div class="row">
              <div class="col-md-6 shadow bg-white rounded p-3 offset-md-3">
                  <div class="float-right">
                      <a href="https://www.digitalocean.com/" class="btn btn-outline-dark ">back</a>
                  </div>
                  <br>
      
                  <div class="clear-fix"></div>
                  <form method="POST" action="/update-quote/{{quote.id}}">
                      {{ csrfField() }}
                      <div class="form-group">
                          <label for="pasword">Edit Quote</label>
                          <textarea type="text" rows="5"  name='body' id="body" class="form-control" id="quote" placeholder="write the inspirational quote">{{quote.body}}</textarea>
                      </div>
                      <div class="text-center">
                          <button type="submit" class="btn btn-primary">Update</button>
                      </div>
      
                  </form>
              </div>
          </div>
      </div>
      @endsection
      

      Cette page contient un contenu semblable à celui du fichier create-quote.edge. La différence est qu’elle contient les détails d’une citation particulière qui doit être modifiée, <form method="POST" action="/update-quote/{{quote.id}}">.

      Enregistrez et quittez le fichier.

      Enfin, générez une page pour afficher une seule citation :

      • adonis make:view quotes/quote

      Vous obtiendrez une sortie semblable à ceci :

      Output

      ✔ create resources/views/quotes/quote.edge

      Ouvrez le fichier avec :

      • nano resources/views/quotes/quote.edge

      Ajoutez le code suivant :

      /resources/views/quotes/quote.edge

      @layout('layouts/master')
      @section('content')
      <div class="container">
          <div class="row">
              <div class="col-md-6 offset-md-3">
                  <div class="card shadow-lg bg-dark text-white">
                      <div class="card-body">
                          <div class="float-right">
                              <a href="https://www.digitalocean.com/" class="btn btn-outline-primary ">back</a>
                          </div>
                              <br>
                          <div class="clear-fix"></div>
                          <blockquote class="blockquote mb-0">
                              <p>{{quote.body}}</p>
                              <footer class="blockquote-footer">
                                  <cite title="Source Title">{{quote.username}}</cite>
                              </footer>
                          </blockquote>
                      </div>
                  </div>
              </div>
          </div>
      </div>
      @endsection
      

      Cette page affiche les détails d’une citation particulière, qui comprend le corps de la citation, quote.body, et l’auteur qui l’a créée, quote.username.

      Une fois que vous avez terminé avec le fichier, enregistrez et quittez.

      Vous avez créé toutes les pages requises pour votre application en utilisant le moteur de modèles Edge. Ensuite, vous allez configurer et créer une connexion à la base de données de votre application.

      Étape 3 – Création d’un schéma de base de données

      Si vous mettez en service votre application maintenant, une erreur se produira car vous n’avez pas encore connecté l’application à une base de données. Dans cette section, vous établirez une connexion à la base de données et utiliserez ensuite la commande adonis pour générer un fichier de migration qui sera utilisé pour créer les tables.

      AdonisJs est livré avec un ORM nommé Lucid ORM, qui permet d’implémenter des enregistrements actifs pour travailler avec votre base de données. Il évite d’avoir à écrire des requêtes SQL qui récupèrent les données de la base de données en temps réel. C’est particulièrement utile lorsque l’on travaille sur une application complexe qui nécessite de nombreuses requêtes. Par exemple, il est possible de récupérer toutes les citations de votre application en écrivant ceci :

      const quotes = await Quote.all()
      

      Pour procéder à la configuration appropriée de la base de données de votre application, assurez-vous que vous êtes toujours dans le répertoire racine de votre application et créez un fichier .env :

      Ouvrez le fichier nouvellement créé et ajoutez le contenu suivant :

      .env

      HOST=127.0.0.1
      PORT=3333
      NODE_ENV=development
      APP_URL=http://${HOST}:${PORT}
      CACHE_VIEWS=false
      APP_KEY=bTVOEgUvmTCfkvgrK8gEBC3Qxt1xSYr0
      DB_CONNECTION=mysql
      DB_HOST=127.0.0.1
      DB_PORT=3306
      DB_USER=sammy
      DB_PASSWORD=password
      DB_DATABASE=adonis
      SESSION_DRIVER=cookie
      HASH_DRIVER=bcrypt
      

      Par défaut, la connexion à la base de données pour une application AdonisJs est SQLite, que vous changerez pour MySQL ici. Vous indiquez également le PORT et l’environnement de l’application, ainsi que les identifiants de votre base de données. Veillez à remplacer les espaces réservés DB_USER, DB_PASSWORD et DB_DATABASE par vos identifiants.

      Ensuite, vous allez créer le modèle et un fichier de migration pour Quote en utilisant la CLI Adonis. Pour ce faire, exécutez la commande suivante :

      • adonis make:model Quote --migration

      Vous verrez une sortie semblable à ce qui suit :

      Output

      ✔ create app/Models/Quote.js ✔ create database/migrations/1568209992854_quote_schema.js

      Cette commande créera un modèle pour Quote dans le dossier app/Models et un fichier de schéma dans le dossier database/migrations. Le fichier de schéma nouvellement créé sera préfixé avec l’horodatage actuel. Ouvrez le fichier de schéma avec :

      • nano database/migrations/1568209992854_quote_schema.js

      Mettez à jour son contenu avec le code suivant :

      database/migrations/…quote_schema.js

      'use strict'
      /** @type {import('@adonisjs/lucid/src/Schema')} */
      const Schema = use('Schema')
      class QuoteSchema extends Schema {
        up () {
          this.create('quotes', (table) => {
            table.increments()
            table.integer('user_id').notNullable()
            table.string('username', 80).notNullable()
            table.string('body').notNullable()
            table.timestamps()
          })
        }
        down () {
          this.drop('quotes')
        }
      }
      module.exports = QuoteSchema
      

      Un fichier de schéma dans AdonisJs nécessite deux méthodes différentes, qui sont :

      • up : méthode utilisée pour créer une nouvelle table ou modifier une table existante.
      • down : méthode utilisée pour revenir sur les modifications appliquées dans la méthode up.

      En plus des champs timestamps() et increments(), vous mettez à jour le contenu du fichier de schéma avec les attributs de champ user_id et username, et la valeur body d’une citation qui sera créée. Les champs user_id et username font référence aux détails de l’utilisateur qui crée une citation particulière. Cela définit une relation de un à plusieurs et signifie qu’un utilisateur peut posséder un nombre infini de citations, mais que chaque citation ne peut appartenir qu’à un seul utilisateur.

      Enregistrez et quittez le fichier.

      AdonisJs est installé par défaut avec un modèle User et son fichier de migration, qui ne nécessite qu’une petite modification pour établir la relation entre le modèle User et le modèle Quote.

      Ouvrez le modèle User dans app/Models/User.js :

      Ajoutez cette méthode immédiatement après la méthode tokens() :

      app/Models/User.js

      ...
      class User extends Model {
        ...
        tokens () {
          return this.hasMany('App/Models/Token')
        }
      
        quote () {
          return this.hasMany('App/Models/Quote')
        }
      }
      
      module.exports = User
      

      Cela permettra d’établir une relation de un à plusieurs avec le tableau Quote en utilisant user_id comme clé étrangère.

      Enregistrez et quittez le fichier.

      Pour conclure cette section, utilisez la commande suivante pour lancer les migrations, qui exécuteront la méthode up() de tous les fichiers de migration :

      Vous verrez une sortie similaire à celle-ci :

      Output

      migrate: 1503248427885_user.js migrate: 1503248427886_token.js migrate: 1568209992854_quote_schema.js Database migrated successfully in 3.42 s

      Vous avez configuré et sécurisé une connexion avec votre base de données. Vous avez également créé un modèle Quote et son fichier de schéma correspondant, et vous avez créé une relation de un à plusieurs entre un User et une variable Quote. Ensuite, vous allez générer les routes et créer des contrôleurs pour traiter les requêtes HTTP et la logique du système, afin de créer, modifier et supprimer une citation.

      Étape 4 – Création de contrôleurs et configuration de routes

      Dans cette section, vous commencerez par créer des contrôleurs pour gérer toute la logique de l’application, puis vous attacherez ces contrôleurs à une route spécifique pour que les utilisateurs puissent y accéder via une URL.

      Pour commencer, vous utiliserez la CLI Adonis pour créer un nouveau contrôleur de requêtes HTTP afin de gérer tous les processus d’authentification pour votre application en exécutant la commande suivante :

      • adonis make:controller Auth --type http

      Cette commande créera un fichier AuthController.js et l’enregistrera dans le dossier app/Controllers/Http. Vous utilisez l’indicateur--type pour indiquer que vous souhaitez que ce contrôleur soit un contrôleur HTTP.

      Vous verrez une sortie semblable à ce qui suit :

      Output

      ✔ create app/Controllers/Http/AuthController.js

      Ensuite, ouvrez le fichier de contrôleur nouvellement créé :

      • nano app/Controllers/Http/AuthController.js

      Mettez-le à jour avec le contenu suivant :

      app/Controllers/Http/AuthController.js

      'use strict'
      const User = use('App/Models/User')
      class AuthController {
      
          loginView({ view }) {
              return view.render('auth.login')
          }
          registrationView({ view }) {
              return view.render('auth.register')
          }
      
          async postLogin({ request, auth, response}) {
              await auth.attempt(request.input('email'), request.input('password'))
              return response.route('index')
          }
      
          async postRegister({ request, session, response }) {
              const user = await User.create({
                  username: request.input('name'),
                  email: request.input('email'),
                  password: request.input('password')
              })
              session.flash({ successmessage: 'User have been created successfully'})
              return response.route('login.create');
          }
      
          async logout ({ auth, response }) {
              await auth.logout()
              return response.route("https://www.digitalocean.com/")
          }
      }
      module.exports = AuthController
      

      Dans ce fichier, vous importez le modèle User et créez ensuite deux méthodes appelées loginView() et registerView() pour afficher respectivement les pages de connexion et d’inscription. Enfin, vous créez les méthodes asynchrones suivantes :

      • postLogin() : cette méthode permettra d’obtenir les valeurs email et password publiées à l’aide de la méthode request intégrée dans AdonisJs, puis de valider cet utilisateur par rapport aux détails de la base de données. Si l’utilisateur existe dans la base de données et a saisi les bons identifiants, il sera redirigé vers la page d’accueil et authentifié afin de pouvoir créer une nouvelle citation. Sinon, un message indiquant que les identifiants sont incorrects sera affiché.
      • postRegister() : cette méthode recevra les valeurs username, email et password d’un utilisateur afin de créer un compte pour cet utilisateur dans la base de données. Un message indiquant que cet utilisateur a bien été créé succès sera transmis à la session, et l’utilisateur sera redirigé vers la page de connexion pour s’identifier et commencer à créer une citation.
      • logout() : cette méthode gérera la fonctionnalité de déconnexion et redirigera l’utilisateur vers la page d’accueil.

      Enregistrez et quittez le fichier.

      Maintenant que vous avez configuré le contrôleur pour procéder à l’inscription et à l’authentification des utilisateurs, vous allez créer un contrôleur de requêtes HTTP pour gérer toutes les opérations concernant les citations.

      Retournez dans le terminal et exécutez la commande suivante pour créer QuoteController :

      • adonis make:controller Quote --type http --resource

      L’utilisation de l’indicateur --resource créera un contrôleur avec des méthodes ressources prédéfinies pour effectuer les opérations CRUD (Create, Read, Update, Delete).

      Vous verrez :

      Output

      ✔ create app/Controllers/Http/QuoteController.js

      Localiser ce fichier dans app/Controllers/Http/QuoteController.js :

      • nano app/Controllers/Http/QuoteController.js

      Mettez-le à jour avec le contenu suivant :

      app/Controllers/Http/QuoteController.js

      'use strict'
      const Quote = use('App/Models/Quote')
      
      class QuoteController {
      
        async index ({ view }) {
          const quote = await Quote.all()
          return view.render('index', {
            quotes: quote.toJSON()
          })
        }
      
        async create ({ view }) {
          return view.render('quotes.create-quote')
        }
      
        async store ({ request,auth,session, response }) {
          const quote = await Quote.create({
            user_id: auth.user.id,
            username: auth.user.username,
            body: request.input('body')
          })
          session.flash({ 'successmessage': 'Quote has been created'})
          return response.redirect("https://www.digitalocean.com/")
        }
      
        async show ({ params, view }) {
          const quote = await Quote.find(params.id)
          return view.render('quotes.view-quote', {
            quote: quote.toJSON()
          })
        }
      
        async edit ({ params, view }) {
          const quote = await Quote.find(params.id)
          return view.render('quotes.edit-quote', {
            quote: quote.toJSON()
          })
        }
      
        async update ({ params, request, response, session }) {
          const quote = await Quote.find(params.id)
          quote.body = request.input('body')
          await quote.save()
          session.flash({'successmessage': 'Quote has been updated'})
          return response.redirect("https://www.digitalocean.com/")
        }
      
        async destroy ({ params, response, session }) {
          const quote = await Quote.find(params.id)
          await quote.delete()
          session.flash({'successmessage': 'Quote has been deleted'})
          return response.redirect("https://www.digitalocean.com/")
        }
      }
      module.exports = QuoteController
      

      Dans ce contrôleur, vous avez importé le modèle Quote et mis à jour les méthodes suivantes qui ont été créées automatiquement en utilisant la CLI AdonisJs :

      • index() : pour récupérer toutes les citations de la base de données et les afficher sur la page d’accueil de l’application.
      • create() : pour afficher une page permettant de créer des citations.
      • store() : pour enregistrer une citation nouvellement créée dans la base de données et retourner une réponse appropriée.
      • show() : pour obtenir l’id d’une citation particulière, la récupérer depuis la base de données et l’afficher sur la page de modification de citation.
      • edit() : pour obtenir le détail d’une citation particulière de la base de données et l’afficher pour modification.
      • update() : pour traiter toute mise à jour effectuée sur une citation et rediriger l’utilisateur vers la page d’accueil.
      • destroy() : pour supprimer une citation de la base de données.

      Enregistrez et quittez le fichier.

      Après avoir créé tous les contrôleurs nécessaires pour cette application, vous pouvez maintenant configurer les routes de manière à ce que les utilisateurs puissent facilement interagir avec votre application. Pour commencer, naviguez vers le fichier start/routes.js.

      Remplacez son contenu par le suivant :

      start/routes.js

      'use strict'
      const Route = use('Route')
      
      Route.get("https://www.digitalocean.com/",'QuoteController.index').as('index')
      Route.get('/register','AuthController.registrationView').as('register.create')
      Route.post('/register-store','AuthController.postRegister').as('register.store').validator('Register')
      Route.get('/login','AuthController.loginView').as('login.create')
      Route.post('/login-store','AuthController.postLogin').as('login.store')
      Route.get('/view-quote/:id','QuoteController.show').as('view.quote')
      
      Route.group(() => {
          Route.get('/create-quote','QuoteController.create').as('create.quote')
          Route.post('/store-quote','QuoteController.store').as('store.quote')
          Route.get('/edit-quote/:id','QuoteController.edit').as('edit.quote')
          Route.post('/update-quote/:id','QuoteController.update').as('update.quote')
          Route.get('/delete-quote/:id','QuoteController.destroy').as('delete.quote')
          Route.post('/logout','AuthController.logout').as('logout')
      }).middleware(['auth'])
      

      Ici, vous définissez le chemin pour chaque route dans votre application, spécifiez les verbes HTTP pour chaque action, et liez la route à une méthode particulière dans chaque contrôleur. Vous nommez également chacune de ces routes telles qu’elles ont été référencées dans les contrôleurs et les vues.

      Pour garantir que seuls les utilisateurs authentifiés puissent accéder à toutes les routes de citation, vous attribuez un middleware de groupe. Et enfin, vous attachez une méthode de validation à la route register.store pour valider les entrées des utilisateurs.

      Enregistrez et quittez le fichier.

      Vous avez créé vos contrôleurs et configuré les routes de votre application. Ensuite, vous allez créer la méthode de validation définie dans cette étape.

      Étape 5 – Validation des entrées des utilisateurs

      AdonisJs n’a pas de validateurs intégrés par défaut. Vous allez donc installer et enregistrer le validateur de votre application manuellement.

      Exécutez la commande suivante pour l’installer :

      Ouvrez le fichier suivant pour enregistrer le fournisseur de validateurs :

      Ensuite, enregistrez le fournisseur de validateurs en l’ajoutant à la liste des fournisseurs comme indiqué ci-dessous :

      start/app.js

      ...
      const providers = [
         ...
         '@adonisjs/cors/providers/CorsProvider',
         '@adonisjs/shield/providers/ShieldProvider',
         '@adonisjs/session/providers/SessionProvider',
         '@adonisjs/auth/providers/AuthProvider',
         '@adonisjs/validator/providers/ValidatorProvider'
      ]
      

      Maintenant que vous avez installé et enregistré le fournisseur de validateurs dans votre application, créez un validateur personnalisé pour valider les entrées des utilisateurs lors de l’inscription avec la commande suivante :

      • adonis make:validator Register

      Cela créera un fichier Register.js dans le répertoire App/validators. Ouvrez le fichier avec :

      • nano app/Validators/Register.js

      Ajoutez le code suivant au fichier :

      app/Validators/Register.js

      'use strict'
      class Register {
        get rules () {
          return {
            name:'required',
            email:'required|email|unique:users',
            password:'required|min:8'
          }
        }
      
        get messages(){
          return{
            'name.required':'Full name is required',
            'email.required':'email is required',
            'email.unique':'email already exists',
            'password.required':'password is required',
            'password.min':'password should be at least 8 characters'
          }
        }
      }
      module.exports = Register
      

      Vous définissez des règles pour des champs spécifiques dans votre application. Si les validations échouent à un moment, le validateur définit automatiquement l’erreur comme un message flash et l’utilisateur est redirigé vers le formulaire.

      Enregistrez et quittez le fichier une fois que vous avez terminé de le modifier.

      Enfin, pour ajouter le style de votre application, ouvrez le fichier suivant :

      Remplacez son contenu par le suivant :

      /public/style.css

      @import url('https://fonts.googleapis.com/css?family=Montserrat:300');
      
      html, body {
        height: 100%;
        width: 100%;
      }
      
      body {
        font-family: 'Montserrat', sans-serif;
        font-weight: 300;
        background-image: url("/splash.png");
        background-color: #220052;
      }
      
      * {
        margin: 0;
        padding: 0;
      }
      
      a {
        color: inherit;
        text-decoration: underline;
      }
      
      p {
        margin: 0.83rem 0;
      }
      
      .quote-wrapper {
        margin-top: 20px;
      }
      
      .quote-wrapper a {
        text-decoration: none;
      }
      
      .quote-wrapper a:hover {
        color: #ffffff;
      }
      
      .empty-quote {
        color: #ffffff;
      }
      
      form {
        padding: 20px;
      }
      

      Dans ce fichier, vous mettez à jour le style CSS de votre application dans le fichier style.css.

      Vous avez installé et enregistré un fournisseur de validateurs afin de vérifier les données saisies par les utilisateurs lors de la procédure d’inscription. Vous avez également mis à jour le contenu de votre feuille de style pour ajouter plus de style à l’application. Dans la dernière étape, vous allez tester votre application.

      Étape 6 – Mise en service de l’application

      Dans cette étape, vous allez mettre en service votre application et créer un utilisateur et un mot de passe pour tester l’identification. Vous allez également ajouter une citation à votre application et la consulter sur la page d’accueil.

      Pour tester votre application, démarrez le serveur de développement avec la commande suivante depuis le répertoire racine de votre application :

      L’application sera alors lancée sur le port défini dans le fichier root .env, qui est 3333. Naviguez jusqu’à http://localhost:333 depuis votre navigateur.

      Page d'accueil de l'application de citations

      Pour l’instant, la page d’accueil est vide car vous n’avez pas encore créé de citation. Cliquez sur le bouton Register (S’inscrire).

      Page d'inscription

      Entrez vos informations et cliquez sur le bouton Submit (Envoyer) pour terminer le processus d’inscription. Vous serez redirigé vers la page de connexion. Entrez votre adresse e-mail et votre mot de passe pour vous identifier.

      Page de connexion

      Une fois que vous vous êtes identifié, cliquez sur le bouton Create Quote (Créer une citation).

      Page de création de citation

      Entrez une citation et naviguez vers la page View all (Tout voir) pour voir votre citation.

      Page Voir toutes les citations

      Vous avez testé votre application en créant et en authentifiant un utilisateur, et en écrivant une citation.

      Conclusion

      Dans ce tutoriel, vous avez construit une application Web avec AdonisJs. Vous avez configuré l’application à l’aide de la CLI AdonisJs et utilisé la CLI pour créer d’autres fichiers pertinents tels que des contrôleurs, des modèles et des vues.

      Vous pouvez créer des applications Web avec ce framework, quelles que soient leur taille et leur complexité. N’hésitez pas à télécharger le code source de ce projet ici sur GitHub. Pour découvrir d’autres caractéristiques, vous pouvez également consulter la documentation officielle.

      Si vous souhaitez explorer certains de nos autres tutoriels sur le framework JavaScript, consultez ce qui suit :



      Source link