Render specific number of Ecto members (resource)

Hello Devs!

If we have created a CRUD resource, for example - posts we could render them in our template with

<%= for post <- @posts do %>
  <%= post.title %>
<% end %>

and of course with list in our controller

websites = Home.list_posts(params)

And that renders all posts’ post.titles.
But for example if we have 6 members in that posts schema, how should we render in template only first 3 ones?

I have tried:

<%= @posts |> Enum.with_index |> Enum.map(fn({post, index<3}) ->  %>

Best Regards,
ykostov

Best option would be to add a limit to your ecto query so you aren’t pulling out more data than you need.

def list_posts_limited(params, limit) do
  #not sure what params represents so left that part out
  Repo.all(from p in Post, limit: ^limit)
end

Otherwise try

Home.list_posts(params) |> Enum.take(3)

But changing the query/adding another function with the limit is the far better option.

2 Likes

sanswork gave you the correct answer answer you need, but on your example, the reason why Enum.map didn’t work is because given a list of n elements, Enum.map returns a list of m elements - it maps from one element to another.

To get from n element to n-m element you can use something like Enum.reduce, or specifically in your use case, Enum.filter would work in tandem with Enum.with_index.

iex(4)> [:a, :b, :c, :d, :e] |> Enum.with_index() |> Enum.filter(fn {_, index} → index < 3 end)
[a: 0, b: 1, c: 2]

iex(5)> [:a, :b, :c, :d, :e] |> Enum.with_index() |> Enum.reduce(, fn {el, index}, acc when index < 3 → [el | acc]; _, acc → acc end)
[:c, :b, :a]

But again, Enum.take/2 is much more idiomatic and delegating to database is also the correct approach since that means you’re not fetching unnecessary data

1 Like