将User对象传递给Notification模型时,为什么会收到ActiveRecord :: AssociationTypeMismatch?

时间:2019-02-04 19:52:03

标签: ruby-on-rails ruby activerecord

当我将带有参数的注释对象传递给Notification.create()对象时,我收到了User的ActiveRecord :: AssociationTypeMismatch。它说明我传入了一个Integer实例(可能是用户ID),而不是User对象本身。我不知道应该如何从注释对象中获取用户对象并将其传递给收件人列。我正在使用名为 acts_as_commentable_with_threading 的gem。如何将User对象的正确实例传递给Notification?

我试图通过链接comment.commentable.user来检索用户。其中返回了目标用户。但是,由于某种原因,它表明我不能使用该对象,因为它是整数类型而不是用户类型。错误如下。

ArrayIndexOutOfBoundsException

comments_controller.rb

Comment Load (1.0ms)  SELECT  "comments".* FROM "comments" WHERE "comments"."id" = $1 LIMIT $2 FOR UPDATE  [["id", 16], ["LIMIT", 1]]
  Comment Create (2.0ms)  INSERT INTO "comments" ("commentable_id", "commentable_type", "body", "user_id", "lft", "rgt", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"  [["commentable_id", 3], ["commentable_type", "Post"], ["body", "Damn"], ["user_id", 2], ["lft", 21], ["rgt", 22], ["created_at", "2019-02-04 18:23:47.285528"], ["updated_at", "2019-02-04 18:23:47.285528"]]
   (1.0ms)  COMMIT
Redirected to http://127.0.0.1:3000/posts/qQ7JeRcQxGXg
  User Load (1.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
Completed 500 Internal Server Error in 6196ms (ActiveRecord: 1466.1ms)



ActiveRecord::AssociationTypeMismatch (User(#211252000) expected, got 2 which is an instance of Integer(#3523260)):

app/controllers/comments_controller.rb:17:in `create'
Processing by ExceptionHandler::ExceptionsController#show as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"KnLViXrCG/67gbUFTQjFMq6eIt7AKvjG4dRgD0JSoPOCOfHqU0n0lVB9l3+lyAc0B+G3mgZ6dv8cG0v9LTvPuw==", "comment"=>{"commentable_id"=>"3", "commentable_type"=>"Post", "body"=>"Damn"}, "commit"=>"Comment"}
Completed 500 Internal Server Error in 285ms (ActiveRecord: 0.0ms)

评论架构

class CommentsController < ApplicationController
  before_action :authenticate_user!

  def create
    commentable = commentable_type.constantize.find(commentable_id)
    @comment = Comment.build_from(commentable, current_user.id, body)

    respond_to do |format|
      if @comment.save
        make_child_comment
        format.html {redirect_back(fallback_location: post_path(@comment))}
        format.js
      else
        format.html {render :action => :new}
      end
    end
    Notification.create(recipient: @comment.commentable.user, actor: current_user.id, action: "commented on your Post", notifiable: @comment.commentable.id, content: @comment.body.truncate(50).to_s)
#GenericCommentNotificationJob.perform_later(@comment.commentable.user, current_user.id, @comment, body)
  end

  def destroy
    @comment = Comment.find_by_id params[:id]

    respond_to do |format|
      if @comment.destroy
        format.html {redirect_to @comment.commentable}
      else
        format.html {redirect_to @comment.commentable, notice: t('error')}
      end
    end
  end

  private

  def comment_params
    params.require(:comment).permit(:body, :commentable_id, :commentable_type, :comment_id)
  end

  def commentable_type
    comment_params[:commentable_type]
  end

  def commentable_id
    comment_params[:commentable_id]
  end

  def comment_id
    comment_params[:comment_id]
  end

  def body
    comment_params[:body]
  end

  def make_child_comment
    return "" if comment_id.blank?

    parent_comment = Comment.find(comment_id)
    @comment.move_to_child_of(parent_comment)
  end
end

comment.rb

  create_table "comments", force: :cascade do |t|
    t.integer "commentable_id"
    t.string "commentable_type"
    t.string "title"
    t.text "body"
    t.string "subject"
    t.integer "user_id", null: false
    t.integer "parent_id"
    t.integer "lft"
    t.integer "rgt"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.bigint "post_id"
    t.index ["post_id"], name: "index_comments_on_post_id"
    t.index ["commentable_id", "commentable_type"], name: "index_comments_on_commentable_id_and_commentable_type"
    t.index ["user_id"], name: "index_comments_on_user_id"
  end

notification.rb

class Comment < ActiveRecord::Base
  acts_as_nested_set :scope => [:commentable_id, :commentable_type]
  validates :body, :presence => true
  validates :user, :presence => true

  # NOTE: install the acts_as_votable plugin if you
  # want user to like on the quality of comments.
  acts_as_votable

  belongs_to :commentable, :polymorphic => true

  # NOTE: Comments belong to a user
  belongs_to :user

  # Helper class method that allows you to build a comments
  # by passing a commentable object, a user_id, and comments text
  # example in readme
  def self.build_from(obj, user_id, comment)
    new \
      :commentable => obj,
      :body => comment,
      :user_id => user_id
  end

  #helper method to check if a comments has children
  def has_children?
    self.children.any?
  end

  # Helper class method to lookup all comments assigned
  # to all commentable types for a given user.
  scope :find_comments_by_user, lambda {|user|
    where(:user_id => user.id).order('created_at DESC')
  }

  # Helper class method to look up all comments for
  # commentable class name and commentable id.
  scope :find_comments_for_commentable, lambda {|commentable_str, commentable_id|
    where(:commentable_type => commentable_str.to_s, :commentable_id => commentable_id).order('created_at DESC')
  }

  # Helper class method to look up a commentable object
  # given the commentable class name and id
  def self.find_commentable(commentable_str, commentable_id)
    commentable_str.constantize.find(commentable_id)
  end
end

通知架构

class Notification < ApplicationRecord
  belongs_to :recipient, class_name: "User"
  belongs_to :actor, class_name: "User"
  belongs_to :notifiable, polymorphic: true
  scope :unread, -> {where(read_at: nil)}
end

实际结果:当用户尝试创建评论时,由于用户对象的活动记录类型不匹配,因此通知无法自行创建。

预期结果:用户创建评论,然后在成功提交评论后创建通知。

1 个答案:

答案 0 :(得分:1)

使用

Notification.create(recipient: @comment.commentable.user, actor_id: current_user.id, action: "commented on your Career Insight", notifiable: @comment.user, content: @comment.body.truncate(50).to_s)