Skip to main content
Test Double company logo
Services
Services Overview
Holistic software investment consulting
Software Delivery
Accelerate quality software development
Product Strategy & Performance
Level up product strategy & performance
Legacy Modernization
Renovate legacy software systems
Pragmatic AI
Solve business problems without hype
Upgrade Rails
Update Rails versions seamlessly
DevOps
Scale infrastructure smoothly
Technical Recruitment
Build tech & product teams
Technical & Product Assessments
Uncover root causes & improvements
Case Studies
Solutions
Accelerate Quality Software
Software Delivery, DevOps, & Product Delivery
Maximize Software Investments
Product Performance, Product Scaling, & Technical Assessments
Future-Proof Innovative Software
Legacy Modernization, Product Transformation, Upgrade Rails, Technical Recruitment
About
About
What's a test double?
Approach
Meeting you where you are
Founder's Story
The origin of our mission
Culture
Culture & Careers
Double Agents decoded
Great Causes
Great code for great causes
EDI
Equity, diversity & inclusion
Insights
All Insights
Hot takes and tips for all things software
Leadership
Bold opinions and insights for tech leaders
Developer
Essential coding tutorials and tools
Product Manager
Practical advice for real-world challenges
Say Hello
Test Double logo
Menu
Services
BackGrid of dots icon
Services Overview
Holistic software investment consulting
Software Delivery
Accelerate quality software development
Product Strategy & Performance
Level up product strategy & performance
Legacy Modernization
Renovate legacy software systems
Pragmatic AI
Solve business problems without hype
Cycle icon
DevOps
Scale infrastructure smoothly
Upgrade Rails
Update Rails versions seamlessly
Technical Recruitment
Build tech & product teams
Technical & Product Assessments
Uncover root causes & improvements
Case Studies
Solutions
Solutions
Accelerate Quality Software
Software Delivery, DevOps, & Product Delivery
Maximize Software Investments
Product Performance, Product Scaling, & Technical Assessments
Future-Proof Innovative Software
Legacy Modernization, Product Transformation, Upgrade Rails, Technical Recruitment
About
About
About
What's a test double?
Approach
Meeting you where you are
Founder's Story
The origin of our mission
Culture
Culture
Culture & Careers
Double Agents decoded
Great Causes
Great code for great causes
EDI
Equity, diversity & inclusion
Insights
Insights
All Insights
Hot takes and tips for all things software
Leadership
Bold opinions and insights for tech leaders
Developer
Essential coding tutorials and tools
Product Manager
Practical advice for real-world challenges
Say hello
Developers
Developers
Developers
Software tooling & tips

Simplify CRUD in Elixir with EctoResource

Check out how EctoResource transforms CRUD operations in Elixir, making coding cleaner and more efficient. Dive in now!
Dayton Nolan
|
March 23, 2020
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

CRUDy contexts can jam up the works in an Elixir/Phoenix application.

Contexts allow for a separation of concerns between data and business logic. Often times, the first thing we do is add many basic CRUD functions to our contexts which essentially delegate to Ecto. This boilerplate code leads to boilerplate tests.

Over time, these CRUD operations add up in the application and compound the problem. The names and APIs of these standard functions can start to drift between modules, causing unexpected behavior and bugs. In short, it can be a mess.

EctoResource cleans up the mess

EctoResource is a Hex package that aims to reduce the boilerplate code involved in basic CRUD operations. It does so by providing macros to generate all the CRUD functions for a given Ecto Repo and Schema.

Consider the following context without using ecto_resource (generated by mix phx.gen.context Accounts User users):

defmodule MyApp.Accounts do
  @moduledoc """
  The Accounts context.
  """

  import Ecto.Query, warn: false

  alias MyApp.Accounts.User
  alias MyApp.Repo

  def list_users do
    Repo.all(User)
  end

  def get_users!(id), do: Repo.get!(User, id)

  def create_users(attrs \\ %{}) do
    %User{}
    |> User.changeset(attrs)
    |> Repo.insert()
  end

  def update_users(%User{} = users, attrs) do
    users
    |> User.changeset(attrs)
    |> Repo.update()
  end

  def delete_users(%User{} = users) do
    Repo.delete(users)
  end

  def change_users(%User{} = users) do
    User.changeset(users, %{})
  end
end

All of the functions here are mostly delegates to Repo, with the addition of binding the operations to the User module.

Alternatively, we can generate these functions using EctoResource. This alleviates the boilerplate and allows the functions within the module to be focused on more sophisticated operations.

