Hey all,
I want to create a new
action in order to write new posts in my project. Each post belongs_to
a user an hence I have a :user_id
field in my schema.
However, when I want to access the new
template, I get the following error:
cannot add constraint to changeset because association 'user' does not exist. Did you mean one of ''?
My post_controller.ex:
defmodule GazetteWeb.PostController do
use GazetteWeb, :controller
alias Gazette.Repo
alias Gazette.Post
alias Gazette.User
plug :scrub_params, "post" when action in [:create, :update] # convert blank_string params into nils
def action(conn, _) do # helps to get three arguments in controller's actions
apply(__MODULE__, action_name(conn),
[conn, conn.params, conn.assigns.current_user]) # here are the three arguments
end
[...]
def new(conn, _params, current_user) do
changeset =
current_user
|> Ecto.build_assoc(:posts)
|> Post.changeset
render conn, "new.html", changeset: changeset
end
[…]
my post.ex:
defmodule Gazette.Post do
use Ecto.Schema
import Ecto.Changeset
alias Gazette.Post
schema "posts" do
field :body, :string
field :title, :string
field :user_id, :id
timestamps()
end
@required_fields ~w(title)a
@optional_fields ~w(body)a
@doc false
def changeset(%Post{} = post, attrs \\ %{}) do
post
|> cast(attrs, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
|> assoc_constraint(:user)
end
end
my user.ex:
defmodule Gazette.User do
use Ecto.Schema
import Ecto.Changeset
alias Gazette.User
schema "users" do
field :email, :string
field :is_admin, :boolean, default: false
field :is_writer, :boolean, default: false
field :name, :string
field :password, :string, virtual: true
field :password_hash, :string
has_many :posts, Gazette.Post
timestamps()
end
@required_fields ~w(email name)a
@optional_fields ~w(is_writer is_admin)a
@doc false
def changeset(%User{} = user, attrs \\ %{}) do
user
|> cast(attrs, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
end
def registration_changeset(struct, params) do
struct
|> changeset(params)
|> cast(params, ~w(password)a, [])
|> validate_length(:password, min: 6, max: 100)
|> hash_password
end
defp hash_password(changeset) do
case changeset do
%Ecto.Changeset{valid?: true,
changes: %{password: password}} ->
put_change(changeset,
:password_hash,
Comeonin.Bcrypt.hashpwsalt(password))
_ ->
changeset
end
end
end
Any idea ?