Struggling With Schema and Seeding Issue

** Just edited the scrips to corrected the wrong way associations I had and tried a different approach to the seed file. The error I am getting now is…

15:50:15.441 [info] create table locations
** (Postgrex.Error) ERROR 42P01 (undefined_table) relation “stations” does not exist

After reading through some books and tutorials I have setup a Phoenix app using Ecto and am struggling with a has_one, belongs_to association. I have Stations, which each have strings I would like to use as station ids.
Each location has one or no station, but each station may have multiple locations.

When I try to seed the database I get an error “** (ArgumentError) unknown field :location_id in %TestApp.Weather.Station”

Station Schema

defmodule TestApp.Weather.Station do
  use Ecto.Schema
  import Ecto.Changeset

  @primary_key {:id, :string, []}
  @derive {Phoenix.Param, key: :id}
  @timestamps_opts [type: :utc_datetime]

  schema "stations" do
    field :latitude, :float
    field :longitude, :float
    field :name, :string

    has_many :locations, TestApp.Weather.Location

    timestamps()
  end

  def changeset(station, attrs) do
    required_fields = [:latitude, :longitude, :name]

    station
    |> cast(attrs, required_fields)
    |> validate_required(required_fields)
  end

end

Location Schema

defmodule TestApp.Weather.Location do
  use Ecto.Schema
  import Ecto.Changeset
  @timestamps_opts [type: :utc_datetime]

  schema "locations" do
    field :latitude, :float
    field :longitude, :float
    field :name, :string

    belongs_to :station, TestApp.Weather.Station

    timestamps()
  end

  def changeset(location, attrs) do
    required_fields = [:latitude, :longitude, :name]
    optional_fields = [:station_id]

    location
    |> cast(attrs, required_fields ++ optional_fields)
    |> validate_required(required_fields)
    |> assoc_constraint(:station)
  end

end

Location Migration

defmodule TestApp.Repo.Migrations.CreateLocations do
  use Ecto.Migration

   def change do
    create table(:locations) do
      add :latitude, :float, null: false
      add :longitude, :float, null: false
      add :name, :string, null: false
      add :station_id, references(:stations)

      timestamps()
    end

    create unique_index(:locations, [:name])
  end
end

Station Migration

defmodule TestApp.Repo.Migrations.CreateStations do
  use Ecto.Migration

 def change do
    create table(:stations, primary_key: false) do
      add :id, :string, primary_key: true
      add :latitude, :float, null: false
      add :longitude, :float, null: false
      add :name, :string, null: false

      timestamps()
    end

    create unique_index(:stations, [:name])
  end
end

Seed File

alias TestApp.Repo
alias TestApp.Weather.{Location, Station}

    station1 = %Station{
      id: "USC00012209",
      latitude: 34.5569,
      longitude: -86.9503,
      name: "DECATUR 5SE",
    }

    location1 = %{
      latitude: 34.7998,
      longitude: -87.6773,
      name: "Florence, AL"
    }

    %Location{}
    |> Location.changeset(location1)
    |> Ecto.Changeset.put_assoc(:station, station1)
    |> Repo.insert()


If each station can have many locations, it seems this should be has_many :locations

also add :location_id, references(:locations) should be removed to Location should have add :station_id references(:stations)

Also belongs_to should be singular, not plural.

Location should have a station_id, not the reverse

It does not work like this, You would need to use put_assoc or cast_assoc in the changeset

You are right, think my brain got twisted up on this one for some reason. I just updated the code with the associations switched.

Thank you. I just made the switch and edited my original post.

This part of the location migration file I think might need additional arguments as :station_id is a string not a regular auto created id? The error I am now getting is
15:50:15.441 [info] create table locations
** (Postgrex.Error) ERROR 42P01 (undefined_table) relation “stations” does not exist

add :station_id, references(:stations)

You need the migration to be in order… stations needs to be created before locations (Just change the timestamp in the name of the migration, to get the order right)

Thank you so much for your help today, you were right, the order was wrong!

I also found I had to do two more things to get it all working.

In the schema

belongs_to :station, TestApp.Weather.Station, [foreign_key: :station_id, type: :string]

In the migration

 add :station_id, references(:stations, type: :string)

Hopefully helpful for someone else who uses a string id in the future.