自我加入ActiveRecord,Parent_Post_ID和我

时间:2012-04-01 20:00:37

标签: ruby-on-rails activerecord self-join

所以我定义了一个自连模型。基本上是论坛上的帖子,以及它所属的parent_post。

class Post < ActiveRecord::Base
  has_many :replies, :class_name => "Post"
  belongs_to :thread, :class_name => "Post", :foreign_key => "parent_post_id"
end

这似乎从根本上说是合理的。我为回复操作创建了一个新的RESTful路由,以及一个操作和视图。

路线:

  resources :forums do
    resources :posts do
      member do
        get 'reply'
      end
    end
  end

视图层和控制动作似乎就是我被淹没的地方。

def reply
  @forum = Forum.find(params[:forum_id])
  @post = @forum.posts.build
  @post.thread = @forum.posts.find(params[:id])
  @post.title = "RE: #{@post.thread.title}"
end

def create
  @forum = Forum.find(params[:forum_id])
  @post = @forum.posts.build(params[:post])
  @post.user = current_user
  if @post.save
    redirect_to forum_post_path(@forum, @post), notice: 'Post was successfully created.'
  else
    render action: "new"
  end
end

在视图层中,我只是尝试使用相同的脚手架生成的部分我正在使用标准的新编辑操作。

#reply.html.erb
<%= render :partial => 'form' %>

#_form.html.erb
<%= form_for [@forum,@post], :html => { :class => 'form-horizontal' } do |f| %>
  <fieldset>
    <legend><h1>New Thread</h1></legend>

    <div class="control-group">
      <%= f.label :title, :class => 'control-label' %>
      <div class="controls">
        <%= f.text_field :title, :class => 'text_field span9' %>
      </div>
    </div>
        <div class="control-group">
      <%= f.label :body, :class => 'control-label' %>
      <div class="controls">
        <%= f.text_area :body, :class => 'text_area span9' %>
      </div>
    </div>
    <div class="form-actions">
      <%= f.submit 'Submit', :class => 'btn btn-primary' %>
      <%= link_to 'Cancel', forum_posts_path(@forum), :class => 'btn' %>
    </div>
  </fieldset>
<% end %>

但是,当我创建帖子时,parent_post_id会丢失,并且它被设置为nil。我需要创建另一个动作吗?有没有其他方法来设置线程?第三件事?

3 个答案:

答案 0 :(得分:0)

添加

<%= hidden_field_tag :forum_id , @forum.id %>

到您的表单

答案 1 :(得分:0)

这将有效:

回复行动:

@forum = Forum.find(params[:forum_id])
@post = @forum.posts.build
@post.thread = @forum.posts.find(params[:id])
@post.title = "RE: #{@post.thread.title}"

然后将其添加到您的视图

<%= f.hidden_field :parent_post_id, @post.thread.id %>

BTW我怀疑你是否需要一个自定义的reply方法,而不是使用内置的RESTful方法,但这应该可以解决你的问题,这不是你的问题。

答案 2 :(得分:0)

基本上,当您提交Posts#create操作时,您提交的网址类似于此/forum/1/posts,会从网址中删除parent_post_id。由于您使用parent_post_id来构建该网址,因此您需要使用POST方法。

我的建议是允许嵌套在POST资源中的replyposts资源。
(即POST /forums/1/posts/1/reply

所以也许这样的事情

resources :forums do
  resources :posts do
    # :show is actually just pointing to a form 
    resource :reply, :only => [:show, :create], 
                     :controller => 'reply' #otherwise gets routed to 'replies'
  end
end

所以你还需要一个ReplyController,但这基本上会与你的帖子控制器上的reply方法相匹配,但会有一些变化。

def show
  @forum = Forum.find(params[:forum_id])
  @post = @forum.posts.find(params[:post_id])
  @reply = @forum.posts.build
  @reply.thread = @post
  @reply.title = "RE: #{@post.thread.title}"
end

def create
  @forum = Forum.find(params[:forum_id])
  @post = @forum.posts.find(params[:post_id])
  @reply = @forum.posts.build(params[:reply])
  @reply.thread = @post
  @reply.user = current_user
  if @reply.save
    redirect_to forum_post_path(@forum, @post), notice: 'Reply was successfully created.'
  else
    render action: "show"
  end
end

最大的问题是您必须从Post块中抽象出form for字段。那是因为你试图POST的网址会有所不同。但是做这样的事情应该不会太糟糕:

回复/ show.html.erb

<%= 
  form_for @reply, :url => forum_post_reply_path(@forum, @post), 
                   :html => { :class => 'form-horizontal' } do |builder|
%>
  <fieldset>
    <legend><h1>New Reply</h1></legend>

    <%= render "posts/post_fields", :f => builder %>

    <div class="form-actions">
      <%= builder.submit 'Submit', :class => 'btn btn-primary' %>
      <%= link_to 'Cancel', forum_post_path([@forum, @post]), :class => 'btn' %>
    </div>
  </fieldset>

<% end %>

<强>文章/ _form.html.erb

<%= form_for [@forum,@post], :html => { :class => 'form-horizontal' } do |builder| %>
  <fieldset>
    <legend><h1>New Thread</h1></legend>

    <%= render "post_fields", :f => builder %>

    <div class="form-actions">
      <%= builder.submit 'Submit', :class => 'btn btn-primary' %>
      <%= link_to 'Cancel', forum_posts_path(@forum), :class => 'btn' %>
    </div>
  </fieldset>
<% end %>

<强>文章/ _post_fields.html.erb

<div class="control-group">
  <%= f.label :title, :class => 'control-label' %>
  <div class="controls">
    <%= f.text_field :title, :class => 'text_field span9' %>
  </div>
</div>
<div class="control-group">
  <%= f.label :body, :class => 'control-label' %>
  <div class="controls">
    <%= f.text_area :body, :class => 'text_area span9' %>
  </div>
</div>

注意:可能有更好的方式来声明路线,但我真的不知道。