Search code examples
elixirphoenix-frameworkecto

Ecto - automatically capitalizing fields


I have an ecto model named Company which has an name field. What I want is before inserting or updating a company in the database is to apply String.capitalize to the name attribute. These are the create and update functions of CompanyController:

def create(conn, %{"company" => company_params}) do
  case Company.insert(conn.assigns.current_user, company_params) do
    {:ok, _company} ->
      redirect(conn, to: company_path(conn, :index))

    {:error, changeset} ->
      render(conn, "new.html", changeset: changeset)
  end
end
def update(conn, %{"id" => company_id, "company" => company_params}) do
  company = Company.get(company_id)

  case Company.update(company, company_params) do
    {:ok, _company} ->
      redirect(conn, to: company_path(conn, :show, company))

    {:error, changeset} ->
      render(conn, "edit.html", company: company, changeset: changeset)
  end
end

Solution

  • It can be done simply by using Map.update! function, either in a separate function of a controller:

    def create(conn, %{"company" => company_params}) do
      case Company.insert(conn.assigns.current_user, with_capitalized_name(company_params)) do
        {:ok, _company} ->
          redirect(conn, to: company_path(conn, :index))
    
        {:error, changeset} ->
          render(conn, "new.html", changeset: changeset)
      end
    end
    
    def update(conn, %{"id" => company_id, "company" => company_params}) do
      company = Company.get(company_id)
    
      case Company.update(company, with_capitalized_name(company_params)) do
        {:ok, _company} ->
          redirect(conn, to: company_path(conn, :show, company))
    
        {:error, changeset} ->
          render(conn, "edit.html", company: company, changeset: changeset)
      end
    end
    
    def with_capitalized_name(company_params)
      Map.update!(company_params, "name", &String.capitalize/1)
    end
    

    Or in a function which is used for casting and validating params (usually called changeset):

    def changeset(company, attrs) do
      company
      |> cast(attrs, [:name])
      |> capitalize(attrs, :name)
    end
    
    defp capitalize(_, attrs, field) do
      Map.update!(attrs, field, &String.capitalize/1)
    end