【发布时间】:2020-04-21 21:07:53
【问题描述】:
我正在尝试在 Rails 6 中创建一个问答线程,用户可以在其中回答问题,然后其他用户可以对答案发表评论 - 类似于 reddit 甚至 stackoverflow。
我在我的 Answer 模型上创建了一个带有“parent_id”的多态关联,并且我能够发布初始问题的答案。但是,嵌套答案不会呈现在初始答案之下,而是呈现在主要问题之下。我想我已经将问题隔离到下面看到的相应部分视图中:
答案视图
<li>
<%= answer.body %></br>
<%= link_to answer.user.first_name, answer.user %>
<%= link_to answer.user.last_name, answer.user %>
answered <%= time_ago_in_words(answer.created_at) %> ago.
<div class="comments-container">
<%= render partial: "answers/reply", locals: {commentable: answer.commentable, parent_id: answer.parent.id} %>
</div>
<ul> <%= render partial: "answers/answer", collection: answer.answers %> </ul>
</li>
据我了解,最后一行应该呈现答案的答案,但是答案呈现在最初的问题下方,而不是答案。关于我做错了什么的任何想法? 我应该使用像Ancestry 这样的宝石来做到这一点吗?如果是这样,那将如何工作?
为了完整起见,这里是其他组件
问题视图
<h3><%= @question.title %></h3>
<p> Asked by <%= link_to @question.user.email, @question.user %> <%= time_ago_in_words(@question.created_at) %> ago. </p>
</br>
<span class="body"> <%= @question.body %> </span>
</br>
<h5><strong><%= @question.answers.count %> Answers</strong></h5>
<%= render @answers %></br>
<%= render partial: "answers/form", locals: {commentable: @question} %> </br>
<%= paginate @answers %>
答案模型
belongs_to :user
belongs_to :parent, optional: true, class_name: 'Answer'
belongs_to :commentable, polymorphic: true
has_many :answers, as: :commentable, dependent: :destroy
validates :body, presence: true
validates :user, presence: true
问题模型
belongs_to :user
has_many :answers, as: :commentable, dependent: :destroy
validates :body, presence: true
validates :title, presence: true
validates :user, presence: true
应答控制器
class AnswersController < ApplicationController
before_action :set_answer, only: [:edit, :update, :destroy, :upvote, :downvote]
before_action :find_commentable, only: [:create]
def new
@answer = Answer.new
end
def create
@answer = @commentable.answers.new(answer_params)
respond_to do |format|
if @answer.save
format.html { redirect_to @commentable }
format.json { render :show, status: :created, location: @commentable }
else
format.html { render :new }
format.json { render json: @answer.errors, status: :unprocessable_entity }
end
end
end
def destroy
@answer = @commentable.answers.find(params[:id])
@answer.discard
respond_to do |format|
format.html { redirect_to @commentable, notice: 'Answer was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_answer
@answer = Answer.find(params[:id])
end
def answer_params
params.require(:answer).permit(:body).merge(user_id: current_user.id, parent_id: params[:parent_id])
end
def find_commentable
@commentable = Answer.find(params[:answer_id]) if params[:answer_id]
@commentable = Question.find(params[:question_id]) if params[:question_id]
end
end
问题控制器
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy, :upvote, :downvote]
def index
@questions = Question.order('created_at desc').page(params[:page])
end
def show
@answer = @question.answers.new
@answers = if params[:answer]
@question.answers.where(id: params[:answer])
else
@question.answers.where(parent_id: nil)
end
@answers = @answers.page(params[:page]).per(5)
end
def new
@question = Question.new
end
def edit
end
def create
@question = Question.new(question_params)
respond_to do |format|
if @question.save
format.html { redirect_to @question, notice: 'You have successfully asked a question!' }
format.json { render :show, status: :created, location: @question }
else
format.html { render :new }
format.json { render json: @question.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @question.update(question_params)
format.html { redirect_to @question, notice: 'Question successfully updated.' }
format.json { render :show, status: :ok, location: @question }
else
format.html { render :edit }
format.json { render json: @question.errors, status: :unprocessable_entity }
end
end
end
def destroy
@question.discard
respond_to do |format|
format.html { redirect_to @questions_url, notice: 'Question successfully deleted.' }
format.json { head :no_content }
end
end
private
def set_question
@question = Question.find(params[:id])
end
def question_params
params.require(:question).permit(:title, :body, :tag_list).merge(user_id: current_user.id)
end
end
【问题讨论】:
-
局部渲染看起来不错,但你不需要那么冗长
<%= render answer.answers %>会做同样的事情。您确定这不是由于格式错误的 html 或 CSS 问题造成的吗?检查 html 源代码(不仅仅是 Web 检查器中呈现的 DOM)。 -
好的,我已经按照建议对代码进行了清理,使其不那么冗长和复杂。 html 源代码也呈现不正确,对答案的回复仅呈现在最底部。我认为这不应该是 CSS 问题,因为我还没有为此做任何花哨的事情。主要只是专注于后端
-
您可能想要退后一步并重新考虑一般方法。基本上对于每个递归迭代,您都将创建一个 N+1 查询。将答案和子答案的数量加在一起,即使有分页,它也会非常慢。我添加了一个不能解决视图问题的答案(这真的不应该是你现在最关心的问题)但解决了数据库设计方面的问题。
-
是的,这就是我的想法。我尝试了不同的方法,主要是使用 gems,但他们遇到了相同的 View 问题。这就是为什么我尝试“手动”进行操作。最初我没有使用多态方法,但我看到其他一些人在使用它,所以我想我会尝试一下它是否可以修复渲染。在任何情况下,我所构建的似乎都行不通,因此必须从头开始。感谢您的帮助!
-
使用像 ancestry 这样的 gem 的问题在于,它抽象得太多,以至于您不会学习如何设置具有自引用关联的树,因此自己动手实际上是一个好主意。在这种情况下,如果您使用三个表
questions->answers->comments从概念上讲会容易得多,这将消除对多态性或 STI 的需求。
标签: ruby-on-rails ruby recursion view comments