Unleashing Efficiency: Building an Advanced Library Management System with Phoenix
Welcome, dear friends! Today, we embark on an exciting journey as we delve into the realm of software development and create a remarkable library management system using Phoenix. In this incredible adventure, we will not only organize and manage a collection of books but also explore the fascinating world of reviews associated with each book. So fasten your seatbelts and get ready to witness the birth of a sophisticated system that will revolutionize the way libraries operate. Together, we shall harness the power of Phoenix to craft a remarkable solution that will streamline the process of book management and enhance the reading experience for all. Let’s embark on this thrilling endeavor and unlock the potential of our library management system with Phoenix!
To get started.
mix phx.new library_management
Configure your database to allow you to create a database.
This will be done in the config/dev.exs .
Run
mix ecto.migrate
to create your database.
We now Generate models, views, and Controller for the books using the mix phx.gen.html command
mix phx.gen.html Books Book books title:string isbn:integer publication_date:date
This generates a book model with fields of a title, isbn and publication_date
Add the resource to your browser scope in lib/library_management_web/router.ex:
resources “/books”, BookController
Change the root route from
get "/", PageController, :index
to
get "/", BookController, :index
Run
mix ecto.migrate
You can now run the server and see what we have
mix phx.server
Now when we go to localhost:4000 , we see the following
You can now add a book!
When you click on New Book you will be redirected to a form where you can add a book, after adding the book, you will be redirected to the show page of the book as below
It would be more ideal if we were redirected back to the root page after adding a new book , to do this we will change the code in our book_controller .
Inside lib/library_management_web/controllers/book_controller.ex
Inside the create action/function, look for this line of code
|> redirect(to: Routes.book_path(conn, :show, book))
And replace it with
|> redirect(to: Routes.book_path(conn, :index))
Now if you add a new Book , you are redirected back to its index page .
You can also do the same for the update action/function.
We can now add a few Books to our application.
We have already added a model with the Books , for the application to the complete, we will be adding Reviews for each book .
Each review will have a name and content .
A book will have many reviews and a review will belong to a book.
To create this , we will use the phx.gen.context Command .
Run
mix phx.gen.context Reviews Review reviews name:string content:string book_id:references:books
This will create a reviews table with a name , content and book_id column .
- We have to define the relationships discussed above into our code ie
(a book has many reviews and a review belongs to a book)
To do this , go to lib/library_management/books/book.ex and in the schema , after the last field , add
has_many(:reviews, LibraryManagement.Books.Review)
And now in lib/library_management/reviews/review.ex and in the schema , remove this line
field :book_id, :id
And replace it with
belongs_to(:book, LibraryManagement.Books.Book)
Now , let us configure a route that will allow us to make reviews for a certain book , to do this , We will use nested routes .
Open lib/library_management_web/router.ex and replace
resources "/book", BookController
with
resources "/book", BookController do
post "/review", BookController, :add_a_review
end
Open your terminal and type .
mix phx.routes
We now have a new route books/:id/reviews where we can post our comment .
A closer look at this line of code
post "/review", BookController, :add_a_review
We see that it is a post request to the route “/books/:id/review , it points to the BookController and to the create_review action inside the book_controller.ex
Let us navigate to lib/library_management_web/controllers/book_controller.ex .
Here we will add the following action/ function
def add_a_review(conn, %{"review" => review_params, "book_id" => book_id}) do
book =
book_id
|> Books.get_book!()
|> Repo.preload([:reviews])
case Books.add_review(book_id, review_params) do
{:ok, _review} ->
conn
|> put_flash(:info, "review added :)")
|> redirect(to: Routes.book_path(conn, :show, book))
{:error, _error} ->
conn
|> put_flash(:error, "review not added :(")
|> redirect(to: Routes.book_path(conn, :show, book))
end
end
at the case , we have a method called add_review that takes in a book_id and the params for a review .
To be able to access the methods in the reviews model , make sure to add these at the top of book_controller.ex
alias LibraryManagement.Reviews.Review
alias LibraryManagement.Reviews
alias LibraryManagement.Repo
In Phoenix , we break everything in modules , if you look at the index action , you will see it calls a function list_books() that is imported from the Book model file in lib/library_management/books/books.ex .
We write smaller methods in the model file then use them in the controller file .
Let us define the add_review function that we have used in the controller .
We shall do this in the Book model file lib/library_management/books/books.ex
Add this to access the method that we will use to create a comment imported from lib/library_management/reviews.ex — the method we are importing is create_review
- Add this on top of lib/library_management/books.ex , add this so as to access the create_review method inside the book module
alias LibraryManagement.Reviews
And the add_review method as follows
def add_review(book_id, review_params) do
review_params
|> Map.put("book_id", book_id)
|> Reviews.create_review()
end
Next, we are going to implement a simple Add Review
form and add it to the page that displays a single post. For that to happen, we need to modify the show action in the post controller. We are going to add the Review.changeset
and pass it to the show.html
template.
def show(conn, %{"id" => id}) do
book =
id
|> Books.get_post!
|> Repo.preload([:reviews])
changeset = Review.changeset(%Review{}, %{})
render(conn, "show.html", book: book, changeset: changeset)
end
After that we are going to create a new review_form.html.heex
template that will be used to enter and save comment data.
This will be inside the lib/library_management_web/templates/book
create the file and add
<%= form_for @changeset, @action, fn f -> %>
<div class="form-group">
<label>Name</label>
<%= text_input f, :name %>
</div>
<div class="form-group">
<label>Content</label>
<%= textarea f, :content %>
</div>
<div class="form-group">
<%= submit "Add Review" %>
</div>
<% end %>
Lastly, we need to add the review_form.html.heex
template to the show.html.heex
and make sure to pass it the correct data:
<%= render "review_form.html", book: @book, changeset: @changeset, action: Routes.book_book_path(@conn, :add_a_review, @book) %>
Before we can try this live , let us go back to our model schema for reviews and ensure that we allow book_id as one of the params .
We do this in lib/library_management/reviews/review.ex
Change the changeset function to
def changeset(review, attrs) do
review
|> cast(attrs, [:name, :content, :book_id])
|> validate_required([:name, :content, :book_id])
end
Now we can add a new Review at the show page of each book
To view the comments on the show page of the book
Navigate to lib/lib_management_web/templates/book/show.html.heex
and at the bottom add
<%= for review <- @book.reviews do %>
<div class="review">
<p>Name of reviewer:<%= review.name %> </p>
<p>Content: <%= review.content %></p>
</div>
<% end %>
Now , we can see the reviews for each book
In conclusion, we’ve embarked on an exciting journey to create a library management system with Phoenix. By leveraging this powerful framework, we’ve revolutionized the way libraries operate, incorporating book reviews to enhance the reading experience and foster a sense of community. To explore the full implementation, documentation, and resources, visit our GitHub repository at [https://github.com/MICHAELMUNAVU83/library_management_phoenix]. Let’s continue pushing the boundaries of library management systems and inspire a love for books that knows no bounds. Happy coding, friends!