parent_params:更新嵌套属性

时间:2017-01-23 22:00:01

标签: ruby-on-rails

(前言/免责声明:我想知道我应该学习什么是为了防止将来出现这样的错误。我是编程新手,并且一整天都在阅读强大的参数,但它似乎没有解决问题)

我有两个模型:艺术家(父母)和歌曲(儿童),具有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

1 个答案:

答案 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列表。