Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add categories #8

Open
wants to merge 2 commits into
base: 05-videos
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 8 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,20 @@
# Rumbl

## Generating Resources

* `phoenix.gen.html` - HTML scaffold
* `phoenix.gen.json` - JSON scaffold

generate a video resource
Generate the `Rumbl.Category` model

```bash
$ dc run app \
mix phoenix.gen.html Video videos \
user_id:references:users \
url:string \
title:string \
description:text
$ dc run app \
mix ecto.migrate
$ mix phoenix.gen.model Category categories name:string
```

## Formatting Code

[[source](https://hexdocs.pm/mix/master/Mix.Tasks.Format.html)]
Generate a migration to add `category_id` to the `videos` table

**file**: `.formatter.exs`

```
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
```bash
$ mix ecto.gen.migration add_category_id_to_video
```

run the following without `--check-formatted` to auto-format code
Run migrations and seeds

```bash
$ dc run app \
mix format --check-formatted
$ mix ecto.migrate
$ mix run priv/repo/seeds.exs
```
35 changes: 35 additions & 0 deletions notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,38 @@ list application routes
```bash
$ mix phoenix.routes
```

generating Resources

* `phoenix.gen.html` - HTML scaffold
* `phoenix.gen.json` - JSON scaffold

generate a video resource

```bash
$ dc run app \
mix phoenix.gen.html Video videos \
user_id:references:users \
url:string \
title:string \
description:text
$ dc run app \
mix ecto.migrate
```

formatting Code [[source](https://hexdocs.pm/mix/master/Mix.Tasks.Format.html)]

**file**: `.formatter.exs`

```
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
```

run the following without `--check-formatted` to auto-format code

```bash
$ dc run app \
mix format --check-formatted
```
13 changes: 13 additions & 0 deletions priv/repo/migrations/20210405174644_create_category.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule Rumbl.Repo.Migrations.CreateCategory do
use Ecto.Migration

def change do
create table(:categories) do
add :name, :string

timestamps()
end

create unique_index(:categories, [:name])
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule Rumbl.Repo.Migrations.AddCategoryIdToVideo do
use Ecto.Migration

def change do
alter table(:videos) do
add :category_id, references(:categories)
end
end
end
8 changes: 8 additions & 0 deletions priv/repo/seeds.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,11 @@
#
# We recommend using the bang functions (`insert!`, `update!`
# and so on) as they will fail if something goes wrong.

alias Rumbl.Repo
alias Rumbl.Category

categories = ~w(Action Drama Romance Comedy Sci-fi)
for category <- categories do
Repo.get_by(Category, name: category) || Repo.insert!(%Category{name: category})
end
18 changes: 18 additions & 0 deletions test/models/category_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule Rumbl.CategoryTest do
use Rumbl.ModelCase

alias Rumbl.Category

@valid_attrs %{name: "some content"}
@invalid_attrs %{}

test "changeset with valid attributes" do
changeset = Category.changeset(%Category{}, @valid_attrs)
assert changeset.valid?
end

test "changeset with invalid attributes" do
changeset = Category.changeset(%Category{}, @invalid_attrs)
refute changeset.valid?
end
end
10 changes: 10 additions & 0 deletions web/controllers/video_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ defmodule Rumbl.VideoController do

alias Rumbl.Video

alias Rumbl.Category
plug :load_categories when action in [:new, :create, :edit, :update]
def load_categories(conn, _) do
query = Category
|> Category.alphabetical
|> Category.names_and_ids
categories = Repo.all(query)
assign(conn, :categories, categories)
end

def action(conn, _) do
apply(__MODULE__, action_name(conn), [conn, conn.params, conn.assigns.current_user])
end
Expand Down
26 changes: 26 additions & 0 deletions web/models/category.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Rumbl.Category do
use Rumbl.Web, :model

schema "categories" do
field :name, :string

timestamps()
end

@doc """
Builds a changeset based on the `struct` and `params`.
"""
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:name])
|> validate_required([:name])
end

def alphabetical(query) do
from c in query, order_by: c.name
end

def names_and_ids(query) do
from c in query, select: {c.name, c.id}
end
end
1 change: 1 addition & 0 deletions web/models/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ defmodule Rumbl.User do
model
|> cast(params, ~w(name username), [])
|> validate_length(:username, min: 1, max: 20)
|> unique_constraint(:username)
end

def registration_changeset(model, params) do
Expand Down
9 changes: 7 additions & 2 deletions web/models/video.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,21 @@ defmodule Rumbl.Video do
field :title, :string
field :description, :string
belongs_to :user, Rumbl.User
belongs_to :category, Rubml.Category

timestamps()
end

@required_fields ~w(url title category)
@optional_fields ~w(category_id)

@doc """
Builds a changeset based on the `struct` and `params`.
"""
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:url, :title, :description])
|> validate_required([:url, :title, :description])
|> cast(params, @required_fields, @optional_fields)
|> validate_required(@required_fields)
|> assoc_constraint(:category)
end
end
2 changes: 1 addition & 1 deletion web/templates/video/edit.html.eex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<h2>Edit video</h2>

<%= render "form.html", changeset: @changeset,
<%= render "form.html", changeset: @changeset, categories: @categories,
action: video_path(@conn, :update, @video) %>

<%= link "Back", to: video_path(@conn, :index) %>
5 changes: 5 additions & 0 deletions web/templates/video/form.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
<%= error_tag f, :url %>
</div>

<div class="form-group">
<%= label f, :category_id, "Category", class: "control-label" %>
<%= select f, :category_id, @categories, class: "form-control", prompt: "Choose a category" %>
</div>

<div class="form-group">
<%= label f, :title, class: "control-label" %>
<%= text_input f, :title, class: "form-control" %>
Expand Down
2 changes: 1 addition & 1 deletion web/templates/video/new.html.eex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<h2>New video</h2>

<%= render "form.html", changeset: @changeset,
<%= render "form.html", changeset: @changeset, categories: @categories,
action: video_path(@conn, :create) %>

<%= link "Back", to: video_path(@conn, :index) %>