如何制作表单来为Post和Picture模型创建多态注释?

问题描述 投票:0回答:1

我需要为 post#show 和 picture#show 视图创建一个表单,以便为它们创建任何评论。我为它们创建了一个多态关联和迁移,但我需要帮助来为它们创建表单。

class Post < ApplicationRecord
  has_many :comments, as: :commentable, dependent: :destroy
end

class Picture < ApplicationRecord
  has_many :comments, as: :commentable, dependent: :destroy
end

class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
end

在谷歌中我搜索了该解决方案,但我不确定它们的正确性:

<%= form_for comment do |f| %>
    <%= f.hidden_field :commentable_id, value: params["id"] %>
    <%= f.hidden_field :commentable_type, value: params["controller"].singularize.capitalize %>
    <p>Comment: <%= f.text_area :content %></p>
    <%= f.submit %>
<% end %>
ruby-on-rails ruby erb polymorphic-associations
1个回答
0
投票

处理多态关联不应该与任何其他嵌套资源有任何不同,因为您的模型是内部实现细节,而不是应用程序的公共 HTTP API 的一部分。

# config/routes.rb
resources :posts do
  resources :comments, only: :create, module: :posts
end

resources :pictures do
  resources :comments, only: :create, module: :pictures
end 

这里我们创建了一条

POST /posts/:post_id/comments
路线和一条
POST /pictures/:picture_id/comments
路线。这会将关系放置在 URI 中,从而使资源之间的 RESTful 关系变得明确,而不是将其隐藏在请求正文中。

使用

module: :posts
将其路由到单独的控制器是可选的,但我发现使用继承比将所有内容都放入单个控制器并通过代码分支嗅探父类更干净。

# Abstract base class for nested comments
class NestedCommentsController < ApplicationController
  before_action :find_commentable 

  def create
    @comment = @commentable.comments.new(comment_params)
    if @comment.save
      yield @comment if block_given?
      redirect_to after_save_path_for(@comment)
    else
      render :new
    end
  end

  private

  def commentable_class
    raise "This method must be implemented by subclasses"
  end

  def commentable_param_key
    commentable_class.model_name.singular_param_key + "_id"
  end

  def commentable_param
    params[commentable_param_key]
  end

  def find_commentable
    @commentable = commentable_class.find(commentable_param)
  end

  def after_save_path_for(comment)
    comment.commentable
  end
end

虽然这可能看起来很复杂,但它只是使用一种方法来避免对父类和 ActiveModel::Naming API 的引用进行硬编码以及约定优于配置。

module Posts 
  class CommentsController < :: NestedCommentsController 
    def commentable_class
      Post
    end
  end
end
module Pictures
  class CommentsController < :: NestedCommentsController 
    def commentable_class
      Picture
    end
  end
end

该表单只是嵌套资源的常规表单:

<%= form_with model: [commentable, comment] do |f| %>
  <p>Comment: <%= f.text_area :content %></p>
  <%= f.submit %>
<% end %>

当您传递数组时,多态路由助手会将其解析为嵌套路由助手,并调用

post_comments_path(post)
picture_comments_path(picture)
来获取表单的操作属性。

数组也被压缩,因此它适用于浅层路线只要你为本地传递nil:

[nil, comment] # comments/1
© www.soinside.com 2019 - 2024. All rights reserved.