Rails多态has_many通过关联 - 形式破碎

时间:2017-10-21 14:53:45

标签: ruby-on-rails activerecord ruby-on-rails-5

在我的Rails 5.1应用程序中,我试图从头开始创建一个标记系统。

我希望Tags成为多态has_many :through关联,以便我可以标记多个模型。

目前我可以通过执行以下操作在控制台中创建Tag(以及关联的Tagging}:Note.last.tags.create(name: "example")生成正确的SQL:

Note Load (0.2ms)  SELECT  "notes".* FROM "notes" ORDER BY "notes"."id" DESC LIMIT $1  [["LIMIT", 1]]
(0.2ms)  BEGIN
SQL (0.4ms)  INSERT INTO "tags" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["name", "example"], ["created_at", "2017-10-21 14:41:43.961516"], ["updated_at", "2017-10-21 14:41:43.961516"]]
Note Load (0.3ms)  SELECT  "notes".* FROM "notes" WHERE "notes"."id" = $1 LIMIT $2  [["id", 4], ["LIMIT", 1]]
SQL (0.4ms)  INSERT INTO "taggings" ("created_at", "updated_at", "tag_id", "taggable_id", "taggable_type") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["created_at", "2017-10-21 14:41:43.978286"], ["updated_at", "2017-10-21 14:41:43.978286"], ["tag_id", 9], ["taggable_id", 4], ["taggable_type", "Note"]]

但是当尝试通过我的表单创建Tag及其关联时,它无法正常工作。我可以创建Tag但不能创建Tagging

控制器/笔记/ tags_controller.rb

class Notes::TagsController < TagsController
  before_action :set_taggable

  private

  def set_taggable
    @taggable = Note.find(params[:note_id])
  end
end

控制器/ tags_controller.rb

class TagsController < ApplicationController
  before_action :authenticate_user!

  def create
    @tag = @taggable.tags.new(tag_params)
    @tag.user_id = current_user.id

    if @tag.save
      redirect_to @taggable, success: "New tag created."
    else
      render :new
    end
  end

  private

  def tag_params
    params.require(:tag).permit(:name)
  end

end

的routes.rb

...
resources :notes, except: [:index] do
  resources :tags, module: :notes
end
...

class Note < ApplicationRecord
  belongs_to :notable, polymorphic: true
  has_many :taggings, as: :taggable
  has_many :tags, through: :taggings
end

class Tag < ApplicationRecord
  has_many :taggings
  has_many :taggables, through: :taggings
end

class Tagging < ApplicationRecord
  belongs_to :tag
  belongs_to :taggable, polymorphic: true
end

备注/ show.html.erb

<p><%= @note.body %></p>
<%= render partial: 'tags/tags', locals: { taggable: @note } %>
<%= render partial: 'tags/form', locals: { taggable: @note }  %>

标记/ form.html.erb

<%= simple_form_for [taggable, Tag.new] do |f| %>
  <%= f.input :name %>
  <%= f.submit %>
<% end %>

2 个答案:

答案 0 :(得分:0)

错误可能是由于默认情况下需要:标记关联而未保存标记。

尝试:

class Tagging < ApplicationRecord
  belongs_to :tag, required: false
  belongs_to :taggable, polymorphic: true
end

答案 1 :(得分:0)

您的方法存在基本缺陷,因为它会创建每个标记的重复项,而不是创建连接记录。它还增加了必要的复杂性,因为您必须为每个可标记资源创建嵌套控制器。

y_oracle的唯一性验证不会失败,这表明您的应用程序存在缺陷 - 您应该在数据库中有一个唯一索引,并在模型中进行验证以避免重复。

这对于像评论这样的东西来说是一个非常好的方法,其中每个创建的记录应该是唯一的,但不适用于您链接到间接关联的情况。

要将现有标签分配给记录,您可以使用选择或复选框来传递ID数组:

tags.name

要创建新标记,您可以使用nested attributes或使用ajax向<%= form_for(@note) do |f| %> # ... <%= f.collection_checkboxes(:tags_ids, Tag.all, :id, :name) %> <% end %> 发送POST请求并更新视图,以便标记最终位于复选框列表中。