How to get user_id in the 'belongs_to' table

I have a schema:

defmodule Anders.Projects.Angebot do
 use Ecto.Schema
 import Ecto.Changeset

 schema "angebots" do
   ....
 field :user_id, :id

and a controller living in > anders_web > controllers > edit > angebot_controller

defmodule AndersWeb.Edit.AngebotController do
 use AndersWeb, :controller

 alias Anders.Projects
 alias Anders.Projects.Angebot

def create(conn, %{"angebot" => angebot_params}) do
  current_user = conn.assigns.current_user
  #changeset = Ecto.build_assoc(current_user, :projects, angebot_params)
  #changeset = Angebot.changeset(%Angebot{user_id: current_user.id}, post_params)

case Projects.create_angebot(angebot_params) do
  {:ok, angebot} ->
    conn
    |> put_flash(:info, "Angebot created successfully.")
    |> redirect(to: edit_angebot_path(conn, :show, angebot))
  {:error, %Ecto.Changeset{} = changeset} ->
    render(conn, "new.html", changeset: changeset)
 end
....
end

I can’t find the correct way to insert the current_user.id
Thanks for supporting my beginning…

1 Like

You can pass it inside angebot_params.

Have a look at this:

Thanks so far… as a beginner I need more understanding, can not transfer that sample into my case.
In a non immutable language like ruby it is a nobrainer:

def create
   @profile = Profile.new(profile_params)
   @profile.user_id = current_user.id

For the moment I stick to a hidden_input…as I cannot find other infos…

Assuming angebot_params is a map:

Projects.create_angebot(Map.put(angebot_params, :user_id, current_user.id)) do

Assuming it’s a list:

Projects.create_angebot([{:user_id, current_user.id} | angebot_params])

Of course your create_angebot needs to know how to deal with the additional field.

1 Like

You might also show how You cast your attributes in your changeset. Somethink like this

@required_fields ~w(name email)a

def changeset(%User{} = user, attrs \\ %{}) do
    user
    |> cast(attrs, @required_fields)
...

It acts like white listing attributes in Ruby (params…permit etc). You might allow user_id in profile changeset, although it is better to set keys through association.

Thanks I try…

angebot
    |> cast(attrs, [:title, :subtitle, :content, :online, :since, :zip, :city, :country, :user_id])
 def create(conn, %{"angebot" => angebot_params}) do
      current_user = conn.assigns.current_user
      #you can do as ruby elixir is not fully immutable. Elixir can rebound
      angebot_params = Map.put(angebot_params, "user_id", current_user.id)
     

    case Projects.create_angebot(angebot_params) do
      {:ok, angebot} ->
        conn
        |> put_flash(:info, "Angebot created successfully.")
        |> redirect(to: edit_angebot_path(conn, :show, angebot))
      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
     end
    ....
    end

Thanks…

def create(conn, %{"angebot" => angebot_params}) do
    current_user = conn.assigns.current_user
    angebot_params = Map.put(angebot_params, "user_id", current_user.id)
case Projects.create_angebot(angebot_params) do
...

throws

expected params to be a map with atoms or string keys, got a map with mixed keys: % . {:user_id => 21, "city" => "", "content" => "", "country" => "", "online" => "false", "since" => "", "subtitle" => "", "title" => "title 1", "zip" => ""}

sorry my fault… now it seems to work… Will check that… Thanks so far…

1 Like

In Elixir %{user: 1} and %{“user” => 1} are not same map.

If you have atom map you should use Map.put(map, :user_id, value)
If you have string fat arrow map Map.put(map, "user_id", value)

This is working:

angebot_params = Map.put(angebot_params, “user_id”, current_user.id)

Just try to move that in a helper…

Today we discussed in forum about user_id in changesets. This is a better approach than allowing cast :user_id in changeset
you can look post about user_id

So for your case

def create(conn, %{"angebot" => angebot_params}) do
      current_user = conn.assigns.current_user
     

    case Projects.create_angebot(angebot_params, current_user) do
      {:ok, angebot} ->
        conn
        |> put_flash(:info, "Angebot created successfully.")
        |> redirect(to: edit_angebot_path(conn, :show, angebot))
      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
     end
    ....
    end

    #lip/projects/projects.ex

    def create_angebot(attrs, %User{id: user_id}) do
      %Angebot{user_id: user_id}
      |> Angebot.changeset(attrs)
      |> Repo.insert()
    end

#lip/projects/angebot.ex
#and delete cast :user_id in changeset function
|> cast(attrs, [:title, :subtitle, :content, :online, :since, :zip, :city, :country])
2 Likes

Thanks a lot … really helpfull