【问题标题】:Saving a record that relies on two tables保存依赖于两个表的记录
【发布时间】:2020-03-23 21:50:49
【问题描述】:

正在开发我的第一个 Rails 应用程序。 我有两个模型:专辑和曲目。

向专辑添加曲目时,我需要专辑 ID 才能保存。 我有一个collection_select,它可以拉出所有专辑并按降序列出它们的ID:

<%= form.collection_select :albums_id, Album.all.order(id: :desc), :id, :title, :include_blank => false %>

这工作正常,创建 html:

<select name="track[albums_id]" id="track_albums_id">
  <option value="11">Eleventh Album Title</option>
  <option value="10">Tenth Album Title</option>
  ...
</select>

但是当我尝试保存新记录时,我总是得到错误: Album must exist

控制器有:

 def create
   @track = Track.new(track_params)

   respond_to do |format|
     if @track.save
       format.html { redirect_to @track, notice: 'Track added.' }
       format.json { render :show, status: :created, location: @track }
     else
       @page_title = 'ERROR - Add Track'
       format.html { render :new }
       format.json { render json: @track.errors, status: :unprocessable_entity }
     end
   end
 end

track_params指的是:

private
  def track_params
    params.require(:track).permit(:albums_id, :title, :track_number, :track_url)
  end

型号:

专辑.rb

class Album < ApplicationRecord
    has_many :tracks
    validates :title, presence: true
    validates :release_year, presence: true
    has_one_attached :photo
end

track.rb

class Track < ApplicationRecord
    belongs_to :album
    validates :title, presence: true
    validates :track_number, presence: true
    validates :track_url, presence: true
end

routes.rb

Rails.application.routes.draw do
  resources :tracks
  root 'pages#about'

  get 'signup', to: 'users#new', as: 'signup'
  get 'login', to: 'sessions#new', as: 'login'
  get 'logout', to: 'sessions#destroy', as: 'logout'
  get 'contact', to: 'messages#new', as: 'contact'
  get 'sessions', to: 'sessions#new'
  get 'dashboard', to: 'pages#dashboard', as: 'dashboard'

  resources :videos
  resources :gigs
  resources :photos
  resources :albums
  resources :users
  resources :groups
  resources :messages
  resources :sessions, only: [:new, :create, :destroy]

  post "/delayed_job" => DelayedJobWeb, :anchor => false
end

接受除:albums_id 之外的所有值。 collection_select 中的选定值始终被忽略并触发阻止保存轨道的错误。 albums_id 是数据库列名,由 rails 作为belongs_to: albums 的结果创建。

我做错了什么?

更新:迁移

...create_albums.rb:

class CreateAlbums < ActiveRecord::Migration[5.2]
  def change
    create_table :albums do |t|
      t.string :artist
      t.string :copyright
      t.string :title
      t.date :release_year
      t.text :comment

      t.timestamps
    end
  end
end

...create_tracks.rb:

class CreateTracks < ActiveRecord::Migration[5.2]
  def change
    create_table :tracks do |t|
      t.belongs_to :albums
      t.string :title
      t.integer :track_number, :default => 1
      t.string :track_url

      t.timestamps
    end
  end
end

【问题讨论】:

  • 您是否在某处关联记录?请显示您的模型文件和您的 routes.rb 文件。
  • @hashrocket 已添加到问题中。
  • 您确定数据库列名为albums_id。看起来应该叫album_id
  • 绝对叫album_id。我检查了 mysql CLI,如果我在没有复数词的情况下尝试它,我会收到 unknown column 类型错误。
  • 可以粘贴专辑和曲目的数据库迁移文件吗?理想情况下,您的模型应该是单数的,因此您生成像 rails g model Album 和 rails g model Track 这样的模型,rails 创建复数 db 表,它们是曲目和专辑。您的迁移文件中一定有问题。请分享一下

标签: controller ruby-on-rails-5 rails-activerecord


【解决方案1】:

您可以做的是遵循 Rails 约定,而不是绕过它。 您可以删除 Albums_id 列(有一种方法可以完成这项工作,但又是一种变通方法,不建议使用),因此 yiu 可以先删除 Albums_id 列,然后添加 Album_id,如下所示:

rails g migration DropColumnFromTrack

然后在生成的迁移文件中:

remove_column :tracks, :albums_id

那么做:(假设你在这一列没有数据)

rails db:migrate

现在生成album_id 列: 下面的 album:references 意味着我们告诉轨道表中的记录属于专辑表。

rails g migration AddAlbumToTrack album:references

然后做

rails db:migrate

确保您的曲目表中有一个 album_id 列,现在关联应该可以正常工作

【讨论】:

  • 我不知道为什么将album_id 创建为albums_id,但请一步一步地感谢您。它现在完美运行。只是花点时间让我了解一切是如何运作的。 :) 谢谢。 :)
  • 我想说尝试阅读 Rails 模型关联,特别是模型中单数和复数之间的区别。花点时间理解这一点,它将为您节省很多时间。
  • 是的,我还有很多东西要学。这些错误最终会帮助我理解。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-11
  • 1970-01-01
  • 2021-09-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多