Using eWebmachine to create a link shortener (part 4)
Posted on October 21, 2014 by Clive in Elixir, eWebmachine, Mustache
In the previous posts, we have been using the temporary Erlang Term Storage or ETS to store the data. As this is an in-memory store, any data that is stored is lost whenever the application is stopped. In this post, we will look to change this and make the data persist between application restarts. To do this we will be using Disc-backed Erlang Term Storage - DETS. This writes the data to a specified file on the disc. For this application using DETS is fine as the data requirements are very small. Should this site take off, then I would recommend using Mnesia.
All changes will be made in lib/shorten_url_srv.ex as this is where the data is stored. The first thing that we’ll do is add a new Module attribute as a constant towards the top of the module: The next thing that will need to happen is setting up the file, this is handled in the init/1 function. Here we ensure that the file is present, if not then the DETS engine creates the file for us. Next up, we need to change the handlers: Lastly, we need to fix the do_lookup/1 function: To test, run the application: and add in some test data for now: Navigate to http://localhost:18080/latest and you should see the link displayed. Now restart the application, and then reload the page. It should still display the stored link. Job Done @dets_file "shorten_urls.dets"
def init(_) do
{:ok, ref} = :dets.open_file(@tab, [file: @dets_file, type: :bag])
:dets.close(ref)
{:ok, %St{next: 0} }
end
def handle_call({:get_url, id}, _from, state) do
{:ok, ref} = :dets.open_file(@tab)
reply = case :dets.lookup(ref, "#{id}") do
[] -> {:error, :not_found}
[{_id, url}] -> {:ok, url}
end
{:reply, reply, state}
end
def handle_call({:put_url, url}, _from, %St{next: n} = state) do
id = ShortenUrlSrv.b36_encode(n)
{:ok, ref} = :dets.open_file(@tab)
:dets.insert(ref, {id, url})
{:reply, {:ok, id}, %St{next: n+1}}
end
defp do_lookup(id) do
{:ok, ref} = :dets.open_file(@tab)
record = case :dets.lookup(ref, id) do
[] -> {:error, :not_found}
[record] -> record
end
record
end
$ iex -S mix
iex> ShortenUrlSrv.put_url('http://www.distortedthinking.agency')
[{"0", 'http://www.distortedthinking.agency'}]