Rust with Docker and Visual Studio Code

1. Install Rustup

Install rustup – installer for the systems programming language Rust.

If you don’t want to install rustup using script obtained using curl, you can use my Docker image which contains installed rustup:

$ docker image pull h00s/rustup

Create directory where Rust toolchain will be located:

$ mkdir $HOME/.rustup

2. Install Rust toolchain

Using rustup Docker image, install toolchain (on GNU Linux):

$ docker container run --rm --user "$(id -u)":"$(id -g)" -v $HOME/.rustup:/.rustup h00s/rustup /usr/bin/rustup install stable-x86_64-unknown-linux-gnu

Add $HOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin to PATH.

3. Install components

$ docker container run --rm --user "$(id -u)":"$(id -g)" -v $HOME/.rustup:/.rustup h00s/rustup /usr/bin/rustup component add rls

$ docker container run --rm --user "$(id -u)":"$(id -g)" -v $HOME/.rustup:/.rustup h00s/rustup /usr/bin/rustup component add rust-src

$ docker container run --rm --user "$(id -u)":"$(id -g)" -v $HOME/.rustup:/.rustup h00s/rustup /usr/bin/rustup component add rust-analysis

4. Configure VSCode for Rust

Install Rust Extension to VSCode. Make sure you added toolchain bin directory to PATH.

Add this to VSCode settings.json:

"rust-client.trace.server": "messages",
"rust-client.disableRustup": true,

Relative time in Phoenix

In my last project I’m writing in Phoenix, I needed to display relative time on insertion time, something like time_ago_in_words in Rails. As such function doesn’t exist in Phoenix framework, I wrote it myself.

First, I wrote a seconds_ago  view function so I can get how many seconds has passed from inserted Ecto.DateTime  to current time:

[code lang="elixir"]
def seconds_ago(datetime) do
  :calendar.datetime_to_gregorian_seconds(:calendar.local_time()) - :calendar.datetime_to_gregorian_seconds(Ecto.DateTime.to_erl(datetime))
end
[/code]

When I have information how many seconds has passed, I can calculate relative time and output it as text:
def time_ago_in_words(seconds) when seconds < 60 do
  "#{seconds} second(s) ago"
end
def time_ago_in_words(seconds) when seconds < 3600 do
  "#{round(seconds/60)} minute(s) ago"
end
def time_ago_in_words(seconds) when seconds < 86400 do
  "#{round(seconds/3600)} hour(s) ago"
end
def time_ago_in_words(seconds) do
  "#{round(seconds/86400)} day(s) ago"
end

To display relative time in template, it’s simple as this:

<%= model.inserted_at |> seconds_ago |> time_ago_in_words %>

UPDATE: Here you can get better version of  time_ago_in_words  which acts like the one in Rails.

Setting page title in Phoenix

In Rails, you probably used content_for  for setting every page title. In Phoenix, layout is rendered before page template is rendered so content_for  approach will not work. Instead, here’s how you can set different page title for every action.

In layout_view.ex file, add get_page_title  function:

def get_page_title(conn) do
  if conn.assigns[:page_title] do
    "#{conn.assigns[:page_title]} - ApplicationName"
  else
    "ApplicationName"
  end
end

Continue reading