简体   繁体   English

下拉菜单中的Controller#create中的ActiveRecord :: AssociationTypeMismatch选择用于Rails自连接

[英]ActiveRecord::AssociationTypeMismatch in Controller#create on dropdown select for a Rails self join

I'm getting an ActiveRecord::AssociationTypeMismatch error on my self join in Rails 5 that I can't figure out how to fix. 我在Rails 5的自连接中遇到ActiveRecord :: AssociationTypeMismatch错误,我不知道如何解决。

It's a simple rails app where a user can share a quote by an Artist (such as David Bowie) about another Artist (such as Lou Reed). 这是一个简单的Rails应用程序,用户可以在其中共享一个艺术家(例如David Bowie)对另一个艺术家(例如Lou Reed)的报价。 So, a quote might look like this: 因此,报价可能如下所示:

Quote Topic: David Bowie Content: "He was a master." 引用主题:David Bowie内容:“他是一个大师。” Speaker: Lou Reed 演讲者:娄·里德

I have a Quote model and an Artist model and the Topics and Speakers are defined as self joins on the Artist model. 我有一个Quote模型和一个Artist模型,并且Topics和Speakers被定义为Artist模型上的self joins。

Here are the models: 这些是模型:

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

Here's the database schema: 这是数据库模式:

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

Here's the relevant code from my Quotes Controller: 这是我的Quotes Controller中的相关代码:

  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

And the dropdown for the Topic of a Quote (which is an Artist) on the new Quote form: 在新的“报价”表单上,“报价主题”(这是一个艺术家)的下拉列表:

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

The dropdown looks fine and appears to be creating the association correctly, but when I submit the form I get the following error: 下拉列表看起来不错,并且似乎可以正确创建关联,但是当我提交表单时,出现以下错误:

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

And the error message highlights the first line in the create action: @quote = current_user.quotes.build(quote_params) 错误消息突出显示了create操作的第一行:@quote = current_user.quotes.build(quote_params)

Am I defining my params wrong? 我定义参数错误吗? What is wrong about my create action to cause this error. 我的创建操作导致此错误的原因是什么。 I can't seem to figure it out after researching it a bunch and trying various solutions. 经过大量研究并尝试了各种解决方案后,我似乎无法弄清楚。

Lee - 李-

Your Quote and Artist models look OK. 您的QuoteArtist模型看起来不错。 Your schema, however, is wrong. 但是,您的架构是错误的。 It should look like: 它应该看起来像:

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

Note speaker_id and topic_id instead of artist_id . 注意speaker_idtopic_id ,而不是artist_id

I'd need to see your stack trace to see what might be wrong with how you have other things set up. 我需要查看您的堆栈跟踪记录,以了解如何进行其他设置。

BTW, have you fixed your params whitelist? 顺便说一句,您是否已将参数白名单固定? This is wrong: 这是错误的:

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

Since your params look like: 由于您的参数看起来像:

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

It should be: 它应该是:

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

As a shot in the dark, try changing: 作为在黑暗中的镜头,请尝试更改:

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

To: 至:

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

I'll update with explanation if that's the problem. 如果这是问题,我将进行解释更新。

Try to change your select with: 尝试通过以下方式更改选择:

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

and permit topic_id with on your controller: 并允许在您的控制器上使用topic_id

params.require(:quote).permit(:content, :source, :topic_id, :artist_id)

You can pass on object as an argument for belongs_to association in rails c : 您可以在rails c中将object传递为belongs_to关联的参数:

Quote.new(topic: Artist.first) 

and Rails'll do rest, but you can't pass an object via http request, but instead you should pass an object's id. 和Rails会休息,但是您不能通过http请求传递对象,而是应该传递对象的ID。

Updated 更新

I'm confused about how do you want to bind Quote with speaker(Artist) and topic(Artist) having the artist_id column on quotes table only? 我对如何将报价与仅在quotes表上具有artist_id列的artist_id (Artist)和topic(Artist)进行绑定感到困惑? It seems you should have different columns to store these connections. 似乎您应该具有不同的列来存储这些连接。 And then you'll be able to use the name of the column for select's name. 然后,您将能够使用列的名称作为select的名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM