【问题标题】:ActiveRecord::StatementInvalid in ControllerNameController#create SQLite3::SQLException: no such column:ActiveRecord::StatementInvalid in ControllerNameController#create SQLite3::SQLException: 没有这样的列:
【发布时间】:2016-08-24 00:08:50
【问题描述】:

我有一个通过 has_many :through 关系加入的“歌曲”和“艺术家”模型。在点击“创建歌曲”后,我得到了这个持续错误:

  • ActiveRecord::StatementInvalid 在 SongsController#create 中 SQLite3::SQLException: 没有这样的列:songs.artist: SELECT 1 AS one FROM "songs" WHERE ("songs"."name" = 'So much more' AND "songs"."artist" IS NULL) LIMIT 1

这是来自模型和视图的代码

song.rb

class Song < ActiveRecord::Base
belongs_to :genre

has_many :artists_songs
has_many :artists, :through => :artists_songs

has_attached_file :image, styles: { large: "600x600>", medium: "300x300>", thumb: "150x150#{}" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/

accepts_nested_attributes_for :artists, allow_destroy: true
accepts_nested_attributes_for :artists_songs, allow_destroy: true

validates :name, :presence => true, uniqueness: { scope: :artist } #Unique names in the scope of PARENT
#4now 'featured, description, genre_id, video' is missing because they aren't really a must, the rest perhaps are
validates :year, :lyrics, :country, :image, :presence => true

结束

艺术家.rb

class Artist < ActiveRecord::Base
belongs_to :country 

has_many :artists_songs
has_many :songs, :through => :artists_songs

has_attached_file :image, styles: { large: "600x600>", medium: "300x300>", thumb: "150x150#{}" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/

validates :name, :presence => true, uniqueness: true
validates :country_id, :image, :presence => true

结束

artists_song.rb“Song”和“Artist”的连接模型

class ArtistsSong < ActiveRecord::Base
  belongs_to :song
  belongs_to :artist 
end

songs_controller.rb

class SongsController < ApplicationController
before_action :find_song, only: [:show, :edit, :update, :destroy]

def index
    @songs = Song.all
end

def new
    @song = Song.new
    @song.artists.build
    #@genres = Genre.all.map{|c| [ c.name, c.id ] }
end

def create
    @song = Song.new(song_params)
    if @song.save
        redirect_to @song, notice: 'Successfully added a song.'
    else
        render 'index'
    end
end

def show

end

def update
    if @song.update(song_params)
        redirect_to @song, notice: 'Successfully updated the song.'
    else
        render 'edit', notice: 'Unable to save the changes'
    end
end

def edit 
end

def destroy
end

#private methods/functions
private 

#In this private method, the artists attributes are passed to be created via the Song model
def song_params
    params.require(:song).permit(:name, :featured, :year, :lyrics, :description, :video, :image, :genre_id, :artists_song_list, artists_attributes: [ :name, :image, :country_id ])
end

def find_song
    @song = Song.find(params[:id])
end

new.html.erb(-songs_controller)

<div class="content">
<%= form_for @song, html: { multipart: true } do |f| %>

    <% if @song.errors.any? %>
        <div>
            <%= @song.errors.count %>
            Prevented this song from saving
            <ul>
                <% @song.errors.full_messages.each do |msg| %>
                    <li><%= msg %></li>
                <% end %>
            </ul>
        </div>
    <% end %>

    <div class="field">
        <%= f.label :name %>
        <%= f.text_field :name %><br>
    </div>

    <div class="artist-fields">
        <h2>Artist(s)</h2>
        <div class="field">
            <%= f.fields_for :artists do |artists_for_form| %>
                <%= render 'artist_fields', f: artists_for_form %>
            <% end %>
        </div>
    </div>

    <div class="field"> 
        <%= f.label :featured %>
        <%= f.text_field :featured%><br>
    </div>
    <div class="field"> 
        <%= f.label :lyrics %>
        <%= f.text_area :lyrics %><br>
    </div>

    <div class="field">
        <%= f.label :genre %>
        <%= select_tag(:genre_id, options_for_select(@genres), :prompt => "Select one!") %>
    </div>


    <div class="field">
        <%= f.label :description %>
        <%= f.text_area :description %><br>
    </div>  
    <div class="field">
        <%= f.label :year %>
        <%= f.text_field :year %><br>
    </div>

    <div class="field">
        <%= f.label :video %>
        <%= f.text_field :video %><br>
    </div>

    <div class="field">
        <%= f.label :image %>
        <%= f.file_field :image %>
    </div>

    <div class"btn">
        <%= f.submit %> 
    </div>

    <%= link_to "Back", root_path %>

<% end %>

我做错了什么以及如何正确实现 has_many :through 关系在 rails 4 中?

三个表的列名(Song、Artist、ArtistsSong)

 irb(main):001:0> Song.column_names
 => ["id", "name", "featured", "lyrics", "description", "comments", "created_at", "updated_at", "video", "year", "image_file_name", "image_content_type", "image_file_size", "image_updated_at", "genre_id"]

 irb(main):002:0> Artist.column_names
 => ["id", "name", "created_at", "updated_at", "country_id", "—force", "image_file_name", "image_content_type", "image_file_size", "image_updated_at"]

 irb(main):003:0> ArtistsSong.column_names
=> ["id", "song_id", "artist_id", "created_at", "updated_at"]

【问题讨论】:

  • 您进行了迁移吗?您的 schema.rb 是否反映了所需的表和字段?
  • @Alfie 是的,我确实运行了所有迁移并计数器检查了所有 3 个表的列名。
  • + 我已经附加了每个表 column_names 的控制台输出...
  • 能否也包括您的错误堆栈跟踪。
  • 我不确定,是在终端上运行“puts caller”还是在错误页面上展开“Framework trace/Full Trace”时的输出[localhost:3000] ?我是 RoR 的新手……

标签: ruby-on-rails ruby activerecord sqlite


【解决方案1】:

通过将artists_songs_attributes[:id, artist_id, song_id] 包含到songs_controller 中的song_params 方法,可以成功地添加一首歌曲,并在歌曲 和 artist 表通过连接表 artists_song

因此,而不是这个:

    def song_params
        params.require(:song).permit(:name, :featured, :year, :lyrics, :description, :video, :image, :genre_id, :artists_song_list, artists_attributes: [ :name, :image, :country_id ])
    end

这行得通:

    def song_params
        params.require(:song).permit(:name, :featured, :year, :lyrics, :description, :video, :image, :genre_id, :artists_song_list, artists_attributes: [ :name, :image, :country_id ], artists_songs_attributes[:id, artist_id, song_id])
    end

我还是新手,正在学习 Ruby on Rails 框架,因此,根据我目前的了解,artists_songs_attributes [:id, artist_id, song_id] 需要传递给加入表(artists_song)创建实际创建两个表(artist & song)的已创建行之间的链接的行。

【讨论】:

    猜你喜欢
    • 2013-10-09
    • 1970-01-01
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    • 2016-12-08
    • 1970-01-01
    相关资源
    最近更新 更多