公共活动上的未定义方法`destroy'

Min*_*ohn 1 methods ruby-on-rails ruby-on-rails-4

用户可以在屏幕上发表评论,并由PublicActivity跟踪:

@comment.create_activity :create, owner: current_user, recipient: @comment.screen.user
Run Code Online (Sandbox Code Playgroud)

并且注释依赖于::在屏幕模型上销毁.

但是当我删除屏幕时,删除注释时,该注释的PublicActivity记录仍然存在.

这是我的Screens Controller:

  def destroy
    @activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
    @activity.destroy #<-- Heres the Problem
    @screen.destroy
    respond_to do |format|
      format.html { redirect_to root_path }
      format.json { head :no_content }
    end
  end
Run Code Online (Sandbox Code Playgroud)

但是在删除屏幕后,我正在undefined method为'nil:NilClass`进行破坏.

我在Railscast上读到:

这是因为在对象被销毁之后调用了create_activity方法.

根据gem维护者的说法,你只需假设记录将被销毁,并在销毁之前调用create_activity

我错过了什么?

以下信息

screen.rb

belongs_to :user
has_many :comments, :dependent =>  :destroy
Run Code Online (Sandbox Code Playgroud)

comment.rb

belongs_to :user
belongs_to :screen
Run Code Online (Sandbox Code Playgroud)

screens_contoller.rb

  def create
    @screen = current_user.screens.build(screen_params)
    respond_to do |format|
      if @screen.save
         format.html { redirect_to @screen, notice: 'You successfully uploaded your Screenshot.' }
        format.json { render action: 'show', status: :created, location: @screen }
        current_user.add_points(2, 'Points for Uploading a Screenshot')
      else
        format.html { render action: 'new' }
        format.json { render json: @screen.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
    @activity.destroy
    @screen.destroy
    respond_to do |format|
      format.html { redirect_to root_path }
      format.json { head :no_content }
      current_user.substract_points(1, "Substraction for Deleting a Screenshot")
    end
  end
Run Code Online (Sandbox Code Playgroud)

comments_controller.rb

  def create
    @screen = Screen.find(params[:screen_id])
    @comment = current_user.comments.build(comment_params)
    @comment.screen_id = @screen.id
    respond_to do |format|
      if @comment.save
        # Create Record for Public Activity
        @comment.create_activity :create, owner: current_user, recipient: @comment.screen.user
        format.html { redirect_to @screen, notice: 'Comment was successfully created.' }
        format.json { render action: 'show', status: :created, location: @comment }
      else
        format.html { render action: 'new' }
        format.json { render json: @comment.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @comment.destroy
    respond_to do |format|
      @activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
      @activity.destroy
      format.html { redirect_to :back }
      format.json { head :no_content }
    end
  end
Run Code Online (Sandbox Code Playgroud)

这就是我的Screen Controller Destroy Action现在的样子:

  def destroy
    @screen = current_user.screens.find(params[:id])
    @activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
    @activity.destroy
    @screen.destroy
    current_user.substract_points(1, "Substraction for Deleting a Screenshot")
    respond_to do |format|
      format.html { redirect_to root_path }
    end
  end
Run Code Online (Sandbox Code Playgroud)

同样的错误:

在此输入图像描述

its*_*way 5

这没有经过测试,但我认为你应该这样做.

首先,您可以删除screen_controller#destroy中对活动的引用

然后在你的comments_controller#destroy中

  @comment = current_user.comments.find(params[:id])
  @activity = PublicActivity::Activity.find_by(trackable_id: (params[:id]), trackable_type: controller_path.classify)
  @activity.destroy
  @comment.destroy
Run Code Online (Sandbox Code Playgroud)

应该在你的回应之外阻止

接下来在您的评论模型中,您应该执行以下操作:

#comment.rb

private

before_destroy :find_and_destroy_comments

def find_and_destroy_comments
  activity = PublicActivity::Activity.find_by(trackable_id: self.id, trackable_type: self.class.name)
  if activity.present?
    activity.destroy
  end
end
Run Code Online (Sandbox Code Playgroud)

调用before_destroy方法会覆盖在调用期间调用的默认ruby destroy方法 dependent: :destroy

让我知道这是否有效,但它应该.