2017-01-23 5 views
1

(Предисловие/отказ от ответственности: Я хотел бы знать, что я должен изучить, чтобы предотвратить такие ошибки в будущем. Я новичок в программировании и читал о сильных параметрах день, но, похоже, это не решило проблему)parent_params: обновить вложенные атрибуты

У меня есть две модели: Исполнитель (Родитель) и Песня (Ребенок) с отношением has_many/belongs_to. Я использую вложенные атрибуты form_for @parent, чтобы создать дочерний объект, со всем моим кодом в parent_controller. (Существует также таблица соединений между пользователем и дочерним элементом, называемая «UserSong» в коде).

Все создается хорошо, но когда я нажимаю «редактировать» на странице показа для ребенка, я получаю форму со всеми дочерними объектами, а не только с определенным дочерним объектом, на который я нажал, - не то, что я хочу, но основная проблема заключается в том, что когда я потом перехожу к редактированию дочернего объекта и нажимаю «submit», я получаю NoMethodError in ParentsController#update, указав private method ‘update’ called for nil:NilClass, что я просто просто не могу избавиться.

Строка кода, которая подсвечивается, - 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

запрос не потому, что @artist равна нулю в своем действии обновления, вам необходимо загрузить значение с чем-то вроде:

@artist = Artist.find(params[:id]) 

Переменные экземпляра существуют только в объеме запроса за раз, поэтому вам всегда нужно загружать значения, необходимые для каждого запроса. (Например, как вы загружаете значение @song в шоу/редактирования действий.

Кроме того, причиной того, что все дочерние объекты нагрузки, что <%= f.fields_for :songs do |p| %> загружает все песни художника (это эквивалентно вызову @artist.songs. Если вы только что хочу одну песню, попробуйте:..

<%= f.fields_for :songs, @song do |p| %> 

Это загрузит fields_for для списка с помощью только одной песни

+0

Это сделал ты человек Два дня отладки решены в течение 5 минут ... Я не уверен, что я должен чувствовать себя вне себя от радости или раздражать себя ... lol – michaelsking1993

+0

Девять times из десяти ноль ошибок возникают из-за неспособности инициализировать переменную (один из недостатков Ruby). – chrismanderson

+0

Почему это недостаток? – michaelsking1993

Смежные вопросы