defmodule MyApp.Accounts do
  @moduledoc """
  The Accounts context.
  """

  import Ecto.Query, warn: false

  alias MyApp.Accounts.User
  alias MyApp.Repo

  use EctoResource

  using_repo(Repo) do
   resource(User)
  end
end

By default resource will generate all the basic CRUD functions:

MyApp.Accounts.all_users/1
MyApp.Accounts.change_user/1
MyApp.Accounts.create_user/1
MyApp.Accounts.create_user!/1
MyApp.Accounts.delete_user/1
MyApp.Accounts.delete_user!/1
MyApp.Accounts.get_user/2
MyApp.Accounts.get_user!/2
MyApp.Accounts.get_user_by/2
MyApp.Accounts.get_user_by!/2
MyApp.Accounts.update_user/2
MyApp.Accounts.update_user!/2

Note: You can generate this list yourself by using the following function in the console: iex> {repo, schema, function_names} = MyContext.__resource__(:resources)

If you need to be more specific you can use the only filter option:

...

using_repo(Repo) do
 resource(User, only: [:create, :delete])
end

...

Which would generate only the given functions

MyApp.Accounts.create_user/1
MyApp.Accounts.delete_user/1

You can also use the except filter option, which is the inverse of only:

...

using_repo(Repo) do
  resource(User, except: [:create, :create!, :delete, :delete!])
end

...

Which would generate all but the given functions

MyApp.Accounts.all_users/1
MyApp.Accounts.change_user/1
MyApp.Accounts.get_user/2
MyApp.Accounts.get_user!/2
MyApp.Accounts.get_user_by/2
MyApp.Accounts.get_user_by!/2
MyApp.Accounts.update_user/2
MyApp.Accounts.update_user!/2

You can see the EctoResource macros eliminate boilerplate function definitions. This lets our context modules remain focused on those functions that deviate from the standard CRUD operations. The functions generated by EctoResource all have the same API, providing a dependable standard.

You might be delighted to know that all the functions generated in your contexts will be included in your application’s documentation if you’re using Exdoc.

If you’d like to see how much can be removed from your contexts you can install EctoResource in your application by adding it to your dependencies:

...

defp deps do
  [
    ...
    {:ecto_resource, "~> 1.2"},
    ...
  ]
end

...

After a mix deps.get, you’ll be all set and ready to use the EctoResource macros in your application! Check it out on Hex. Read the documentation.

Related Insights

🔗
Elixir like a local
🔗
How to create powerful APIs with GraphQL and Elixir

Explore our insights

See all insights
Leadership
Leadership
Leadership
AI in the workforce: A shifting talent equation

AI is transformative: reshaping the workforce, blurring roles, and breaking career ladders. Explore how orgs can balance people, technology, and business in this new era of work.

by
Jonathon Baugh
Leadership
Leadership
Leadership
The anvil of alignment: The value of monoliths over microservices

Before dismantling your monolith for microservices, understand its crucial role in organizational alignment. We explore hidden costs, Conway's Law, and strategic insights for leaders making architectural decisions.

by
Dave Mosher
by
Joel Helbling
by
Steve Jackson
by
Patrick Brown
by
Jonathon Baugh
Developers
Developers
Developers
Build common (virtual) ground with unstructured remote calls

Taking remote work to new levels takes new techniques. Explore how unstructured remote calls can help build trust.

by
Tyler Sloane
Letter art spelling out NEAT

Join the conversation

Technology is a means to an end: answers to very human questions. That’s why we created a community for developers and product managers.

Explore the community
Test Double Executive Leadership Team

Learn about our team

Like what we have to say about building great software and great teams?

Get to know us
Test Double company logo
Improving the way the world builds software.
What we do
Services OverviewSoftware DeliveryProduct StrategyLegacy ModernizationPragmatic AIDevOpsUpgrade RailsTechnical RecruitmentAssessments
Who WE ARE
About UsCulture & CareersGreat CausesEDIOur TeamContact UsNews & AwardsN.E.A.T.
Resources
Case StudiesAll InsightsLeadership InsightsDeveloper InsightsProduct InsightsPairing & Office Hours
NEWSLETTER
Sign up hear about our latest innovations.
Your email has been added!
Oops! Something went wrong while submitting the form.
Standard Ruby badge
614.349.4279hello@testdouble.com
Privacy Policy
© 2020 Test Double. All Rights Reserved.