This chapter covers
So far, you’ve been writing and using Elixir code in an IEx session or, in chapter 4, in a single file. The majority of your Elixir and Phoenix projects won’t be organized like this, however. As your application grows in complexity, it’s important to impose some sort of organizational structure to keep things manageable.
In this chapter, we’ll cover the structure of a typical Elixir application. Along the way, you’ll use the Mix utility to automate a lot of tasks that would take some effort if done manually. Finally, you’ll use the Hex package manager to bring third-party tools and libraries into your application. All of this will help you get your application set up properly before you tackle using a real database in chapter 6.
Your auction application in chapter 4 consisted of a fake repo, a public interface layer to access the data in the repo, and an Item struct that defined the data structure of your auction items. All that code—three modules—existed in a single file. Once you start adding more functionality, that kind of project structure will become unmaintainable.
You could break up the modules into separate files. This is a great idea on the surface, but as you increasingly need to use code from one file in a different file, you’ll end up with a web of interconnected files that all depend on one another.
Fortunately, there’s a standard directory structure for Elixir projects. As you can see in figure 5.1, there are usually three top-level directories for every Elixir application:
Along with the standard directories, you’ll typically find a file named mix.exs. This file can be considered the brain or mother ship of your application. You’ll look at this file in the next section.
Although simple applications are typically structured in this way, you’ll be creating multiple applications—one for the business logic you’ve been working on and one for your Phoenix application. But you’ll also create another skeleton application to tie them together. This kind of pattern is called an umbrella application. The top-level umbrella application will contain the subapplications that contain the logic.
You may be thinking, “Oh, great. Every time I want to start a new Elixir application, I have to remember this standard structure.” If you are indeed thinking that, I’ve got some great news for you! You don’t have to remember it at all! All you have to remember is mix. Like IEx, the Mix utility is installed when you install Elixir. And also like IEx, it has an excellent help system. If all you remember is the command mix, you can figure out how to get the rest.
The following listing jumps directly into using the Mix tool (in the terminal). It will tell you all the different things it can do.
> mix ** (Mix) "mix" with no arguments must be executed in a directory with a mix.exs file Usage: mix [task] Examples: 1 mix - Invokes the default task (current: "mix run") mix new PATH - Creates a new Elixir project at the given path mix help - Lists all available tasks mix help TASK - Prints documentation for a given task
The second example in the preceding listing tells you how to create a new Elixir project. That sounds helpful. But what if you want to know more? You can see in the following listing that mix even tells you how to get more help. If you enter mix help new it will give you all the help documentation for that specific task.
> mix help new mix new Creates a new Elixir project. It expects the path of the project as argument. mix new PATH [--sup] [--module MODULE] [--app APP] [--umbrella] 1 A project at the given PATH will be created. The application name and module name will be retrieved from the path, unless --module or --app is given. A --sup option can be given to generate an OTP application skeleton including a supervision tree. Normally an app is generated without a supervisor and without the app callback. An --umbrella option can be given to generate an umbrella project. An --app option can be given in order to name the OTP application for the project. A --module option can be given in order to name the modules in the generated code skeleton. ## Examples mix new hello_world 2 Is equivalent to: mix new hello_world --module HelloWorld To generate an app with a supervision tree and an application callback: mix new hello_world --sup To generate an umbrella application with sub applications: mix new hello_world --umbrella cd hello_world/apps mix new child_app
You can see that there are a number of options you can specify when creating a new Elixir application. If you wanted to create a new Elixir application, you’d definitely want to use this tool as the first step. mix new will not only generate the standard Elixir application directory structure but also give you some files that are starting points for your application.
Before you create an application for your auction backend, let’s use the tool on a throwaway project just to see how it works. Because the first option to mix new is the path of the project as well as the application name, you need to avoid most special characters. Like in variable names, you avoid using dashes, but you can use underscores. If you’re like me and prefer dashes to underscores in your directory names, you can specify an alternative name for the application itself (with --app) that uses underscores instead.
Suppose you want to create a Facebook replacement named FriendFace.[1] In a temporary directory somewhere, run the following command.
Thanks to the show “The IT Crowd” for the name inspiration.
> mix new friend-face --app friend_face * creating README.md * creating .formatter.exs * creating .gitignore * creating mix.exs * creating config * creating config/config.exs * creating lib * creating lib/friend_face.ex * creating test * creating test/test_helper.exs * creating test/friend_face_test.exs 1 Your Mix project was created successfully. You can use "mix" to compile it, test it, and more: cd friend-face mix test 2 Run "mix help" for more commands.
You can see that not only did the mix new command create your directory structure, but it also gave you a README, a .gitignore file for ignoring files in your Git repo if you were to create one, a config file, a skeleton module for your friend_face application, and even a test file. You can peek into each of these files and see that they’re not just empty files. They’re files that have actual uses as they are, and they’re very helpful as you’re getting started. If you follow the instructions at the end of listing 5.3 and run mix test in your project directory, you’ll even discover that it already has a passing test.
After you’re done exploring this test application, feel free to delete the directory and all the files it generated for you. You won’t need them.
Now that you’ve seen the basics of how mix works, let’s create an application for your auction site. You’ll use the mix new command like before, but this time you’ll do it in a nontemporary directory that you use for your projects. The first thing you need to generate is the umbrella itself. You’ll then create an auction application inside that umbrella.
Creating an umbrella application is very simple: pass the --umbrella flag to mix new. Let’s call this umbrella structure auction_umbrella to make it recognizably an umbrella structure. I got the following output in my terminal when I ran that command.
> mix new --umbrella auction_umbrella * creating README.md * creating .formatter.exs * creating .gitignore * creating mix.exs * creating apps * creating config * creating config/config.exs Your umbrella project was created successfully. Inside your project, you will find an apps/ directory where you can create and host many apps: cd auction_umbrella cd apps 1 mix new my_app 2 Commands like "mix compile" and "mix test" when executed in the umbrella project root will automatically run for each application in the apps/ directory.
This kind of structure allows you to create sub-applications under the umbrella application. You don’t really need to modify anything it generated at the moment, but the output does offer a good clue as to what you should do next. All the sub-applications of an umbrella application are stored in the apps directory (auction_umbrella/apps in this case). You can cd into that subdirectory and run mix new app_name to generate a sub-application.
You’ll name your application Auction. Catchy, huh? cd into auction_umbrella/apps and type mix new auction --sup in your terminal. What does the --sup do? It creates an application skeleton along with the files to easily create a supervision tree. This won’t make much difference now, but it will as you go on (you’ll use that supervisor in chapter 7—it will do things like make sure the database connections are maintained). You should see output like the following.
> mix new auction --sup 1 * creating README.md * creating .formatter.exs * creating .gitignore * creating mix.exs * creating config * creating config/config.exs * creating lib * creating lib/auction.ex * creating lib/auction/application.ex * creating test * creating test/test_helper.exs * creating test/auction_test.exs Your Mix project was created successfully. You can use "mix" to compile it, test it, and more: cd auction mix test Run "mix help" for more commands.
You may have realized that you now have two mix.exs files in your umbrella application—one at the top level of the umbrella, and one in the new Auction application. That’s perfectly fine—they’ll live well with each other. But the rest of the work you’ll do in this chapter will be strictly inside the auction_web/apps/auction directory.
For any Elixir application, the mix.exs file is pretty magical. In it, you define things like the current version of your application, your application’s name, the version of Elixir it runs on, any outside dependencies that your application requires in order to run, and any additional applications or supervisors that also need to be started when your application is started.
If you take a peek inside the auction_umbrella/apps/auction/mix.exs file that the mix new task generated for you, you can begin to see just how helpful that Mix task is.
defmodule Auction.MixProject do use Mix.Project def project do [ app: :auction, version: "0.1.0", build_path: "../../_build", config_path: "../../config/config.exs", deps_path: "../../deps", lockfile: "../../mix.lock", elixir: "~> 1.7", start_permanent: Mix.env() == :prod, deps: deps() ] end # Run "mix help compile.app" to learn about applications. 1 def application do [ extra_applications: [:logger], mod: {Auction.Application, []} ] end # Run "mix help deps" to learn about dependencies. 1 defp deps do [ # {:dep_from_hexpm, "~> 0.3.0"}, 2 # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, # {:sibling_app_in_umbrella, in_umbrella: true}, ] end end
Let’s further break down each of these functions.
You may have noticed that some of the files you’re working with have the extension .ex, and some have the extension .exs. What’s the difference? When do you use each?
Most of the time, you’ll be writing .ex files, as you want all the benefits of compiled code (compiler optimizations, speed, and so on). .exs files, because they’re interpreted, are slower to run (they have to go through parsing, tokenization, and so on). They are, however, a flexible choice when you don’t require compilation. For example, the mix.exs file in an Elixir project and all test code files are .exs files.
The project function defines the top-level details of your Elixir application:
The ~> means the following version number can be incremented by the last dot value in the version. In this case, you could run versions 1.7 through 1.?, but not versions before 1.7 or versions 2.0 and later.
The following listing shows the project function.
def project do [ app: :auction, version: "0.1.0", build_path: "../../_build", 1 config_path: "../../config/config.exs", 1 deps_path: "../../deps", 1 lockfile: "../../mix.lock", 1 elixir: "~> 1.7", start_permanent: Mix.env() == :prod, deps: deps() ] end
These are only some of the options that can be set here for your application. Elixir itself has a few more (which you can read about in its excellent documentation for Mix.Project: https://hexdocs.pm/mix/Mix.Project.html). Other dependencies of your application may also have options that will need to be set here.
The application function (see listing 5.8) is pretty simple in terms of what’s generated, but the functionality it provides is big. In simple terms, it’s what tells the compiler that you’d like to generate an .app file for your application. According to the documentation (which you can read by typing # Run "mix help compile.app", as in the comment about the function declaration in listing 5.6), “An .app file is a file containing Erlang terms that defines your application. Mix automatically generates this file based on your mix.exs configuration.”
def application do [ extra_applications: [:logger], mod: {Auction.Application, []} 1 ] end
An Elixir application compiles down to Erlang code (figure 5.2), which will run on the BEAM virtual machine, and the application function provides additional instructions to the compiler about how to compile Erlang code. The most-used options concern additional, external applications that need to be started along with your application. Any application name you provide to extra_applications (in :atom form) is guaranteed to start before your application, so that it will be ready to accept commands when your application needs it. By default, Elixir’s built-in Logger application is started up to provide logging functionality.
Third-party applications and dependencies can tell the Elixir compiler that they need to be started along with your application. If they do, they’ll be started automatically without you having to tell Elixir to do so. If an application needs to be included in extra_applications, the README for the library will let you know. If it doesn’t mention the requirement, you can bet that it will either be started automatically or that it doesn’t need to be started at all.
Finally, the mod key is an application callback. Any module you specify in this list (along with a list of arguments, which is currently empty) will be called when the main application starts. The callback expects Auction.Application.start/2 to be defined. When you generated the application with the --sup flag, it created that module for you and placed the reference to it here in the mod key.
The final function in your generated mix.exs file is deps. This is where you list all the external applications, packages, and libraries your application depends on. You can see in the following listing that you currently rely on no external packages.
defp deps do [ # {:dep_from_hexpm, "~> 0.3.0"}, # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, # {:sibling_app_in_umbrella, in_umbrella: true}, 1 ] end
Dependencies are specified with the package name plus the version numbers accepted in a tuple (like {:package_name, "~> 1.0"}). For the version requirements, a few different options can be specified. For more details, check the Version documentation: https://hexdocs.pm/elixir/Version.html. You’ll be using deps extensively in the coming sections.
A handful of other options and functions you can use in your Mix file aren’t generated in a skeleton application, and you won’t use them in this book. For more information on these options, check out the Mix.Project documentation: https://hexdocs.pm/mix/Mix.Project.html.
You’ve used mix new auction to generate a skeleton application structure and configuration for your Auction application, and now you need to move the code you created in chapter 4 from a single file containing multiple modules into separate files for each module.
I apologize for the little bit of busywork in this section—this is the only time in this book where you’ll cut and paste code like this. In the last chapter, I wanted to make it clear that you could define as many modules as you wanted in a single file and that they would all compile. It was also the easiest way to use multiple modules without a full-on Mix application. But that means that you now need to break that file into three separate modules.
One of the cool things about Elixir is that you can name the files whatever you want in whatever structure you want. This allows you to structure your application as you see fit. The flip side is that unless you decide on some rules regarding how you’re going to structure your application files, it can quickly get out of control.
If you’ll recall, you defined three modules in auction.ex in chapter 4:
You’ll therefore create three different files—one for each module. Usually the application and library code should go in the lib directory that mix new generated for you, so you’ll start there.
The mix new task created an auction.ex file in the lib directory of your application. Paste all the code that made up the Auction module into that file. You’ll notice that mix new auction generated a hello function in that file—it’s safe to overwrite all the contents of the generated file. The following listing shows that module.
defmodule Auction do 1 alias Auction.{FakeRepo, Item} @repo FakeRepo def list_items do @repo.all(Item) end def get_item(id) do @repo.get!(Item, id) end def get_item_by(attrs) do @repo.get_by(Item, attrs) end end
For the Auction.Item module, you need to create a new file. You could create this file in the top level of the lib directory, but it’s standard practice to match your directory structure to the namespacing of your module. Item is namespaced under Auction in your module name (Auction.Item), so a good rule of thumb is to create an auction subdirectory and have item.ex live in there. Figure 5.3 shows the file structure based on namespacing.
Paste the entirety of the Auction.Item module code into a file named lib/auction/item.ex (or whatever other name you may have chosen). The following listing shows the contents of that file.
defmodule Auction.Item do defstruct [:id, :title, :description, :ends_at] 1 end
Finally, you have the Auction.FakeRepo code. Like Auction.Item, you match the module namespacing and your directory structure. Paste the Auction.FakeRepo module code a file named lib/auction/fake_repo.ex.
defmodule Auction.FakeRepo do alias Auction.Item @items [ 1 %Item{ id: 1, title: "My first item", description: "A tasty item sure to please", ends_at: ~N[2020-01-01 00:00:00] }, %Item{ id: 2, title: "WarGames Bluray", description: "The best computer movie of all time, now on Bluray!", ends_at: ~N[2018-10-15 13:39:35] }, %Item{ id: 3, title: "U2 - Achtung Baby on CD", description: "The sound of 4 men chopping down The Joshua Tree", ends_at: ~N[2018-11-05 03:12:29] } ] def all(Item), do: @items def get!(Item, id) do Enum.find(@items, fn(item) -> item.id === id end) end def get_by(Item, map) do Enum.find(@items, fn(item) -> Enum.all?(Map.keys(map), fn(key) -> Map.get(item, key) === map[key] end) end) end 2 end
A good rule of thumb for filenames is to convert InitCase module names to lowercase and use an underscore before the previously capitalized letters. PhoenixInAction becomes phoenix_in_action, and “FakeRepo” becomes fake_repo.
If you’ve followed along so far, you should have a directory structure similar to figure 5.4. But because Elixir is a compiled language, you need to compile your application before it can run. Thankfully, this is very easy.
Now that you’ve got the code all organized, you may be wondering how to run it. In chapter 4, you compiled the file directly and brought it into an IEx session to play with. Now that you have a full-fledged application, you can use the mix utility. For example, to compile your application, you can issue the command mix compile.
> mix compile Compiling 4 files (.ex) Generated auction app
The first time you run this, it will go through your entire application looking for .ex files and compiling them into something that can run on the Erlang VM (using the mix.exs file). You’ll notice in the preceding output that it compiled four files. Because there were no warnings during compilation, it tells you that it successfully generated the auction application.
If you run mix compile again right away, you’ll get no output from the compiler. This is because Elixir’s compiler is smart enough to recognize that no changes have been made since the last time you compiled, so nothing needs to be done. In fact, it’s smart enough to know not only whether any files changed, but also which files have changed. If a file hasn’t changed, it won’t be recompiled (unless it’s affected by a file that did change). This will save you lots of time as you build your app.
You now have a compiled application, so how do you run it? You haven’t created a graphical interface for the application yet—only the code required to play with your fake data through a public interface. Because of that, the only way you can interact with the program at the moment is via IEx. But you’ll start this IEx session a little differently than in the past.
In chapter 4, you started IEx while requiring a specific file (your application code, auction.ex). Now you no longer have a single file. Instead, you have an Elixir Mix application. To start up an IEx session and require an entire Mix application to be brought in, you can use the iex -S mix command inside the directory of a Mix application:
> iex -S mix Erlang/OTP 21 [erts-10.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async- threads:1] [hipe] [dtrace] Interactive Elixir (1.7.4) - press Ctrl+C to exit (type h() ENTER for help) iex(1)>
If you hadn’t already compiled your application, it would compile here before starting IEx. But because you did compile it, it will start right up and include all the files of the Auction application. The following listing shows an example of testing the public interface you created.
iex(1)> Auction.list_items |> Enum.map(fn(item) -> item.title end) 1 ["My first item", "WarGames Bluray", "U2 - Achtung Baby on CD"] iex(2)> Auction.get_item_by(%{title: "WarGames Bluray"}) %Auction.Item{description: "The best computer movie of all time, now on Bluray!", ends_at: ~N[2018-10-15 13:39:35], id: 2, title: "WarGames Bluray"}
It’s all working! You didn’t have to manually require any files or specify which files you were going to use—it all just worked! This is the magic of an Elixir application. I say magic because moving from using individual source code files outside of a Mix application (as in chapter 4, with a mess of file requires and effort needed to get everything working together) to having something that just works right off the bat (as in this chapter) is very refreshing.
Now that you’ve gone through the configuration for the Auction application, you can move on to declaring the dependencies. Some very smart Elixir and Erlang developers have produced open source packages that can add functionality to your application, and one such package you’ll eventually add to your application is Ecto. Ecto describes itself as “A database wrapper and language integrated query for Elixir.”
You’ll eventually need to move away from your FakeRepo and into a real repo so you can allow real functionality in your application. Ecto is currently the package to use when creating Elixir applications that need to talk to databases. In fact, you have to explicitly tell Phoenix not to bring in Ecto if you don’t need it when creating a new Phoenix project.
As you’ll recall from the discussion of the mix.exs file (section 5.1.3), your application keeps track of its required dependencies in the deps function. So far, you know you’re going to require a package called Ecto and that it belongs in the mix.exs file.
Hex is Elixir’s package manager. But Hex is more than that—it also comes with nice Mix tasks that make using the package manager easy. For example, there’s a great search tool. Let’s say you know you’re going to need a package that makes rendering React.js components easier in your Phoenix application, but you don’t know any package names. You can either go into a web browser and search the database through Hex’s frontend (at https://hex.pm) or use the Mix task mix hex.search PACKAGE. The following listing shows the output from using the Mix task.
> mix hex.search react 1 Package Version URL reaxt 1.0.1 https://hex.pm/packages/reaxt react_phoenix 0.5.0 https://hex.pm/packages/ react_phoenix lyn 0.0.16 https://hex.pm/packages/lyn phoenix_components 1.0.2 https://hex.pm/packages/ phoenix_components react_on_elixir 0.0.4 https://hex.pm/packages/ react_on_elixir phoenix_reactor 0.1.0 https://hex.pm/packages/ phoenix_reactor reactive 0.0.1 https://hex.pm/packages/reactive reactivity 0.6.0 https://hex.pm/packages/reactivity elixir_script_react 1.0.2-react.15.6.1 https://hex.pm/packages/ elixir_script_react Phoenix_react 0.1.0 https://hex.pm/packages/ phoenix_react
If you get an error stating that “The task “hex.search” could not be found,” run the command mix local.hex and try again.
The packages listed here have something to do with the word “react.” It could be in the package name, in the description, or other places, and they’re ordered loosely by popularity.
Sometimes you’ll know what package you need, and you need to know the latest version number. In those cases, I’ve found the Mix task to be the fastest way to retrieve that information. For example, you know you’ll need Ecto in your application, so the only further piece of information you require is the latest version number (unless you already know of a specific one you want to depend on). That means you can search for ecto with the Mix task, as shown in the following listing. Ecto is split into two distinct packages: ecto and ecto_sql. For now, you need the ecto_sql version in order to talk to your database.
> mix hex.search ecto 1 Package Description Version URL ecto A toolkit for data mapping... 3.0.3 https://hex.pm/packages/ecto ecto_sql SQL-based adapters for Ecto... 3.0.3 https://hex.pm/packages/ ecto_sql # SNIP!
You can see that the latest version was 3.0.3 when I ran this command. Unless you have a compelling reason to use an older version of a package, it’s generally a good idea to use the latest. You’ll depend on at least version 3.0.3 in your application.
It’s likely that by the time you read this, the version numbers will have advanced beyond 3.0.3. If that’s the case, use the latest version available.
To specify the package name and version 3.0.3, your deps function would look like the following.
defp deps do [ {:ecto_sql, "3.0.3"} 1 ] end
The preceding listing shows how to specify a dependency to a specific version requirement. But sometimes there are other ways you’d like to handle the dependency versions.
In general, Hex packages should use semantic versioning (major.minor.patch). In the case of Ecto, you’re looking at the major 3, minor 0, patch 5 release. Major versions can have backward-incompatible changes in them—you’ll normally require some migration in your usage of the package if you change major versions. Minor versions typically contain new functionality but don’t break existing usage. Patch versions typically contain minor bug fixes and the like.
So what if you want to keep your Ecto package up to date but don’t want to worry about manually editing the deps function every time there’s a new release? There are a few options in the version specification syntax that you can use:
Regardless of the version requirements, Hex will attempt to fetch the latest, most recent package version that meets the requirements specified. With that in mind, let’s make sure you have Hex include any bug fixes in the 3.0 minor branch by using the ~> 3.0.3 format. The following listing shows what the deps function should look like.
defp deps do [ {:ecto_sql, "~> 3.0.3"} 1 ] end
Ecto is an important part of your application, because it provides a wrapper around a database, but it doesn’t speak to the database directly. Ecto requires an adapter specific to the database that you’d like to use. Why not use the adapter directly, without Ecto? Ecto provides a large range of utilities and functions that make working with a database much easier and without a lot of the boilerplate code that’s usually necessary. And because you’re writing code that Ecto then translates into database-speak, you can typically move from one database to another without having to change much (if any) of your code.
In this book, you’ll be using the PostgreSQL database, so you’ll use the PostgreSQL adapter. The vast majority of the code you’ll write (if not all of it) will work as written with any of the other Ecto adapters. There may be small exceptions to this (mostly during the setup of the adapter itself), but the fact that databases are so easily interchangeable is one of the great things about using Ecto.
Because you’re using PostgreSQL, you need to modify your deps function in mix.exs to include the dependency (postgrex), as in the following listing.
defp deps do [ {:ecto_sql, "~> 3.0.3"}, {:postgrex, "~> 0.14.1"} 1 ] end
If you’d rather use a different supported database for your application, be sure to use the correct adapter (see table 5.1).
Database |
Ecto adapter |
Dependency |
---|---|---|
PostgreSQL | Ecto.Adapters.Postgres | postgrex |
MySQL | Ecto.Adapters.MySQL | mariaex |
MSSQL | MssqlEcto | mssql_ecto |
SQLite | Sqlite.Ecto2 | sqlite_ecto2 |
Mnesia | EctoMnesia.Adapter | ecto_mnesia |
Now that you have the dependencies specified, you need to bring them into your application. You do that in the following listing by using a Mix task—mix deps.get. When you execute that task in your terminal, it will query hex.pm about the latest applicable versions of the dependencies you specified. It also does the job of fetching their dependencies, so you don’t have to worry about manually ensuring that a long line of dependency requirements are met (see figure 5.5).
> mix deps.get Resolving Hex dependencies... Dependency resolution completed: New: connection 1.0.4 db_connection 2.0.3 decimal 1.6.0 1 ecto 3.0.5 2 ecto_sql 3.0.3 postgrex 0.14.1 telemetry 0.2.0 * Getting ecto_sql (Hex package) * Getting postgrex (Hex package) * Getting connection (Hex package) * Getting db_connection (Hex package) * Getting decimal (Hex package) * Getting ecto (Hex package) * Getting telemetry (Hex package)
The output you see is Hex fetching the required packages and putting them into the deps directory of your application. The next time you compile your application (whether explicitly via mix compile or by starting your application with iex -S mix), those dependencies will be compiled into your application for your application code to take advantage of.
We’ll go deeper into using Ecto in the next chapter, but to demonstrate how you can use external dependencies with little fuss, let’s temporarily add the UUID package to your application dependencies. Add the dependency requirement to your mix.exs file as follows.
defp deps do [ {:ecto_sql, "~> 3.0.3"}, {:postgrex, "~> 0.14.1"}, {:uuid, "~> 1.1.8"} 1 ] end
Be sure to run mix deps.get again to fetch the newly added dependency.
Now, use it in your application’s environment via an IEx session. UUID is a package that allows you to easily generate universally unique identifiers, so you’ll test its ability to do so in the following listing by using its uuid4/0 function to generate a version 4 UUID. You could even use it to generate auction titles.
> iex -S mix # ... likely lots of code compilation output iex(1)> UUID.uuid4 "40a6eb21-4c85-46ac-a550-e18130187aee" 1 iex(2)> %Auction.Item{title: UUID.uuid4} %Auction.Item{description: nil, ends_at: nil, id: nil, title: "592b2b0b-5f9e-4c74-91d9-478bd2ca1d9b"} 1
Because the purpose of UUIDs is to be “universally unique,” your output will be different than mine was, but the formatting will be the same, and it will be a valid UUID string. It works!
You’re now done with your little experiment, and you no longer need the UUID package. How can you get rid of once-required dependencies that are no longer needed? It’s actually very easy. Simply remove it from the deps/0 function in your mix.exs file.
defp deps do [ {:ecto_sql, "~> 3.0.3"}, {:postgrex, "~> 0.14.1"} 1 ] end
Once you’ve done that, you can again run mix deps.get and it will update your mix.lock file, which keeps track of all your dependencies. But if you look in your deps folder for your project, you’ll still see a directory for UUID. If you’d like to get rid of that, you can manually delete it from the directory, or you can use the mix deps.clean uuid command in your terminal. It will determine that it’s no longer needed and remove the package’s code from your hard drive.
3.135.200.211