protocol Ecto.Queryable not implemented for TrainWeb.Catalog.Category of type Atom, the given module does not exist. This protocol is implemented for the following type(s): Atom, BitString, Ecto.Query, Ecto.SubQuery, Tuple
my code in product.ex
defmodule TrainWeb.Catalog.Product do
use Ecto.Schema
import Ecto.Changeset
alias TrainWeb.Catalog.Category
schema "products" do
field :title, :string
field :description, :string
field :price, :decimal
field :views, :integer
many_to_many :categories, Category, join_through: "product_categories", on_replace: :delete
timestamps(type: :utc_datetime)
end
def changeset(product, attrs) do
product
|> cast(attrs, [:title, :description, :price, :views])
|> validate_required([:title, :description, :price, :views])
end
end
my code in product_html.ex
defmodule TrainWeb.ProductHTML do
use TrainWeb, :html
embed_templates "product_html/*"
attr :changeset, Ecto.Changeset, required: true
attr :action, :string, required: true
def product_form(assigns)
def category_opts(changeset) do
existing_ids =
changeset
|> Ecto.Changeset.get_change(:categories, [])
|> Enum.map(& &1.data.id)
for cat <- TrainWeb.Catalog.list_categories(),
do: [key: cat.title, value: cat.id, selected: cat.id in existing_ids]
end
end
My code in product_controller.ex
defmodule TrainWeb.ProductController do
use TrainWeb, :controller
alias TrainWeb.Catalog
alias TrainWeb.Catalog.Product
def index(conn, _params) do
products = Catalog.list_products()
render(conn, :index, products: products)
end
def new(conn, _params) do
changeset = Catalog.change_product(%Product{})
render(conn, :new, changeset: changeset)
end
def create(conn, %{"product" => product_params}) do
case Catalog.create_product(product_params) do
{:ok, product} ->
conn
|> put_flash(:info, "Product created successfully")
|> redirect(to: ~p"/products/#{product}")
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, :new, changeset: changeset)
end
end
def update(conn, %{"id" => id, "product" => product_params}) do
product = Catalog.get_product!(id)
case Catalog.update_product(product, product_params) do
{:ok, product} ->
conn
|> put_flash(:info, "Product updated successfully")
|> redirect(to: ~p"/products/#{product}")
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, :edit, product: product, changeset: changeset)
end
end
def show(conn, %{"id" => id}) do
product =
id
|> Catalog.get_product!()
|> Catalog.inc_page_views()
render(conn, :show, product: product)
end
def edit(conn, %{"id" => id}) do
product = Catalog.get_product!(id)
changeset = Catalog.change_product(product)
render(conn, :edit, product: product, changeset: changeset)
end
def delete(conn, %{"id" => id}) do
product = Catalog.get_product!(id)
{:ok, _product} = Catalog.delete_product(product)
conn
|> put_flash(:info, "Product deleted successfully")
|> redirect(to: ~p"/products")
end
end
My code in context catalog.ex
defmodule TrainWeb.Catalog do
import Ecto.Query, warn: false
alias Train.Repo
alias TrainWeb.Catalog.Product
alias Train.Catalog.Category
def list_products do
Repo.all(Product)
end
# def get_product!(id), do: Repo.get!(Product, id)
def get_product!(id) do
Product |> Repo.get!(id) |> Repo.preload(:categories)
end
def create_product(attrs \\ %{}) do
%Product{}
# |> Product.changeset(attrs)
|> change_product(attrs)
|> Repo.insert()
end
def change_product(%Product{} = product, attrs \\ %{}) do
# Product.changeset(product, attrs)
categories = list_categories_by_id(attrs["category_ids"])
product
|> Repo.preload(:categories)
|> Product.changeset(attrs)
|> Ecto.Changeset.put_assoc(:categories, categories)
end
def update_product(%Product{} = product, attrs) do
product
# |> Product.changeset(attrs)
|> change_product(attrs)
|> Repo.update()
end
def delete_product(%Product{} = product) do
Repo.delete(product)
end
def inc_page_views(%Product{} = product) do
{1, [%Product{views: views}]} = from(p in Product, where: p.id == ^product.id, select: [:views])
|> Repo.update_all(inc: [views: 1])
put_in(product.views, views)
end
def list_categories do
Repo.all(Category)
end
def get_category!(id), do: Repo.get!(Category, id)
def create_category(attrs \\ %{}) do
%Category{}
|> Category.changeset(attrs)
|> Repo.insert()
end
def update_category(%Category{} = category, attrs) do
category
|> Category.changeset(attrs)
|> Repo.update()
end
def delete_category(%Category{} = category) do
Repo.delete(category)
end
def change_category(%Category{} = category, attrs \\ %{}) do
Category.changeset(category, attrs)
end
def list_categories_by_id(nil), do: []
def list_categories_by_id(category_ids) do
Repo.all(from c in Category, where: c.id in ^category_ids)
end
end
My code in category.ex
defmodule Train.Catalog.Category do
use Ecto.Schema
import Ecto.Changeset
schema "categories" do
field :title, :string
timestamps(type: :utc_datetime)
end
@doc false
def changeset(category, attrs) do
category
|> cast(attrs, [:title])
|> validate_required([:title])
|> unique_constraint(:title)
end
end
Do i miss something? it’s error when i try to view one of list product