Like / Follow / Vote in Phoenix (Elixir) Web App using Votex
Functionality made simple with a plug and play library.
“Like a photo”, “Up-vote response” or “Follow user” come under a basic set of operations one needs in every other web project. Managing a separate entity or handling the execution within the specific models can be a never ending debate. It is smart to leave external libraries take care of these rudimentary tasks while your focus should be on core activities.
Let’s demonstrate a simple blogger app. Start with creating an empty Phoenix project
mix phx.new blogger --no-brunch
cd blogger
It will create a boilerplate code base to start development with. Type “Y” to proceed installing dependencies.
Before creating a database, you need to change the config file so that it has the access to database.
nano config/dev.exsconfig :blogger, Blogger.Repo,
adapter: Ecto.Adapters.Postgres,
username: "Your DB Username",
password: "Your DB Password",
Now, it is time to create the database and run the development server.
mix ecto.create
mix phx.server
On browsing http://localhost:4000, you’ll be greeted with the following screen.
Let’s quickly generate some models with the help of generators and migrate.
mix phx.gen.schema Blog blogs title:string views:integer
mix phx.gen.schema Team teams name:string category:string
mix phx.gen.schema User users username:string age:integermix ecto.migrate
Having three models at our disposal, we can play around for a while
iex -S mix # Start Interactive Elixir Shell%Blogger.User{username: "alex01", age: 25} |> Blogger.Repo.insert%Blogger.Blog{title: "Elixir on Phoenix", views: 0} |> Blogger.Repo.insert%Blogger.Team{name: "FYYT", category: "Football Players"} |> Blogger.Repo.insert
Add Votex as a dependency in root project and configure it
defp deps do [
{:votex, "~> 0.3.0"}
]
end
config/config.exs
config :votex, Votex.DB,
repo: Blogger.Repo
Install the newly included dependency and run migration
mix deps.get
mix votex.gen.migration
mix ecto.migrate
Modify the schema files of Ecto, which will expose the votable functions. The goal is to make Blog likeable by either a User or a Team.
In short,
User is a voter
Team is a voter
Blog is votable
lib/blogger/user.ex
defmodule Blogger.User do
use Votex.Voter # Add this line
end
lib/blogger/team.ex
defmodule Blogger.Team do
use Votex.Voter
end
lib/blogger/blog.ex
defmodule Blogger.Blog do
use Votex.Votable
end
Finally the magic methods can be executed now
iex -S mix # Shellalias Blogger.{User, Blog, Team, Repo}user = Repo.all(User) |> Enum.at(0)
blog = Repo.all(Blog) |> Enum.at(0)
team = Repo.all(Team) |> Enum.at(0)blog |> Blog.vote_by user
# {:ok, %Votex.Vote{}}user |> User.voted_for? blog
# trueblog |> Blog.votes_for |> length
# 1blog |> Blog.unvote_by user
# {:ok, %Votex.Vote{}}user |> User.voted_for? blog
# false
Voter details can be fetched from blog
blog |> Blog.votes_for |> Enum.map(fn vote -> vote.voter end)[
%Blogger.Team{
__meta__: #Ecto.Schema.Metadata<:loaded, "teams">,
category: "Football Players",
id: 1,
inserted_at: ~N[2018-09-01 20:06:46.827705],
name: "FYYT",
updated_at: ~N[2018-09-01 20:06:46.827720]
},
%Blogger.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
age: 25,
id: 1,
inserted_at: ~N[2018-09-01 19:49:40.815278],
updated_at: ~N[2018-09-01 19:49:40.818200],
username: "alex01"
}
]
Votex can also be used for self referential voting, e.g. A user can follow another user. Just need to declare User as votable too.
lib/blogger/user.ex
defmodule Blogger.User do
use Votex.Voter
use Votex.Votable
end
Now a user can also follow another user
user1 = user{_, user2} = %User{username: "brian17", age: 20} |> Repo.insertuser2 |> User.vote_by user1
# {:ok, _}
user1 |> User.votes_for[
%{
__meta__: #Ecto.Schema.Metadata<:loaded, "votex_votes">,
__struct__: Votex.Vote,
id: 4,
inserted_at: ~N[2018-09-01 20:24:59.768915],
updated_at: ~N[2018-09-01 20:24:59.768942],
votable_id: 3,
votable_type: "users",
voter: %Blogger.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
age: 25,
id: 1,
inserted_at: ~N[2018-09-01 19:49:40.815278],
updated_at: ~N[2018-09-01 19:49:40.818200],
username: "alex01"
},
voter_id: 1,
voter_type: "users"
}
]
That’s all for now. I hope this covers majority of the use cases an app might need. I also happen to be the creator of Votex so would appreciate feedback. You can check out Votex at Github. It is directly inspired from Acts as Votable in Ruby. Please do clap if you find this useful.
AVIACOMMERCE: OPEN SOURCE E-COMMERCE
Aviacommerce is an open source e-commerce framework with an aim to simplify e-commerce ecosystem by creating and unifying smart services and providing consistent, cost-effective solution to sellers helping them sell more. visit aviacommerce.org to know more.