Stay Hungry.Stay Foolish.
phoenix中实现文章和标签多对多关联

创建model

article model 和 article migration

schema "articles" do
    field :title, :string
    field :body, :string
    field :reading, :integer, default: 0
    belongs_to :category, HelloPhoenix.Category, foreign_key: :category_id

    has_many :comments, HelloPhoenix.Comment, on_delete: :delete_all
    many_to_many :tags, HelloPhoenix.Tag, join_through: "articles_tags", on_delete: :delete_all

    timestamps()
end

def change do
    create table(:articles) do
      add :title, :string
      add :body, :string
      add :category_id, references(:categorys, on_delete: :nothing)

      timestamps()
    end
    create index(:articles, [:category_id])
end

tag model 和 tag migrartion

schema "tags" do
    field :name, :string
    many_to_many :articles, HelloPhoenix.Article, join_through: "articles_tags", on_delete: :delete_all

    timestamps()
end

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

      timestamps()
    end
    create unique_index(:tags, [:name])

end

article_tag model 和article_tag migration,添加article_tag model主要是为了方便之后对articles_tags进行数据库操作,因为phoenix的多对多api功能不全

schema "articles_tags" do
    field :article_id, :integer
    field :tag_id, :integer
end

def change do
    create table(:articles_tags, primary_key: false) do
      add :article_id, references(:articles)
      add :tag_id, references(:tags)
    end
end

如上在tag和article model中加入on_delete: delete_all就可以在删除tag或者article的时候自动删除article_tag数据表中的数据。

业务逻辑处理

关于article controller我是这么写的, 创建文章勾选tag的时候, tag_ids为勾选的tags id

article
|> Repo.preload(:tags)
|> Ecto.Changeset.change()
|> Ecto.Changeset.put_assoc(:tags, Enum.map(tag_ids, fn id -> Repo.get(Tag, id) end))
|> Repo.update!

编辑文章的时候,先删除在articles_tags表中关于这篇文章的所有关联,然后重新插入新的关联关系

from(p in ArticleTag, where: p.article_id == ^id) |> Repo.delete_all   # 删除之前所有关联

 article                                                                                                             # 重新插入所有关联
 |> Repo.preload(:tags) 
 |> Ecto.Changeset.change()
 |> Ecto.Changeset.put_assoc(:tags, Enum.map(tag_ids, fn id -> Repo.get(Tag, id) end)) 
 |> Repo.update!
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证
评论
2016-11-28 03:24:01

试着评价一下