(前言/免责声明:我想知道我应该学习什么是为了防止将来出现这样的错误。我是编程新手,并且一整天都在阅读强大的参数,但它似乎没有解决问题)
我有两个模型:艺术家(父母)和歌曲(儿童),具有has_many / belongs_to关系。我使用一个嵌套的属性form_for @parent来创建一个子对象,我的所有代码都在parents_controller中。 (User和Child之间也有一个连接表,在代码中称为“UserSong”。
一切都被创造得很好,但是当我点击孩子的节目页面上的“编辑”时,我得到一个包含所有子对象的表单,而不仅仅是我点击的特定子对象 - 而不是我想要的,但是主要问题是,当我继续编辑子对象并按“提交”时,我得到NoMethodError in ParentsController#update
,指定private method ‘update’ called for nil:NilClass
,我根本无法摆脱。< / p>
突出显示的代码行是if @parent.update(parent_params)
,我在下面的代码中以粗体显示。
parents_controller:
class ArtistsController < ApplicationController
before_action :authenticate_user!
def create
@artist = Artist.find_or_create_by(name: params[:artist][:name].strip.titleize)
@song = @artist.songs.find_or_create_by(title: params[:artist][:songs_attributes]["0"][:title].strip.titleize) do |song|
song.lyrics = params[:artist][:songs_attributes]["0"][:lyrics].strip
end
@user_song = current_user.user_songs.find_or_create_by(song_id: @song.id) do |user_id|
user_id.user_id = current_user.id
end
redirect_to root_path
end
def index
@songs = Song.all
end
def new
@artist = Artist.new
@artist.songs.build
@user_song = UserSong.new(user_id: current_user.id, song_id: @song)
end
def show
@song = Song.find(params[:id])
end
def destroy
UserSong.where(:song_id => params[:id]).first.destroy
flash[:success] = "The song has been removed from your playlist"
redirect_to root_path
end
def edit
@song = Song.find(params[:id])
@artist = @song.artist
end
def update
respond_to do |format|
if @artist.update(artist_params)
format.html { redirect_to session.delete(:return_to), notice: 'Song/Artist was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: @artist.errors, status: :unprocessable_entity }
end
end
end
private
def artist_params
params.require(:artist).permit(:id, :name, songs_attributes: [:id, :title, :lyrics])
end
end
表格如下:
<%= form_for @artist do |f| %>
<div class="form-group">
<%= f.text_field :name, placeholder: "Artist", class: "form-control" %>
</div>
<%= f.fields_for :songs do |p| %>
<div class="form-group">
<%= p.text_field :title, placeholder: "Song title", class: "form-control" %>
<br />
<%= p.text_area :lyrics, placeholder: "Input lyrics here", rows: 20, class: "form-control" %>
</div>
<% end %>
<div class="form-group">
<%= f.submit "Add song" %>
</div>
<% end %>
任何指向正确方向的线索都会非常感激!
编辑:如果有帮助,我已经发布了以下相关路线:
artists GET /artists(.:format) artists#index
POST /artists(.:format) artists#create
new_artist GET /artists/new(.:format) artists#new
edit_artist GET /artists/:id/edit(.:format) artists#edit
artist GET /artists/:id(.:format) artists#show
PATCH /artists/:id(.:format) artists#update
PUT /artists/:id(.:format) artists#update
DELETE /artists/:id(.:format) artists#destroy
songs GET /songs(.:format) artists#index
POST /songs(.:format) artists#create
new_song GET /songs/new(.:format) artists#new
edit_song GET /songs/:id/edit(.:format) artists#edit
song GET /songs/:id(.:format) artists#show
PATCH /songs/:id(.:format) artists#update
PUT /songs/:id(.:format) artists#update
DELETE /songs/:id(.:format) artists#destroy
答案 0 :(得分:0)
请求失败,因为更新操作中@artist
为nil,您需要使用以下内容加载值:
@artist = Artist.find(params[:id])
实例变量一次只存在于请求范围内,因此您始终需要加载每个请求所需的值。 (就像在显示/编辑操作中加载@song
值一样。
此外,所有子对象加载的原因是<%= f.fields_for :songs do |p| %>
加载了所有艺术家的歌曲(相当于调用@artist.songs
。如果您只想要一首歌,请尝试:< / p>
<%= f.fields_for :songs, @song do |p| %>
这将只为一首歌加载fields_for
列表。