Questions about the way ecto is used in event.ex

Hi all,

I am trying to understand the way Mobilizòn uses the ecto changeset facility, and I have some questions about design decisions made, etc. Is there anybody left on the project who was around when those decisions were made?

Specifically I find myself wondering why change/2 was used rather than cast/2 on what is clearly external data. Is the data validated elsewhere, making the cast/2 validation redundant?

Anyway, I’d very much like to improve my understanding of why these decisions were taken, and so if it’s documented somewhere or if somebody remembers it would be wonderful.

Best,

Mark

Hi,

Could you pinpoint where change/2 is used? Mobilizon.Events.Event uses cast/2 from what I can see.

Indeed it does. I was looking in the wrong place.

But this leaves me with another mystery. For some reason calling the updateEvent mutation with an existing picture attribute (the unchanged picture from before by mediaId) throws this error:

defp raise_if_updating_with_struct!(%{field: name, owner: owner}, %{__struct__: _} = new) do
    raise """
    you have set that the relation #{inspect name} of #{inspect owner}
    has `:on_replace` set to `:update` but you are giving it a struct/
    changeset to put_assoc/put_change.

    Since you have set `:on_replace` to `:update`, you are only allowed
    to update the existing entry by giving updated fields as a map or
    keyword list or set it to nil.

    If you indeed want to replace the existing #{inspect name}, you have
    to change the foreign key field directly.

    Got: #{inspect new}
    """
  end

I suppose being a bit less used to functional programming I must be reading this wrong, but I thought that would be unreachable with a cast/2 call.

Anyway, @tcit sorry about the noise.

Here’s the error, including a stacktrace:

Apr 20 10:47:07 mobilizon mobilizon[602880]: 10:47:07.525 request_id=GDgBENVUUR_lBSoHXLiB user_id=128 actor_name=@concertcloud [error] GenServer #PID<0.6>
Apr 20 10:47:07 mobilizon mobilizon[602880]: ** (RuntimeError) you have set that the relation :picture of Mobilizon.Events.Event
Apr 20 10:47:07 mobilizon mobilizon[602880]: has `:on_replace` set to `:update` but you are giving it a struct/
Apr 20 10:47:07 mobilizon mobilizon[602880]: changeset to put_assoc/put_change.
Apr 20 10:47:07 mobilizon mobilizon[602880]: Since you have set `:on_replace` to `:update`, you are only allowed
Apr 20 10:47:07 mobilizon mobilizon[602880]: to update the existing entry by giving updated fields as a map or
Apr 20 10:47:07 mobilizon mobilizon[602880]: keyword list or set it to nil.
Apr 20 10:47:07 mobilizon mobilizon[602880]: If you indeed want to replace the existing :picture, you have
Apr 20 10:47:07 mobilizon mobilizon[602880]: to change the foreign key field directly.
Apr 20 10:47:07 mobilizon mobilizon[602880]: Got: %Mobilizon.Medias.Media{__meta__: #Ecto.Schema.Metadata<:loaded, "medias">, id: 18291, file: %Mobilizon>
Apr 20 10:47:07 mobilizon mobilizon[602880]:     (ecto 3.11.1) lib/ecto/changeset/relation.ex:279: Ecto.Changeset.Relation.raise_if_updating_with_struct!>
Apr 20 10:47:07 mobilizon mobilizon[602880]:     (ecto 3.11.1) lib/ecto/changeset/relation.ex:333: Ecto.Changeset.Relation.single_change/6
Apr 20 10:47:07 mobilizon mobilizon[602880]:     (ecto 3.11.1) lib/ecto/changeset/relation.ex:173: Ecto.Changeset.Relation.change/3
Apr 20 10:47:07 mobilizon mobilizon[602880]:     (ecto 3.11.1) lib/ecto/changeset.ex:1885: Ecto.Changeset.put_change/7
Apr 20 10:47:07 mobilizon mobilizon[602880]:     (ecto 3.11.1) lib/ecto/changeset.ex:2131: Ecto.Changeset.put_relation/5
Apr 20 10:47:07 mobilizon mobilizon[602880]:     (mobilizon 5.1.0) lib/mobilizon/events/event.ex:173: Mobilizon.Events.Event.common_changeset/2
Apr 20 10:47:07 mobilizon mobilizon[602880]:     (mobilizon 5.1.0) lib/mobilizon/events/event.ex:159: Mobilizon.Events.Event.update_changeset/2
Apr 20 10:47:07 mobilizon mobilizon[602880]:     (mobilizon 5.1.0) lib/mobilizon/events/events.ex:285: Mobilizon.Events.update_event/2

This results when I call the updateEvent mutation with the following variables:

{"attributedToId":"73091","beginsOn":"2025-05-07T20:00:00+02:00","category":"FILM_MEDIA","description":"Jusqu’à ce que la dignité devienne une habitude, documentaire de Pik polychrom, Suisse, Chili, 2025\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003eProjection en présence des  réalisateur.ices.s, suivie d’une discussion. \u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003eChili 2025. En octobre, 6 années se seront écoulées depuis la Révolte. Le gouvernement Boric arrive au terme de son mandat. De nombreux prisonniers, activistes de l’Estallido Social restent emprisonnés. Les victimes de traumatismes oculaires continuent de se suicider. Les Mapuche souffrent toujours plus de la répression de l’Etat et les entreprises transnationales continuent de détruire impunément leurs territoires. Les espaces de mémoire sont un à un effacés, et la Révolte n’est plus qualifiée de « sociale » mais de « criminelle » par les tenants du pouvoir.\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003eNéanmoins, si les lieux peuvent être détruits, les souvenirs et les aspirations à une vie digne ne peuvent pas l’être. Et une question demeure alors: comment la dignité peut-elle devenir une habitude ?\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003eINFOS pratiques\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003eBar ouvert et empanadas à 19h00Projection à 20hÂge légal : (16)Âge suggéré : (16)\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003eEmpanadas: Nous avons la chance de proposer des empanadas argentines faites maison de grande qualité! Soit à la viande soit napolitaine (végétarienne: tomate, mozzarella, olives) pour CHF5.- / pièce accompagnée d’une délicieuse sauce.\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003eVisions du nouveau Monde\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003e\u003c/p\u003e\u003cp\u003eDepuis plus de 15 ans, Visions du Nouveau Monde est un cycle de projections de films d’Amérique du Sud et d’Amérique Centrale avec un accent sur des œuvres inédites ou peu distribuées en Suisse romande. Les projections ont lieu les mercredis, plusieurs fois par mois au Centre socioculturel Pôle Sud. Ponctuellement des réalisateurs et réalisatrices ou des associations travaillant sur les thématiques abordées dans les films sont invités pour discuter avec le public. \u003cp/\u003e\u003cp\u003e Help promote your favourite venues with: https://concertcloud.live/contribute","draft":false,"endsOn":"2025-05-07T22:00:00+02:00","externalParticipationUrl":"https://polesud.ch/evenement/hasta-que-la-dignidad-se-haga-costumbre/","id":"16476","joinOptions":"EXTERNAL","onlineAddress":"https://polesud.ch/evenement/hasta-que-la-dignidad-se-haga-costumbre/","options":{"commentModeration":"ALLOW_ALL","showStartTime":true,"showEndTime":false,"timezone":"Europe/Zurich"},"organizerActorId":"65691","physicalAddress":{"id":0,"description":"Pôle Sud","locality":"Lausanne","postalCode":"1003","street":"3 Avenue Jean-Jacques Mercier","country":"Switzerland","region":"Vaud","geom":"6.629243540056818;46.52036095"},"picture":{"mediaId":"18517"},"tags":["Pôle Sud","Lausanne"],"title":"Hasta que la dignidad se haga costumbre - film","visibility":"PUBLIC"}

Now, if I omit the "picture" struct from the json variables, and the query it does work, but it deletes any existing picture.

What I would really like to see is the possibility to send a minimal changeset with just those variables that change somehow. That’s why I started digging into events.ex and event.ex. I understand now that I was reading the code there wrong.

So my strategy is this: I’m going to go through a basic ecto tutorial this weekend, to try to understand better how it works, and what it can do and can’t do. Then I’ll come back to this.