Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing Scopes and Associations in Phoenix/Ecto

In Rails, if I have the following setup:

class Post < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :post

  def self.approved
    where(approved: true)
  end
end

Then I can do something like this:

post = Post.find(100)
comments = post.comments.approved

to quickly get all the approved comments for the given Post.

How can I do something similar in Ecto?

defmodule MyApp.Post do
  use Ecto.Model

  schema "posts" do
    #columns omitted
    has_many :comments, MyApp.Comment
  end
end

defmodule MyApp.Comment do
  use Ecto.Model

  schema "comments" do
    #columns omitted
    belongs_to :post, MyApp.Post
  end
end

I've got the post with comments pre-loaded:

post = MyApp.Post
       |> MyApp.Repo.get(100)
       |> MyApp.Repo.preload(:comments)

I am not even sure where to start with the approved scope in MyApp.Comment.

like image 283
Eric Farkas Avatar asked Sep 07 '25 18:09

Eric Farkas


1 Answers

Preloads are allowed to receive queries. So you can filter associated comments like this.

post = 
  MyApp.Post
  |> Ecto.Query.preload(comments: ^MyApp.Comment.approved(MyApp.Comment))
  |> MyApp.Repo.get(100)

And in your Comment model

def approved(query) do
  from c in query,
  where: c.approved == true
end
like image 154
Dmitry Biletskyy Avatar answered Sep 11 '25 02:09

Dmitry Biletskyy