chrisdel101

chrisdel101

When adding two foreign keys using has_many only one is getting added

I have a Role like this in DB. It is attached to both a organization and a employee. But I cannot get both fields organization_id && employee_id to populate. This what it looks like after inserting an employee and an organization.


 id | name  | value | organization_id | employee_id |    
----+-------+-------+-----------------+-------------+-
 21 | owner | 1     |              |          24     |

Modeling


  schema "employees" do
    has_many :roles, Role

  schema "organizations" do
    has_many :roles, Role

  schema "roles" do
    belongs_to :employee, Employee, foreign_key: :employee_id
    belongs_to :organization, Organization, foreign_key: :organization_id

 create table(:roles) do
      add :organization_id, references(:organizations)
      add :employee_id, references(:employees)

The problem is not with the modelling but with the actual insertion.
Here what I’ve tried but it’s not working. I always get the table at the top w/ a missing FK.

I try to

  • associate the employee with the role then update the employee,
  • associate the role itself with an organization and then update the org.
  • Missing: associating the org with the role and upate the org.

Note: this is a bunch of random stuff trying to make the associations take. I know it’s not pretty.


def register_and_preload_employee(attrs) do
  # build a role instance
    role = Role{
      name: "owner",
      value: "1"
    }
    
    # build employee changeset
    emp_changeset = Employee.registration_changeset(%Employee{}, attrs)
    # assoc role with employee
    emp_changeset = Ecto.Changeset.put_assoc(emp_changeset, :roles, [role])
         #role is inserted
  # Ecto.Changeset<
  #   action: nil,
  #   changes: %{
  #     email: "...
  #   ...
  #     roles: [
  #       #Ecto.Changeset<action: :insert, changes: %{}, errors: [],
  #        data: #Role<>, valid?: true>
  #     ]
  #   },
  #   errors: [],
  #   data: #Employee<>,
  #   valid?: true
  # >
    # get org and build_assoc foreign key
    organization_id = 1
    # get org and preload roles
    organization = Company.get_organization(organization_id) |> Repo.preload(:roles)
    # ATTEMPT to build assoc with org and role
    role_w_org = Ecto.build_assoc(organization, :roles, role)
    #  org is loaded into role
    # %Role{
    #   __meta__: #Ecto.Schema.Metadata<:built, "roles">,
    #   id: nil,
    #   name: "owner",
    #   value: "1",
    #   employee_id: nil,
    #   employee: #Ecto.Association.NotLoaded<association :employee is not loaded>,
    #   organization_id: 1,
    #   organization: #Ecto.Association.NotLoaded<association :organization is not loaded>,
    #   inserted_at: nil,
    #   updated_at: nil
    # }
    
    # insert employee
    case Repo.insert(emp_changeset) do
      {:ok, new_emp} ->
     #preload in case required
        emp_preload =
          Repo.preload(new_emp, :organizations)
          |> Repo.preload(:roles)
        # ATTEMPT  build assoc with org and role
        role_loaded =  Ecto.build_assoc(emp_preload, :roles, role_w_org)
        # both foreign keys here
        # %TurnStile.Role{
        #   __meta__: #Ecto.Schema.Metadata<:built, "roles">,
        #   id: nil,
        #   name: "owner",
        #   value: "1",
        #   employee_id: 24,
        #   employee: #Ecto.Association.NotLoaded<association :employee is not loaded>,
        #   organization_id: 1,
        #   organization: #Ecto.Association.NotLoaded<association :organization is not loaded>,
        #   inserted_at: nil,
        #   updated_at: nil
        # }
        # try to update role via employee update - role_loaded is not holding
        update = update_employee(emp_preload)  #-> Repo.update(...)
        #AND/OR
        # try to update role via organization update since it's preloaded
       update_organization(organization) #-> Repo.update(...)
    
    end
  end

I guess maybe my issue is not understanding where the “child” actually gets inserted (not just in elixir, but in any FK relationship). Since the child Role is not actually inserted by me.

Marked As Solved

al2o3cr

al2o3cr

There’s no need to give up, things aren’t THAT bad! :slight_smile:

You will always get better results with questions about Ecto if you are specific about what you are trying to do. In particular, this is important:

This specific task is alternatively phrased as “I want to insert an employee and also create a role associated to an existing organization”, which then translates to Ecto operations:

organization = get_the_org_somehow()

role = Ecto.build_assoc(organization, :roles, %{"name" => "owner", etc})
# role is unsaved and has an organization_id but no employee_id

employee_changeset =
  %Employee{}
  |> Employee.registration_changeset(attrs)
  |> Ecto.Changeset.put_assoc(:roles, [role])
# changeset contains an unsaved Employee with one unsaved Role

result = Repo.insert(employee_changeset)

You might also refactor this to make Employee.registration_changeset take an Organization and do the put_assoc there, to keep things tidy.

Also Liked

al2o3cr

al2o3cr

What do you mean by “role_loaded is not holding” here? There’s no connection between emp_preload and role_loaded.

It’s hard to say with certainty without the code for these, but neither one takes role_loaded as an argument so it’s not going to have an effect on them.

What happens if you do Repo.insert(role_loaded)?

Where Next?

Popular in Questions Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New

Other popular topics Top

vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 53690 245
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30877 112
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New

We're in Beta

About us Mission Statement