Ошибка Rails Не удалось найти альбом без идентификатора - PullRequest
1 голос
/ 20 апреля 2020

Я пытаюсь отобразить все отзывы, написанные пользователем на странице показа пользователей. У пользователей много альбомов и отзывов. Отзывы принадлежат альбомам и пользователям. Альбомы имеют много отзывов и пользователей. Я хочу связать Review.title со страницей показа альбомов, принадлежащих этому обзору. Я довольно новичок в Rails, поэтому я не уверен, какой код добавить, чтобы сделать эту работу.

Ошибка:

ActiveRecord::RecordNotFound in UsersController#show
Couldn't find Album without an ID
Extracted source (around line #60):
58
59
60
61
62
63


    def find_album
        @album = Album.find(params[:album_id])
    end

    def user_params

контроллер пользователя

class UsersController < ApplicationController
    before_action :set_current_user, only: [:index, :show, :new, :edit, :destroy]
    #before_action :set_review, only: [:show, :edit, :update, :destroy]
    before_action :set_user, only: [:show, :edit, :update, :destroy]
    before_action :find_album, only: [:show, :create, :edit, :update, :destroy]
    before_action :must_login, only: [:index, :show, :new, :create, :edit, :update, :destroy]

    def index
        @users = User.all
    end

    def show
        @reviews = @user.reviews

    end

    def new
        @user = User.new
    end

    def create
        @user = User.new(user_params)
        if @user.save
            session[:user_id] = @user.id
            redirect_to albums_path
        else
            render :new
        end
    end

    def edit
    end

    def update
        @user.update(user_params(:name, :email, :password_digest))
        redirect_to user_path(@user)
    end

    def destroy
        @user = User.destroy
    end

    private

   # def set_review
   #     @review = Review.find(params[:id])
   # end

    def set_user
        @user = User.find(params[:id])
    end

    def set_current_user
        @user = current_user
    end

    def find_album
        @album = Album.find(params[:album_id])
    end

    def user_params
        params.require(:user).permit(:name, :email, :password, :password_confirmation)
    end
end

Модель пользователя:

class User < ApplicationRecord
    has_secure_password
    validates :email, uniqueness: true, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
    validates :name, uniqueness: true, length: {in: 3..20}, presence: true
    has_many :reviews
    has_many :albums, through: :reviews

    def self.from_omniauth(auth)
        where(provider: auth.provider, uid: auth.uid).first_or_initialize do |user|
          user.provider = auth.provider
          user.uid = auth.uid
          user.name = auth.info.name
          user.oauth_token = auth.credentials.token
          user.oauth_expires_at = Time.at(auth.credentials.expires_at)
          user.save!
        end
      end
end

rout.rb

Rails.application.routes.draw do
  get '/auth/:provider/callback' => 'sessions#omniauth'
  get 'auth/failure', to: redirect('/')
  get '/signup' => 'users#new', as: 'signup'
  post '/signup' => 'users#create'
  get '/signin' => 'sessions#new'
  post '/signin' => 'sessions#create'
  get '/signout' => 'sessions#destroy'
  post '/logout', to: "sessions#destroy"

  resources :albums do
    resources :reviews, except: [:index]
  end
  resources :users, only: [:show, :destroy]
  resources :reviews, only: [:index]

  root to: "albums#index"
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

users # show. html .erb


<p>Here is a list of Reviews you wrote:</p>
<% @reviews.each do |review| %>
        <%= link_to review.title, album_path(@album) %><br>
        <%= review.content %><br>
        <br>
<% end %>

<br>
<% if @user.reviews == nil? %>
<p>No reviews yet!</p>
<p>Choose from the list of albums to review <%= link_to "here!", albums_path %></p>
<% end %>

Контроллер альбомов

class AlbumsController < ApplicationController
    before_action :set_album, only: [:show, :edit, :update, :destroy]
    before_action :must_login, only: [:new, :show, :create, :edit, :update, :destroy]

    def index
        @albums = Album.all
        @user = current_user
    end

    def show
        @review = @album.reviews.build
        @review.user = current_user

        @review.save
        @reviews = Review.recent #scope
    end

    def new
        @album = Album.new
        @review = @album.reviews.build
        @user = current_user
    end

    def create
        #@user = User.find(current_user.id)
        @album = current_user.albums.build(album_params)
        #@album.user_id = current_user.id
        @album.reviews.each { |r| r.user ||= current_user } # I'm using ||= so i can use the same code on update without changing reviews that already have a user
        if @album.save
            redirect_to album_path(@album)
        else
            render :new
        end
    end

    def edit
        @user = current_user
    end

    def update
        #@album = current_user.albums.build(album_params)
        @album.user_id = current_user.id
        if @album.update(album_params)
            redirect_to album_path(@album), notice: "Your album has been updated."
        else
            render 'edit'
        end
    end

    def destroy
        @album.delete
        @album.avatar.purge
        redirect_to albums_path
    end

    private

    def set_album
        @album = Album.find(params[:id])
    end

    def album_params
        params.require(:album).permit(:artist, :title, :avatar, :user_id, reviews_attributes:[:title, :date, :content]) #removed the :user_id and :album_id from the permitted parameters for reviews_attributes, don't want users to exploit that assignation adding those parameters that I'm actually not using
    end
end

Отзывы контроллер

class ReviewsController < ApplicationController
    before_action :set_review, only: [:show, :edit, :update, :destroy]
    before_action :set_current_user, only: [:index, :show, :new, :edit, :destroy]
    before_action :find_album, only: [:show, :create, :edit, :update, :destroy]
    before_action :must_login, only: [:index, :show, :new, :create, :edit, :update, :destroy]

    def index
        @albums = Album.with_recent_reviews
    end

    def show

        #@reviews = Review.where("album_id = ?", params[:album_id])
    end

    def new
        if params[:album_id] && @album = Album.find_by(id: params[:client_id])
            @review = @album.reviews.build
        else
            redirect_to albums_path
        end
    end

    def create
        @review = current_user.reviews.build(review_params)
        @review.album = @album
        if @review.save
            redirect_to album_path(@album)
        else
            @album = @review.album
            render :new
        end
    end

    def edit
    end

    def update
        if @review.update(review_params)
            redirect_to album_path(params[:album_id])
        else
            render 'edit'
        end
    end

    def destroy
        if current_user.id == @review.user_id
          @album.reviews.find(params[:id]).destroy
          redirect_to album_path(params[:album_id])
        else
           flash[:error] = "Unable to delete your review. Please try again."
           redirect_to album_reviews_path(@review)
        end
      end

    private

    def set_review
        @review = Review.find(params[:id])
    end

    def set_current_user
        @user = current_user
    end

    def find_album
        @album = Album.find(params[:album_id])
    end

    def review_params
        params.require(:review).permit(:title, :date, :content, album_attributes:[:artist, :title, :user_id])
    end

end


Ответы [ 2 ]

0 голосов
/ 20 апреля 2020

Поскольку пользователи have_many :reviews и отзывы belong_to :user, все, что вам нужно сделать, это:

def show
  @reviews = @user.reveiws
end

Затем в вашем файле show.html.erb вы можете выполнить итерацию по @reviews и извлечь все, что вы хотите от обзора.

<% @reviews.each do |review| %>
  <p><%= link_to review.title, album_path(review.album) %></p>
  <p><%= review.content %></p>
<% end %>
0 голосов
/ 20 апреля 2020

Я думаю, что это проблема маршрутов. Волшебство c выполняется с вложенными маршрутами и одиночными контроллерами: должен быть user_controller, а также album_controller и reviews_controller. Вы можете просто использовать что-то вроде user.albums и user.reviews, как только вы нашли пользователя по id.

From: https://medium.com/podiihq/understanding-rails-routes-and-restful-design-a192d64cbbb5

Rails позволяет Вы можете организовать группы контроллеров под пространством имен с ключевым словом «пространство имен» во время маршрутизации.

Например, группировка контроллеров статей и комментариев под контроллером администратора.

namespace :admin do 
 resources :articles, :comments
end

Чтобы получить доступ к статьям в вашем браузере, необходимо добавить к ним префикс администратора, то есть / admin / article

В конце концов, как только вы создали / обновили свои маршруты до чего-то вроде

Я думаю, что вы можете использовать пространство имен или ресурсы типа

resources :users do 
 resources :reviews, :albums
end

и контроллеры, которые вы можете используйте следующий код в вашем пользовательском контроллере:

  def index
    @reviews= @user.reviews
    @albums = @user.albums
  end

См. также пример с акулами: https://www.digitalocean.com/community/tutorials/how-to-create-nested-resources-for-a-ruby-on-rails-application

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...