我在Phoenix Framework中有三个模型,User
,Post
,Vote
。 用户只有在点数超过1分时才能对该帖子进行投票。用户点是通过他们的帖子从其他用户获得的票数来计算的。
这是我在Vote
模型中定义的内容:
schema "votes" do
field :type, :integer # -1 0 1
belongs_to :user, News.User
belongs_to :post, News.Post
timestamps()
end
由于用户点未在Vote
架构中定义,因此我无法直接在模型中使用validate_change
或add_error
,除非我阅读其他模型'数据决定是否向变更集添加错误,显然它会在Vote
模型中做太多事情。
我应该把约束放在哪里?控制器或型号?
也许我应该对数据库设置约束,确保用户点永远不会低于零?我找到了类似触发器的东西但PostgreSQL trigger将如何将结果返回到变更集?
我在我的控制器中试过了:
def create(conn, %{"vote" => vote_params}, user) do
changeset = user
|> build_assoc(:votes)
|> Vote.changeset(vote_params)
changeset = if user.point < 1 do
Ecto.Changeset.add_error(changeset, :user_id, "You points is not enough.")
end
case Repo.insert(changeset) do
{:ok, vote} ->
conn
|> put_status(:created)
|> put_resp_header("location", vote_path(conn, :show, vote))
|> render("show.json", vote: vote)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(WechatNews.ChangesetView, "error.json", changeset: changeset)
end
end
这很容易,但我也必须在update
行动中重复这一点。
答案 0 :(得分:0)
你可以按照
的方式做点什么def changeset(struct, params) do
struct
|> cast([:points], params)
|> validate_required(:points)
end
def point_changeset(struct, params) do
struct
|> changeset(params)
|> check_points
end
defp check_points(changeset) do
if get_field(changeset, :points) < 1 do
add_error(changeset, :points, "too low")
else
changeset
end
end
这将为您提供一个函数point_changeset/2
,只有在您需要检查用户是否可以根据其点执行某项操作时,才能使用该函数。它仍然会调用具有您希望始终运行的验证的主changeset/2
函数。