Is it good practice to have a context be the plural of a schema?

Hello all,

I’m migrating my app to the new Phoenix 1.3 guidelines. It’s a really simple app and I was wondering if it’s ok to name a context the plural form of the schema ?

I have a User schema and I’m pretty sure it won’t end up with accounts and stuff. Is it ok to have the context be “users” ?

And what does this means ? def update_user(%User{} = user, attrs), do: I don’t get the %User{} = user in the params ? Is it pattern matching to ensure user is a %User{} struct ?

Thanks for your answers :slight_smile:

1 Like

From what I understand, the “purpose” of the context module is that it is an entry point for interacting with the modules/entities within that context and that it defines a clear boundary between those modules and the rest of your application. An internal API if you will.

However, since it seems that the user scheme is the only thing in that context (whose name you already have trouble coming up with!), I think it would make sense to place the User module at the root level. It is always still an option to group it together with other modules later on that belong to the same context (Authentication.User, Authentication.Registration, …).

And what does this means ? def update_user(%User{} = user, attrs), do: I don’t get the %User{} = user in the params ? Is it pattern matching to ensure user is a %User{} struct ?

It is a pattern match yes, when the function is invoked the actual value is matched against the function arguments from right to left: %User{} = user = %User{name: "robinmonjo", ...}. So it indeed also verifies the right hand side is a user struct.

(You may also directly capture fields of the struct via this syntax:)

def update_user(%User{name: name} = user, attrs)
1 Like

Thank you for your answer @thomasbrus ! It starts to make sense.

I think that I should think about the context module as an entry point for a domain of my application. So if my app handle users (persistence/schema, registration, authentication etc …) I’m free to create a “Users” context with the users.ex file exposing all the API of my domain and have as much module as I like in the “Users” context. I could have something like this:

users/
   users.ex # exposing my Users context API
   user.ex # containing the schema
   user_repo.ex # containing the changesets / validations etc ...
   auth.ex # containing logic for the auth

As for the pattern matching I was aware of the possibility to directly destructure the parameter, but it was weird to see this %User{} = user because it doesn’t destructure any values so I didn’t see how %User{} = user is “better” than just user. But it makes sense now:

defmodule Test do                   
   def func(%{} = m), do: IO.inspect(m)
end
Test.func("hello") # no function clause matching
Test.func(%{test: "test"}) # ok

So it’s more than just destructuring it’s “nested” pattern matching :slight_smile:

2 Likes