Rails:深层嵌套资源会出错:未定义方法'comments'

时间:2016-03-19 23:59:44

标签: ruby-on-rails nested comments nested-forms

我在rails应用程序中收到此错误undefined method 'comments'。我知道我不应该使用> 1级嵌套资源,但在这种情况下我不知道如何应用正确的方法。

目前这是我的路线:

resources :performance_indicators  do
    resources :improvement_actions do
      member do
        put "like" => "improvement_actions#upvote"
        put "unlike" => "improvement_actions#downvote"
      end
      resources :comments
    end
  end

正如我所说,我收到了这个错误:

NoMethodError in PerformanceIndicators#show
Showing .../app/views/comments/_form.html.erb where line #1 raised:
undefined method `comments' for nil:NilClass

我不知道我的问题是否在控制器中。有人可以帮忙吗? :)

修改

我的评论/ _form:

    <%= form_for([@performance_indicator, @improvement_action, @improvement_action.comments.build]) do |f| %>


  <div class="field">
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </div>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

这是我的CommentsController:

    class CommentsController < ApplicationController
  before_action :set_comment, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!, except: [:index, :show]
  before_action :set_improvement_action


  # GET /comments
  # GET /comments.json
  def index
  end

  # GET /comments/1
  # GET /comments/1.json
  def show
  end

  # GET /comments/new
    def new
      @comment = @improvement_action.comments.new
    end

  # GET /comments/1/edit
  def edit
  end

  # POST /comments
  # POST /comments.json
  def create

    @comment = @improvement_action.comments.new(comment_params)

      if @comment.save
        format.html { redirect_to [@improvement_action.performance_indicator, @improvement_action], notice: 'Comment was successfully created.' }
        format.json { render :show, status: :created, location: [@improvement_action, @comment] }
      else
        format.html { render :new }
        format.json { render json: @comment.errors, status: :unprocessable_entity }
    end
  end

  # PATCH/PUT /comments/1
  # PATCH/PUT /comments/1.json
  def update
    respond_to do |format|
      if @comment.update(comment_params)
        format.html { redirect_to @comment, notice: 'Comment was successfully updated.' }
        format.json { render :show, status: :ok, location: @comment }
      else
        format.html { render :edit }
        format.json { render json: @comment.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /comments/1
  # DELETE /comments/1.json
  def destroy
    @comment.destroy
    respond_to do |format|
      format.html { redirect_to comments_url, notice: 'Comment was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_comment
      @comment = Comment.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
  def comment_params
    params.require(:comment).permit(:body)
  end

  def set_improvement_action
    @improvement_action = ImprovementAction.includes(:comments).find(params[:improvement_action_id])
  end
end

这是我的PerformanceIndicatorController:

class PerformanceIndicatorsController < ApplicationController
  before_action :set_performance_indicator, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!, except: [:index, :show]
  # GET /performance_indicators
  # GET /performance_indicators.json
  def index
    @performance_indicators = PerformanceIndicator.all
  end

  # GET /performance_indicators/1
  # GET /performance_indicators/1.json
  def show
    #@performance_indicators = PerformanceIndicator.all.order("created_at DESC")
  end

  # GET /performance_indicators/new
  def new
    @performance_indicator = PerformanceIndicator.new
    @comments = Comment.new
  end

  # GET /performance_indicators/1/edit
  def edit
  end

  # POST /performance_indicators
  # POST /performance_indicators.json
  def create
    @performance_indicator = PerformanceIndicator.new(performance_indicator_params)

    respond_to do |format|
      if @performance_indicator.save
        format.html { redirect_to @performance_indicator, notice: 'Performance indicator was successfully created.' }
        format.json { render :show, status: :created, location: @performance_indicator }
      else
        format.html { render :new }
        format.json { render json: @performance_indicator.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /performance_indicators/1
  # PATCH/PUT /performance_indicators/1.json
  def update
    respond_to do |format|
      if @performance_indicator.update(performance_indicator_params)
        format.html { redirect_to @performance_indicator, notice: 'Performance indicator was successfully updated.' }
        format.json { render :show, status: :ok, location: @performance_indicator }
      else
        format.html { render :edit }
        format.json { render json: @performance_indicator.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /performance_indicators/1
  # DELETE /performance_indicators/1.json
  def destroy
    @performance_indicator.destroy
    respond_to do |format|
      format.html { redirect_to performance_indicators_url, notice: 'Performance indicator was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  def set_comment
    @improvement_action = ImprovementAction.find(params[:improvement_action_id])
    @comment = Comment.find(params[:id])
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_performance_indicator
      @performance_indicator = PerformanceIndicator.find(params[:id])
    end



    # Never trust parameters from the scary internet, only allow the white list through.
    def performance_indicator_params
      params.require(:performance_indicator).permit(:name, :numberTimesIdentifiedProblems, :numberTimesAnalysed)
    end



end

1 个答案:

答案 0 :(得分:0)

让我们从修复深层嵌套开始。

resources :performance_indicators, shallow: true do
  resources :improvement_actions
end

resources :improvement_actions, only: [] do
  member do
    put "like" => "improvement_actions#upvote"
    put "unlike" => "improvement_actions#downvote"
  end

  resources :comments
end

only: []是一种聪明的技巧,可以在一个资源下嵌套路由,但会抑制路由的生成。我们想要,因为第一个块实际上声明了我们需要的所有路径。

                                       Prefix Verb   URI Pattern                                                                              Controller#Action
    performance_indicator_improvement_actions GET    /performance_indicators/:performance_indicator_id/improvement_actions(.:format)          improvement_actions#index
                                              POST   /performance_indicators/:performance_indicator_id/improvement_actions(.:format)          improvement_actions#create
 new_performance_indicator_improvement_action GET    /performance_indicators/:performance_indicator_id/improvement_actions/new(.:format)      improvement_actions#new
edit_performance_indicator_improvement_action GET    /performance_indicators/:performance_indicator_id/improvement_actions/:id/edit(.:format) improvement_actions#edit
     performance_indicator_improvement_action GET    /performance_indicators/:performance_indicator_id/improvement_actions/:id(.:format)      improvement_actions#show
                                              PATCH  /performance_indicators/:performance_indicator_id/improvement_actions/:id(.:format)      improvement_actions#update
                                              PUT    /performance_indicators/:performance_indicator_id/improvement_actions/:id(.:format)      improvement_actions#update
                                              DELETE /performance_indicators/:performance_indicator_id/improvement_actions/:id(.:format)      improvement_actions#destroy
                       performance_indicators GET    /performance_indicators(.:format)                                                        performance_indicators#index
                                              POST   /performance_indicators(.:format)                                                        performance_indicators#create
                    new_performance_indicator GET    /performance_indicators/new(.:format)                                                    performance_indicators#new
                   edit_performance_indicator GET    /performance_indicators/:id/edit(.:format)                                               performance_indicators#edit
                        performance_indicator GET    /performance_indicators/:id(.:format)                                                    performance_indicators#show
                                              PATCH  /performance_indicators/:id(.:format)                                                    performance_indicators#update
                                              PUT    /performance_indicators/:id(.:format)                                                    performance_indicators#update
                                              DELETE /performance_indicators/:id(.:format)                                                    performance_indicators#destroy
                      like_improvement_action PUT    /improvement_actions/:id/like(.:format)                                                  improvement_actions#upvote
                    unlike_improvement_action PUT    /improvement_actions/:id/unlike(.:format)                                                improvement_actions#downvote
                  improvement_action_comments GET    /improvement_actions/:improvement_action_id/comments(.:format)                           comments#index
                                              POST   /improvement_actions/:improvement_action_id/comments(.:format)                           comments#create
               new_improvement_action_comment GET    /improvement_actions/:improvement_action_id/comments/new(.:format)                       comments#new
              edit_improvement_action_comment GET    /improvement_actions/:improvement_action_id/comments/:id/edit(.:format)                  comments#edit
                   improvement_action_comment GET    /improvement_actions/:improvement_action_id/comments/:id(.:format)                       comments#show
                                              PATCH  /improvement_actions/:improvement_action_id/comments/:id(.:format)                       comments#update
                                              PUT    /improvement_actions/:improvement_action_id/comments/:id(.:format)                       comments#update
                                              DELETE /improvement_actions/:improvement_action_id/comments/:id(.:format)                       comments#destroy

取消资源嵌套意味着可以通过很少的环节来跳过。

class CommentsController < ApplicationController

  before_action :set_improvement_action

  # GET /improvement_actions/:improvement_action_id/comments/new
  def new
    @comment = @improvement_action.comments.new 
  end

  # POST /improvement_actions/:improvement_action_id/comments
  def create
    @comment = @improvement_action.comments.new(comment_params) do |c|
      # @todo - you should associate comment with the user who created it at some point.
      # c.author = current_user
    end

    # note that you where saving the record twice!
    if @comment.save
      format.html { redirect_to [@improvement_action.performance_indicator, @improvement_action], notice: 'Comment was successfully created.' }
      format.json { render :show, status: :created, location: [@improvement_action, @comment] }        
    else
      format.html { render :new }
      format.json { render json: @comment.errors, status: :unprocessable_entity }
    end
  end

  # ...

  private

    def comment_params
      params.require(:comment).permit(:body)
    end

    def set_improvement_action
      @improvement_action = ImprovementAction.includes(:comments)
                              .find(params[:improvement_action_id])
    end

end

如果可能,您应该在控制器端使用新记录处理播种。

<%= form_for([@improvement_action, @comment]) do |f| %>
  <div class="field">
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </div>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>