Safely modify records

Safely modify records.

Good afternoon, I’m new to elixir.

I have a question - how to safely modify records?

Let’s say I have a user and articles.

The script is like this:

  1. The user is authenticated and authorized.
  2. The user wants to change his article.
  3. We have an HTML form in which the article is loaded.
  4. A cunning user can change the article ID in the form and change any article.

The question is how to avoid this?

I think it is possible to check that the article belongs to the user. Am I right?

Yes, you can do this either in a controller or a liveview, with something such as:

  def edit(conn, %{"id" => id}) do
    with article <- Articles.get_article!(id),
         true <- article.user_id == conn.assigns.current_user.id do
      # do the update
    end
  end

You can also abstract this to a module, such as Authorization, and have functions like:

def authorize(%User{id: user_id}, :edit, %Article{user_id: user_id}), do: true
def authorize(%User{}, :edit, %Article{}), do: false

I get what this does but what kind of dark magic is going on here. Hoping you can explain these lines… .typically I expect something like if user1 is member of (allowed list), user1 can edit/do xyz. Still getting used to this syntax. thx.

FWIW, the with syntax is just one way to do it :slight_smile:

This is perfectly acceptable also:

def edit(conn, %{"id" => id}) do
  # This probably raises an error if no article matches? If not, you'd need more conditionals
  article = Articles.get_article!(id) 

  if article.user_id == conn.assigns.current_user.id do
    # do the update
  else
       
  end
end
1 Like

Yeah of course. As zachdaniel said above, they’re just different ways of writing things. The authorize function could also be written like so:

def authorize(user, action, article) do
  case action do
    :edit -> user.id == article.user_id
    _ -> false
  end
end

It checks that the current user who is trying to do something with the article is the owner of that article.

def authorize(%User{id: user_id}, :edit, %Article{user_id: user_id}), do: true

This line does exactly the same, but utilizes pattern matching and destructuring in the function head.