6
votes

I'm currently working on a Phoenix project where I'm unsatisfied with the way I'm calling fields in the templates.

The schema is currently

defmodule MyApp.Car do
  use MyApp.Web, :model
  schema "car" do
    field :columnName, :string
  end
end

car = Repo.get!(Car, id)

I'd like to be able to call the result with car.column_name rather than car.columnName

Migrating the database isn't currently an option due to a number of applications using the database.

3
AFAIK it is not possible at this time.josemrb
I guess you could create a view and use it in your schema, thats one way to go about it but I believe it will work only with selects.NoDisplayName

3 Answers

5
votes

There is a source option for field.

:source - Defines the name that is to be used in database for this field.

defmodule MyApp.Car do
  use MyApp.Web, :model
  schema "car" do
    field :column_name, :string, source: :columnName
  end
end
1
votes

I believe this could be done Ecto's field source mapper.

defmodule MyApp.Car do
  use Ecto.Schema

  @field_source_mapper fn
    :column_name -> :columnName
    x -> x
  end

  schema "car" do
    field :column_name, :string
  end
end
0
votes

If you want an Ecto schema to use snake_case for column names that reference camelCase columns, you will need to create a view. If your view is just used to rename columns, it will be "updatable" in Postgres/MySql/Microsoft SQL Server. This means that INSERT's UPDATE's and DELETE's into the view will write to the actual table the view references.

For example, if you car table definition looks like this:

CREATE TABLE car(
   id             SERIAL PRIMARY KEY,
   modelName      VARCHAR(255),
   makeName       VARCHAR(255),
   manufacturerId INT REFERENCES manufacturer(id)
);

you can create a migration that creates a view selecting from each column with a snake_case alias name:

defmodule MyApp.Repo.Migrations.CarView do
  use Ecto.Migration

  def up do
    execute """
      CREATE VIEW my_app_car
      AS
      SELECT
          id AS id,
          modelName AS model_name,
          makeName AS make_name,
          manufacturerId AS manufacturer_id
      FROM car; 
    """
  end

  def down do
    execute "DROP VIEW my_app_car;"
  end
end

and your Ecto Schema would just need to use your view as its source ("my_app_car" instead of "car"):

defmodule MyApp.Car do
  use MyApp.Web, :model
  schema "my_app_car" do
    field :model_name, :string
    field :make_name, :string
    belongs_to :manufacturer, MyApp.Manufacturer
  end
end

You can then use your MyApp.Car Ecto schema as if its source were the original "car" table, but with the modified column names.

If you're using a database that supports schemas, (e.g. Postgres, SQL Server) you can create a separate schema for your views, instead of naming all of your ecto views "my_app_[TABLE NAME]".