Reputation: 151
I'm trying to get my nested form to work. It's a form for a New Album with a space to write a review underneath. The form submits and the Album displays on the page, but the Review does not, it just appears blank. I only am getting one error in the log "Unpermitted parameter: reviews_attributes"
Log:
Started POST "/albums" for ::1 at 2020-04-19 12:10:58 -0400
Processing by AlbumsController#create as HTML
Parameters: {"authenticity_token"=>"jYHM+yeExcTJtENvjQBDsOMo8Ig1g5bRa+hYZ9kCkiI4NO3KP3xdV7SpSZ2IeIOp0wC+5WLxflu22NTIXtoibg==", "album"=>{"artist"=>"Blink 182", "title"=>"California", "avatar"=>#<ActionDispatch::Http::UploadedFile:0x00007fc372d8d5f0 @tempfile=#<Tempfile:/var/folders/26/p006tryd6yb9sp9rq446p07c0000gn/T/RackMultipart20200419-64975-1bp8ang.jpg>, @original_filename="71GfPCWJHXL._SL1500_.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"album[avatar]\"; filename=\"71GfPCWJHXL._SL1500_.jpg\"\r\nContent-Type: image/jpeg\r\n">, "reviews_attributes"=>{"0"=>{"title"=>"Blink 182 review", "date"=>"2020-04-19", "content"=>"NOT THE BLINK182 I KNOW AND LOVE WHERE IS ToM BRING BACK TOM"}}}, "commit"=>"Create Album"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 11], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:10:in `current_user'
Unpermitted parameter: :reviews_attributes
(0.1ms) begin transaction
↳ app/controllers/albums_controller.rb:29:in `create'
Album Create (0.4ms) INSERT INTO "albums" ("artist", "title", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["artist", "Blink 182"], ["title", "California"], ["created_at", "2020-04-19 16:10:58.838672"], ["updated_at", "2020-04-19 16:10:58.838672"]]
↳ app/controllers/albums_controller.rb:29:in `create'
ActiveStorage::Blob Load (0.3ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" INNER JOIN "active_storage_attachments" ON "active_storage_blobs"."id" = "active_storage_attachments"."blob_id" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 6], ["record_type", "Album"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/controllers/albums_controller.rb:29:in `create'
ActiveStorage::Attachment Load (0.2ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 6], ["record_type", "Album"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/controllers/albums_controller.rb:29:in `create'
ActiveStorage::Blob Create (0.3ms) INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "metadata", "byte_size", "checksum", "created_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["key", "l22w59ulprgmmqrs025woawhi1h6"], ["filename", "71GfPCWJHXL._SL1500_.jpg"], ["content_type", "image/jpeg"], ["metadata", "{\"identified\":true}"], ["byte_size", 137504], ["checksum", "IXxJAt318tAPkwmaLBUW/A=="], ["created_at", "2020-04-19 16:10:58.852999"]]
↳ app/controllers/albums_controller.rb:29:in `create'
ActiveStorage::Attachment Create (0.4ms) INSERT INTO "active_storage_attachments" ("name", "record_type", "record_id", "blob_id", "created_at") VALUES (?, ?, ?, ?, ?) [["name", "avatar"], ["record_type", "Album"], ["record_id", 6], ["blob_id", 11], ["created_at", "2020-04-19 16:10:58.856948"]]
↳ app/controllers/albums_controller.rb:29:in `create'
Album Update (0.2ms) UPDATE "albums" SET "updated_at" = ? WHERE "albums"."id" = ? [["updated_at", "2020-04-19 16:10:58.862445"], ["id", 6]]
↳ app/controllers/albums_controller.rb:29:in `create'
(3.3ms) commit transaction
↳ app/controllers/albums_controller.rb:29:in `create'
Disk Storage (2.5ms) Uploaded file to key: l22w59ulprgmmqrs025woawhi1h6 (checksum: IXxJAt318tAPkwmaLBUW/A==)
[ActiveJob] Enqueued ActiveStorage::AnalyzeJob (Job ID: 9114fadd-5897-4939-9cd6-1d0751f129b2) to Async(active_storage_analysis) with arguments: #<GlobalID:0x00007fc372ddf5d0 @uri=#<URI::GID gid://review-project/ActiveStorage::Blob/11>>
Redirected to http://localhost:3000/albums/6
Completed 302 Found in 63ms (ActiveRecord: 5.5ms | Allocations: 15980)
Nested form (albums/_form.html.erb)
<%= form_for(@album) do |f| %>
<% if @album.errors.any? %>
<ul>
<% @album.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<%= f.label :artist %>
<%= f.text_field :artist %>
<br><br>
<%= f.label :title %>
<%= f.text_field :title %>
<br><br>
<%= f.label "Album Image:" %><br>
<%= f.file_field :avatar %>
<br><br>
<h2>Write your review of the album</h2>
<%= f.fields_for :reviews do |ff| %>
<%= ff.label :title %>
<%= ff.text_field :title %>
<br>
<%= ff.label :date %>
<%= ff.date_field :date %>
<br>
<%= ff.label :content %>
<%= ff.text_area :content %>
<% end %>
<br>
<%= f.submit %>
<% end %>
<br><br><br>
<%= link_to "Back to Album", albums_path(@album) %>
albums controller:
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, review_attributes:[:title, :date, :content])
end
end
Reviews controller
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
Album model:
class Album < ApplicationRecord
has_many :reviews
has_many :users, through: :reviews
has_one_attached :avatar
accepts_nested_attributes_for :reviews
validates_presence_of :artist
validates_presence_of :title
scope :with_recent_reviews, -> { includes(:reviews).where(reviews: { date: [(Date.today - 7.days)..Date.tomorrow] }) } #scope relies on include method and custom query on related model (reviews)
end
Review model:
class Review < ApplicationRecord
belongs_to :album, optional: true
belongs_to :user
validates_presence_of :content
validates :title, presence: true, uniqueness: true
validates :date, presence: true
accepts_nested_attributes_for :album
scope :recent, -> { where("date(date) >= ?", Date.today - 7.days) } #scope
end
Routes.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
Upvotes: 0
Views: 272
Reputation: 15848
The reviews
association is a has_many so fields_for should use the plural form.
= f.fields_for :reviews do |ff|
So that way rails creates that parameter reviews_attributes
you are permitting.
If you are still having problems with that change show the new error and stacktrace.
EDIT: If you want to set the current user id as the user of the review (similar to what you did to assign the current user as the album creator), you can assign that before saving the record:
def create
# @user = User.find(current_user.id) you don need this, you already have the user at current_user, no need to find it again
@album = current_user.albums.build(album_params)
# @album.user = current_user you don't need this, current_user.albums.build already sets this
@album.reviews.each { |r| r.user ||= current_user } # I'm using ||= so you 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
And also, remove the :user_id
and :album_id
from the permitted parameters for reviews_attributes
, you don't want users to exploit that assignation adding those parameters that you are actually not using
Upvotes: 1