Controller中的ActiveRecord :: AssociationTypeMismatch#在下拉列表中创建Rails自联接

时间:2018-01-19 04:25:50

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

我在Rails 5中自我加入时收到ActiveRecord :: AssociationTypeMismatch错误,我无法弄清楚如何修复。

这是一个简单的rails应用程序,用户可以分享艺术家(如David Bowie)关于另一位艺术家(如Lou Reed)的引用。所以,引用可能如下所示:

引用 主题:大卫鲍伊 内容:"他是大师。" 演讲者:Lou Reed

我有一个Quote模型和一个Artist模型,主题和演讲者被定义为Artist模型的自连接。

以下是模型:

class Artist < ApplicationRecord
  default_scope -> { order(name: :asc) }

  belongs_to :user

  has_many :spoken_quotes, class_name: "Quote", foreign_key: :speaker_id
  has_many :topic_quotes,  class_name: "Quote", foreign_key: :topic_id

  validates :user_id, presence: true
  validates :name,    presence: true, length: { maximum: 60 },
                      uniqueness: { case_sensitive: false }
end

class Quote < ApplicationRecord
  default_scope -> { order(created_at: :desc) }

  belongs_to :user

  belongs_to :speaker, class_name: "Artist"
  belongs_to :topic,   class_name: "Artist"

  validates :speaker, uniqueness: {scope: :topic}
  validates :topic,   uniqueness: {scope: :speaker}

  validates :user_id, presence: true
  validates :content, presence: true, length: { maximum: 1200 }
  validates :source,  presence: true, length: { maximum: 60 }

end

这是数据库架构:

create_table "artists", force: :cascade do |t|
    t.string "name"
    t.integer "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["user_id", "created_at"], name: "index_artists_on_user_id_and_created_at"
    t.index ["user_id"], name: "index_artists_on_user_id"
  end

  create_table "quotes", force: :cascade do |t|
    t.integer "user_id"
    t.integer "artist_id"
    t.text "content"
    t.string "source"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["artist_id", "created_at"], name: "index_quotes_on_artist_id_and_created_at"
    t.index ["artist_id"], name: "index_quotes_on_artist_id"
    t.index ["user_id", "created_at"], name: "index_quotes_on_user_id_and_created_at"
    t.index ["user_id"], name: "index_quotes_on_user_id"
  end

以下是我的报价控制器中的相关代码:

  def create
    @quote = current_user.quotes.build(quote_params)
    if @quote.save
      flash[:success] = "Quote created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end

  def quote_params
      params.require(:quote).permit(:content, :source, :topic, :artist_id)
  end

新报价单上的报价主题(艺术家)的下拉列表:

<%= f.collection_select :topic, Artist.all, :id, :name %>

下拉列表看起来很好并且似乎正确地创建了关联,但是当我提交表单时,我收到以下错误:

Artist(#70317289606580) expected, got "15" which is an instance of String(#70317259521760)

错误消息突出显示了create操作中的第一行:     @quote = current_user.quotes.build(quote_params)

我定义我的params错了吗?我的创建操作导致此错误有什么问题。在研究了一堆并尝试各种解决方案之后,我似乎无法弄明白。

2 个答案:

答案 0 :(得分:2)

李 -

您的QuoteArtist型号看起来不错。但是,您的架构是错误的。它应该看起来像:

create_table "artists", force: :cascade do |t|
  t.integer  "user_id"
  t.string   "name"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

create_table "quotes", force: :cascade do |t|
  t.integer  "user_id"
  t.integer  "speaker_id"
  t.integer  "topic_id"
  t.text     "content"
  t.string   "source"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

注意speaker_idtopic_id而不是artist_id

我需要查看您的堆栈跟踪,以了解您如何设置其他内容可能出现的问题。

顺便说一下,你修复了你的params白名单吗?这是错的:

def quote_params
  params.require(:quote).permit(:content, :source, :topic, :artist_id)
end

因为你的params看起来像:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"7xXgP3T1ZyxVhnr9TtBxeuYSRLBiuX01JSkQ4m4rN9pBS1W0iW6TJtsS7KyvunpCIZFiFltmdEwZGIYqsnxbyw==", "quote"=>{"topic_id"=>"2", "speaker_id"=>"1", "content"=>"asdfadsf", "source"=>"http://fuzz.com"}, "commit"=>"Post"}

应该是:

def quote_params
  params.require(:quote).permit(:content, :source, :topic_id, :speaker_id)
end

在黑暗中拍摄,尝试更改:

validates :speaker, uniqueness: {scope: :topic}
validates :topic,   uniqueness: {scope: :speaker}

要:

validates :speaker_id, uniqueness: {scope: :topic_id}
validates :topic_id,   uniqueness: {scope: :speaker_id}

如果出现问题,我会更新解释。

答案 1 :(得分:0)

尝试使用以下选项更改您的选择:

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css"/>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
<div class="ui">
  <label for="autocompleteGood">Name: </label>
  <input id="autocompleteGood">
</div>

并在您的控制器上允许<%= f.collection_select :topic_id, Artist.all, :id, :name %>

topic_id

您可以在params.require(:quote).permit(:content, :source, :topic_id, :artist_id) 中传递object作为belongs_to关联的参数:

rails c

并且Rails会休息,但是您无法通过http请求传递对象,而是应该传递对象的ID。

<强>更新

我很困惑你想如何将Quote与仅在Quote.new(topic: Artist.first) 表上artist_id列的发言人(艺术家)和主题(艺术家)绑定?您似乎应该有不同的列来存储这些连接。然后,您就可以使用列名称来选择名称。