Rails:深度嵌套资源给出错误:未定义的方法"注释"



我在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 %>

这是我的评论控制器:

    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

这是我的绩效指标控制器:

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

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

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 %>

最新更新