Reputation: 2391
I'm learning Elixir/Phoenix on a sample project and started with Phoenix 1.2. Now I recreated the project with Phoenix 1.3 to see/learn differences and adapt my old code.
In there I have a has_many
relationship between a model Position
and Skill
. Whereas in the 1.2 code in position_controller.ex
I used
case Repo.insert(changeset) do
{:ok, position} ->
position = position |> Repo.preload(:skills)
...
to have skills
preloaded for rendering I'm unsure where to put this in my 1.3 code.
Controller seems to be the wrong place now (Repo
isn't even known) so I placed it into my context file inside create_position
like this:
def create_position(attrs \\ %{}) do
with {:ok, %Position{} = position} <-
%Position{}
|> Position.changeset(attrs)
|> Repo.insert() do
position = Repo.preload(position, :skills)
{:ok, position}
end
end
Which feels strange since it now does more than just inserting.
So what is the correct and best way to perform this task?
Upvotes: 3
Views: 478
Reputation: 10041
You will want to separate things out depending on what your contexts / application looks like.
def insert_position(attrs) do
attrs
|> changeset()
|> MyApp.Repo.insert()
end
If skills and positions are in the same context, you can do something along the lines of
def load_skills(position) do
MyApp.Repo.preload(position, :skills)
end
If it is in a separate context, you can do the following
def get_skills_for_position(position) do
# I'm not sure which way you have the relationship
MyApp.Repo.all(from skill in MyApp.Skill,
join: position in MyApp.Position,
on: skill.id == position.skill_id)
end
Then, in your controller, it is up to you to put these things together.
def create(conn, %{"position" => position_attrs}) do
case create_position(position_attrs) do
{:ok, position} ->
# or load_skills_for_position, depending if they are in the same contexts.
position = load_skills(position)
...
{:error, changeset} ->
...
end
end
Upvotes: 3