Вложенные ресурсы в рельсы

Я пытаюсь создать простое приложение для рельсов, в котором пользователи могут создавать любое количество списков воспроизведения. Я очень новичок в рельсах, и мне интересно, следует ли мне вкладывать ресурсы следующим образом:

Rails.application.routes.draw do
  resources :users do
    resources :playlists
  end

Выполнение этого таким образом дает это, когда я rake routes:

            Prefix Verb   URI Pattern                                  Controller#Action
    user_playlists GET    /users/:user_id/playlists(.:format)          playlists#index
                   POST   /users/:user_id/playlists(.:format)          playlists#create
 new_user_playlist GET    /users/:user_id/playlists/new(.:format)      playlists#new
edit_user_playlist GET    /users/:user_id/playlists/:id/edit(.:format) playlists#edit
     user_playlist GET    /users/:user_id/playlists/:id(.:format)      playlists#show
                   PATCH  /users/:user_id/playlists/:id(.:format)      playlists#update
                   PUT    /users/:user_id/playlists/:id(.:format)      playlists#update
                   DELETE /users/:user_id/playlists/:id(.:format)      playlists#destroy
             users GET    /users(.:format)                             users#index
                   POST   /users(.:format)                             users#create
          new_user GET    /users/new(.:format)                         users#new
         edit_user GET    /users/:id/edit(.:format)                    users#edit
              user GET    /users/:id(.:format)                         users#show
                   PATCH  /users/:id(.:format)                         users#update
                   PUT    /users/:id(.:format)                         users#update
                   DELETE /users/:id(.:format)                         users#destroy
              root GET    /                                            default_pages#home
            signup GET    /signup(.:format)                            users#new
            signin GET    /signin(.:format)                            users#signin

Я могу успешно добраться до /users/1/playlists, в котором у меня есть эта ссылка (внутри index.html.erb плейлистов):

<%= link_to 'New Playlist', new_user_playlist_path(params[:user_id])%>

Но щелкнув по нему, я получаю эту ошибку:

     undefined method `playlists' for nil:NilClass

   Extracted source (around line #18):
   16       # GET /playlists/new
   17       def new
   18         @playlist = @user.playlists.new
   19       end
   20       # GET /playlists/1/edit

Вот как выглядит мой playlist_controller:

class PlaylistsController < ApplicationController
  before_action :set_playlist, only: [:show, :edit, :update, :destroy]
                :set_user

  # GET /playlists
  # GET /playlists.json
  def index
    @playlists = Playlist.all
  end

  # GET /playlists/1
  # GET /playlists/1.json
  def show
  end

  # GET /playlists/new
  def new
    @playlist = @user.playlists.new
  end

  # GET /playlists/1/edit
  def edit
  end

  # POST /playlists
  # POST /playlists.json
  def create
    @playlist = @user.playlists.new(playlist_params)

    respond_to do |format|
      if @playlist.save
        format.html { redirect_to @user.playlist, notice: 'Playlist was successfully created.' }
        format.json { render :show, status: :created, location: @playlist }
      else
        format.html { render :new }
        #format.json { render json: @playlist.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /playlists/1
  # PATCH/PUT /playlists/1.json
  def update
    respond_to do |format|
      if @playlist.update(playlist_params)
        format.html { redirect_to @playlist, notice: 'Playlist was successfully updated.' }
        format.json { render :show, status: :ok, location: @playlist }
      else
        format.html { render :edit }
        format.json { render json: @playlist.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /playlists/1
  # DELETE /playlists/1.json
  def destroy
    @playlist.destroy
    respond_to do |format|
      format.html { redirect_to playlists_url, notice: 'Playlist was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    def set_user
      @user = User.find_by(params[:user_id])
    end
    # Use callbacks to share common setup or constraints between actions.
    def set_playlist
      @playlist = Playlist.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def playlist_params
      params.require(:playlist).permit(:user_id, :title, :img)
    end
end

Я думаю, что поскольку ожидаемый URL-адрес должен выглядеть примерно так: users/1/playlists/1, мне нужно передать две переменные, одну для user_id и одну для идентификатора списка воспроизведения (какого-то рода), но я этого не делаю. точно знаю, где/как... Кто-нибудь может мне помочь?

Спасибо


person user2804881    schedule 09.11.2014    source источник
comment
Вы настроили отношения в модели User? has_many :playlists   -  person dasnixon    schedule 09.11.2014
comment
Кроме того, вы можете использовать @user.playlists.build. Обратите внимание на .build, который автоматически установит соответствующий внешний ключ.   -  person dasnixon    schedule 09.11.2014
comment
У меня уже есть соответствующие настройки моделей, спасибо. Где бы я использовал .build?   -  person user2804881    schedule 09.11.2014
comment
Когда вы устанавливаете @playlist под действием new. @playlist = @user.playlists.build. Кроме того, я не думаю, что вы хотите, чтобы Playlist.all было меньше index. Поскольку плейлист связан с User, вероятно, должен быть @playlists = @user.playlists   -  person dasnixon    schedule 09.11.2014
comment
Это имеет большой смысл, спасибо! Я еще не понял этого, так как просто копирую учебник и исправляю ошибки, когда иду учиться.   -  person user2804881    schedule 09.11.2014


Ответы (1)


Думаю проблема в before_action, поэтому @user не ставится. Попробуйте добавить еще раз before_action под строкой before_action :set_playlist, only: [:show, :edit, :update, :destroy]

class PlaylistsController < ApplicationController
  before_action :set_playlist, only: [:show, :edit, :update, :destroy]
  before_action :set_user, only: [:new, :create]

  ...
end

UPD

Я нашел еще одно место. Попробуйте использовать @user внутри вашего представления. new_user_playlist_path(@user), он уже должен быть создан из before_action

person Bob    schedule 09.11.2014
comment
Сначала я получил эту ошибку: ActiveRecord::InverseOfAssociationNotFoundError в PlaylistsController#new Не удалось найти обратную ассоциацию для пользователя (:playlist в User) И я вспомнил, что у меня было это в моей модели Playlist: class Playlist ‹ ActiveRecord::Base created_to : user, inverse_of: :playlist проверяет :user_id, присутствие: true end Но я никогда не понимал, зачем мне нужна часть inverse_of:. После удаления inverse_of: :playlist я попробовал еще раз, и это сработало! Вы знаете, зачем мне нужна часть inverse_of? Какой цели это служит? - person user2804881; 09.11.2014
comment
Некоторую информацию можно найти здесь: guides.rubyonrails.org/ - person Bob; 09.11.2014