Missing file field in Nested Attributes - ruby-on-rails

I'm using paperclip in nested attributes and I'm not sure what I'm missing. The view on the form is missing the file upload option.
Form
<%= form_with(model: news, local: true, html: { multipart: true } ) do |form| %>
<%= form.fields_for :images do |img| %>
<%= img.file_field :img, multiple: true %>
<% end%>
<% end %>
Models
class News < ApplicationRecord
has_many :images, dependent: :destroy
accepts_nested_attributes_for :images, allow_destroy: true
end
class Image < ApplicationRecord
belongs_to :news
has_attached_file :img, :styles => { :show => "600x600>" }, size: { less_than: 2.megabytes }
validates_attachment_content_type :img, :content_type => ["image/jpg", "image/jpeg", "image/gif", "image/png"]
end
Controller
class NewsController < ApplicationController
def new
#news = News.new
#news.images.build
end
def create
#news = News.new(news_params)
respond_to do |format|
if #news.save
format.html { redirect_to #news, notice: 'News was successfully created.' }
format.json { render :show, status: :created, location: #news }
else
format.html { render :new }
format.json { render json: #news.errors, status: :unprocessable_entity }
end
end
end
private
def set_news
#news = News.find(params[:id])
end
def news_params
params.require(:news).permit(:title, :description, :category, images_attributes: [:id, :img, :news_id, :_destroy])
end
end
If I change :images to :image in the form the field appears, but then gives an error on submission:
Unpermitted parameter: :image

In your case, you need to explicitly pass a record_object to the fields_for
<%= form.fields_for :images, #news.images.build do |img| %>
<%= img.file_field :img, multiple: true %>
<% end%>
Also in order to send multiple values for img, it should be an array in the permitted params. You should change the news_params to below
def news_params
params.require(:news).permit(:title, :description, :category, images_attributes: [:id, :news_id, :_destroy, img: []])
end

Related

rails nested_attributes form can't find id

So i have two models : Internship and Review. I want the Review to be a nested_attributs of Internship. So that i can create an internship with a review.
My problem is that the review form integrated in the new form internship, doesn't find the id of the internship. It raise the errors 'Review internship must exist'
Internship.rb
has_many :reviews, foreign_key: "review_internship_id"
has_many :review_users, foreign_key: 'review_user_id', class_name:"User", through: :reviews
accepts_nested_attributes_for :reviews, allow_destroy: true
validates_associated :reviews
Review.rb
belongs_to :review_user, class_name: "User"
belongs_to :review_internship, class_name: "Internship"
Internship_controller
def new
#internship = Internship.new
#internship.reviews.new
end
def create
#internship = Internship.new(internship_params)
#internship.user = current_user
#internship.reviews.first.review_user_id = current_user.id
respond_to do |format|
if #internship.save
format.html { redirect_to #internship, notice: 'Expérience crée avec succès' }
format.json { render :show, status: :created, location: #internship }
else
format.html { render :new }
format.json { render json: #internship.errors, status: :unprocessable_entity }
end
end
end
private
def internship_params
params.require(:internship).permit(:adress, :zipcode, :city, :specialty, :organization, :population, :cursus, :title, :duration, :description, :region, :remuneration, :user_id, reviews_attributes: [:title, :notation, :description, review_internship_id: params[:internship_id], review_user_id: current_user.id])
end
The new form in internship new
<%= form_with(model: internship, local: true) do |form| %>
....
<!--NESTED ATTRIBUTS REVIEW-->
<%= form.fields_for :reviews do |p| %>
<%= p.label :titre %>
<%= p.text_field :title, class:"form-control" %>
<%= p.label :note %>
<%= p.number_field :notation, min: 1, max: 5, class:"form-control" %>
<%= p.label :description %>
<%= p.text_area :description, class:"form-control" %>
<% end %>
...
<% end %>
So this is what i've tried in Internship controller
#intership.reviews.review_internship_id = #internship.id
So that it can find the id of the internship. The error is "Review Internship must exist".
It did the same with "Review User", which was solved with #internship.reviews.first.review_user_id = current_user.id
Do you have any idea where the problem is, and how i can find the internship id with another way. I've also tried the params[:id]
Thanks for your help
:
You don't really need a user_id foreign key on reviews since it can get there through the interview:
class Review
belongs_to :internship
has_one :user, through: :interview
end
class Internship
belongs_to :user
has_many :reviews
end
class User
has_many :internships
has_many :reviews, through: :internships
end
And you definitely don't ever need to be manually assigning parent ids for nested records.
class IntershipsController < ApplicationController
def new
#internship = Internship.new
#internship.reviews.new
end
def create
#internship = Internship.new(internship_params) do |i|
i.user = current_user
end
respond_to do |format|
if #internship.save
format.html { redirect_to #internship, notice: 'Expérience crée avec succès' }
format.json { render :show, status: :created, location: #internship }
else
format.html { render :new }
format.json { render json: #internship.errors, status: :unprocessable_entity }
end
end
end
private
def internship_params
# use some line-breaks!
params.require(:internship)
.permit(
:adress, :zipcode, :city, :specialty,
:organization, :population, :cursus,
:title, :duration, :description,
:region, :remuneration, :user_id,
reviews_attributes: [
:id, :title, :notation, :description
]
)
end
end

simple_form not showing nested field

I am trying simple_form nested attributes as suggested in https://github.com/plataformatec/simple_form/wiki/Nested-Models
The thing is, when I render the form I just can see the submit button, but not the input field. What am I doing wrong?
_form.html.erb
<%= simple_form_for [:admin, #incident] do |f| %>
<%= f.error_notification %>
<%= f.simple_fields_for :comments do |builder| %>
<%= builder.input :info, label: "Informe de seguimiento" %>
<% end %>
<div class="form-actions">
<%= f.submit "Enviar", class: "btn btn-primary" %>
</div>
<% end %>
incidents_controller.rb
class Admin::IncidentsController < ApplicationController
before_action :set_incident, only: [:show, :edit, :update]
def index
#incidents = Incident.all
end
def show
end
def new
#incident = Incident.new
#incident.comments.build
end
def edit
end
def update
respond_to do |format|
if #incident.update(incident_params)
format.html { redirect_to #incident, notice: 'Incidencia actualizada actualizada con éxito.' }
format.json { render :show, status: :ok, location: #incident }
else
format.html { render :edit }
format.json { render json: #incident.errors, status: :unprocessable_entity }
end
end
end
private
def set_incident
#incident = Incident.find(params[:id])
end
def incident_params
params.require(:incident).permit(:info, :subject, :status, comments_attributes: [:info])
end
end
incident.rb
class Incident < ApplicationRecord
belongs_to :user, optional: true
has_many :comments, dependent: :destroy
accepts_nested_attributes_for :comments, allow_destroy: true, reject_if: proc { |attributes| attributes['info'].blank? }
enum status: [:abierto, :tramite, :pendiente, :cerrado]
after_initialize :set_default_status, :if => :new_record?
def set_default_status
self.status ||= :abierto
end
end
comment.rb
class Comment < ApplicationRecord
belongs_to :user, optional: true
belongs_to :incident
end
You need to add #incident.comments.build to the show action of Admin::IncidentsController. Now it has no comments, I suppose, so the form is empty.
And you need to add :id to comments_attributes, without it comment can't be saved. If you planning to have some 'Delete' checkbox for existing comments you also need to add :_destroy to the attributes array

Ruby on Rails paperclip multiple upload with nested attributes

I was wondering if someone can help me with file uploading!
I'm trying to upload multiple images using paperclip and having nested attributes.
models
class Trip < ActiveRecord::Base
has_many :trip_images, :dependent => :destroy
end
class TripImage < ActiveRecord::Base
belongs_to :trip
has_attached_file :photo, :styles => { :large => "800x800>", :medium => "500x500>", :thumb => "150x150#" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :photo, content_type: /\Aimage\/.*\Z/
end
controller
def create
#trip = Trip.new(trip_params)
respond_to do |format|
if #trip.save
format.html { redirect_to #trip, notice: 'Trip was successfully created.' }
format.json { render :show, status: :created, location: #trip }
else
format.html { render :new }
format.json { render json: #trip.errors, status: :unprocessable_entity }
end
end
end
def trip_params
params.require(:trip).permit(
:user_id,
trip_images_attributes: [:id, :photo])
end
view
<%= simple_form_for #trip, html: { multipart: true } do |f| %>
<%= f.simple_fields_for :trip_images do |p| %>
<%= p.file_field :photo, as: :file, multiple: true %>
<% end%>
<%= f.button :submit %>
<% end %>
How do I save multiple images in my trip image database? When I submit the form, nothing gets saved into the database.
Add :trip_id to trip_images_attributes:
def trip_params
params.require(:trip).permit(
:user_id,
trip_images_attributes: [:trip_id, :id, :photo]) # :_destroy
end
Also you can add :_destroy if you plan to be able to remove photos.
What you also missed is to add accepts_nested_attributes_for :trip_images to Trip model.
Change your form to something like this:
= f.simple_fields_for :trip_images do |tp|
= render 'trip_photos_fields', f: photo
.links
%br= link_to_add_association 'Add another photo', f
And _trip_photos_fields.html.haml partial:
- unless f.object.new_record?
%br= link_to_remove_association "Delete photo", f
= link_to image_tag(f.object.photo.url(:medium)), f.object.photo.url, target: '_blank'
- if f.object.new_record?
= f.file_field :photo, as: :file

Why is adding multiple images to a gallery object not working at all

I am creating a gallery where you can upload multiple images via form.
The form is nested inside another form and when that is submitted it should create the gallery with the attached images inside it. When I check the output I get this which means its not submitting the correct images to the gallery object at all:
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"BJhkDx7rCRMIlXQ6T9FskXZe7+fdYxj0qm+VnCaC51w=",
"book"=>{
"jacket_cover" =>#<ActionDispatch::Http::UploadedFile:0x000001025d3128
#tempfile=#<File:/var/folders/mf/srx7jt8s2rdg0mn5hr98cvz80000gn/T/RackMultipart20140918-47766-1g9kyas>, #original_filename="559a7a477253d58f891f8e852162dfac.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"book[jacket_cover]\"; filename=\"559a7a477253d58f891f8e852162dfac.jpg\"\r\nContent-Type: image/jpeg\r\n">,
"title"=>"zd szw wrwr",
"synopsis"=>"<p>cfdcrgcgrere</p>\r\n",
"body"=>"<p>rccgregrrgerereg</p>\r\n",
"age"=>"19",
"publisher"=>"Dove books",
"author_attributes"=>{
"name"=>"zsdxfrrwg",
"biography"=>"<p>exffwfwefewewf</p>\r\n"},
"gallery_attributes"=>{
"images_attributes"=>{
"0"=>{
"file"=>[#<ActionDispatch::Http::UploadedFile:0x000001025d20e8 #tempfile=#<File:/var/folders/mf/srx7jt8s2rdg0mn5hr98cvz80000gn/T/RackMultipart20140918-47766-tk1rdb>, #original_filename="23ebb202a3655c6d0947251cce8625b6.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"book[gallery_attributes][images_attributes][0][file][]\"; filename=\"23ebb202a3655c6d0947251cce8625b6.jpg\"\r\nContent-Type: image/jpeg\r\n">, #<ActionDispatch::Http::UploadedFile:0x000001025d1ff8 #tempfile=#<File:/var/folders/mf/srx7jt8s2rdg0mn5hr98cvz80000gn/T/RackMultipart20140918-47766-j3ji7c>, #original_filename="559a7a477253d58f891f8e852162dfac.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"book[gallery_attributes][images_attributes][0][file][]\"; filename=\"559a7a477253d58f891f8e852162dfac.jpg\"\r\nContent-Type: image/jpeg\r\n">]
}
}
}
}, "commit"=>"Create Book"
}
The books_controller handles the submission of the gallery with the images in it:
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!, only: [:new, :edit, :update, :destroy]
# GET /books
# GET /books.json
def index
#books = Book.order('created_at DESC').all
end
# GET /books/1
# GET /books/1.json
def show
# #book = Book.find(params[:id])
#book = Book.friendly.find(params[:id])
#gallery = #book.gallery
end
# GET /books/new
def new
#book = Book.new
#book.build_author
#gallery = #book.build_gallery
#gallery.images.build
end
# GET /books/1/edit
def edit
end
# POST /books
# POST /books.json
def create
#raise params.inspect
#book = Book.new(book_params)
#binding.pry
respond_to do |format|
if #book.save
format.html { redirect_to #book, notice: 'Book was successfully created.' }
format.json { render action: 'show', status: :created, location: #book }
else
format.html { render action: 'new' }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /books/1
# PATCH/PUT /books/1.json
def update
respond_to do |format|
if #book.update(book_params)
format.html { redirect_to #book, notice: 'Book was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
# DELETE /books/1
# DELETE /books/1.json
def destroy
#book.destroy
respond_to do |format|
format.html { redirect_to books_url }
format.json { head :no_content }
end
end
# Get authors
# def reviews
# #book = Book.friendly.find(params[:id])
# #reviews = #movie.reviews
# respond_to do |format|
# format.html { render 'reviews/index' } # index.html.erb
# format.json { render json: #movies }
# end
# end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
# #book = Book.find(params[:id])
#book = Book.friendly.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def book_params
params.require(:book).permit(:title, :synopsis, :body, :age, :publisher, :jacket_cover, author_attributes: [:name,:biography], gallery_attributes: [:name, :book_id ] )
end
end
book.rb
class Book < ActiveRecord::Base
has_attached_file :jacket_cover, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :jacket_cover, :content_type => /\Aimage\/.*\Z/
validates :jacket_cover, :title, :slug, :synopsis, :body, :age, :publisher, presence: true
validates_uniqueness_of :title
extend FriendlyId
friendly_id :title, use: [:slugged, :finders]
belongs_to :author
has_one :gallery
has_many :stories
accepts_nested_attributes_for :author
accepts_nested_attributes_for :gallery
scope :available, ->{ where(available: true) }
scope :unavailable, ->{ where(available: [nil, false]) }
end
image.rb
class Image < ActiveRecord::Base
belongs_to :gallery
has_attached_file :file, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :file, :content_type => /\Aimage\/.*\Z/
end
gallery.rb
class Gallery < ActiveRecord::Base
belongs_to :books
has_many :images
accepts_nested_attributes_for :books
accepts_nested_attributes_for :images, :allow_destroy => true
end
galleries_controller.rb
class GalleriesController < ApplicationController
before_action :set_gallery, only: [:show, :edit, :update, :destroy]
def index
#galleries = Gallery.all
end
def show
#gallery = Gallery.find(params[:id])
#images = #gallery.images
end
def new
#gallery = Gallery.new
##gallery.images.build
# #images = #gallery.build_images
# #gallery.images.build
end
def edit
#gallery.images.build
end
def create
#gallery = Gallery.new(gallery_params)
#image = Image.create()
##gallery.images.build
respond_to do |format|
if #gallery.save
format.html { redirect_to #gallery, notice: 'Gallery was successfully created.' }
format.json { render action: 'show', status: :created, location: #gallery }
else
format.html { render action: 'new' }
format.json { render json: #gallery.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #gallery.update(gallery_params)
format.html { redirect_to #gallery, notice: 'Gallery was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #gallery.errors, status: :unprocessable_entity }
end
end
end
def destroy
#gallery.destroy
respond_to do |format|
format.html { redirect_to galleries_url }
format.json { head :no_content }
end
end
private
def set_gallery
#gallery = Gallery.find(params[:id])
end
def gallery_params
params.require(:gallery).permit(:name, :book_id, :image)
#params.require(:gallery).permit(:name, :book_id, :images[], images_attributes: [:id, :file []])
#params.require(:gallery).permit(:name, :book_id, :images[images_attributes: [:file]])
# params.require(:gallery).permit(:name, :book_id, images_attributes: [:id, :image[:file]])
end
end
Added form in here that submits the gallery of images:
<%= simple_form_for(#book, :html => { :multipart => true } ) do |f| %>
<%= f.error_notification %>
<div class="inputs">
<div id="image" class="field">
<h3>Add the book image here</h3>
<div class="single-file">
<div class="file_upload">
<%= f.file_field :jacket_cover %>
</div>
</div>
</div>
<div id="title" class="field">
<h3>Add the title</h3>
<%= f.input :title %>
</div>
<div id="synopsis" class="field">
<h3>Add the book synopsis</h3>
<%= f.input :synopsis, :as => :ckeditor, :label => false, :input_html => { :ckeditor => { :toolbar => 'Full', :height => 400 } } %>
</div>
<div id="body" class="field">
<h3>Add the book body summary here</h3>
<%= f.input :body, :as => :ckeditor, :label => false, :input_html => { :ckeditor => { :toolbar => 'Full', :height => 400 } } %>
</div>
<div id="age" class="field">
<h3>Add the book age group</h3>
<%= f.input :age, collection: [['3-7', '3-7'],['7-11', '7-11'],['11-14', '11-14']], prompt: "Select age range" %>
</div>
<div id="publisher" class="field">
<h3>Who published the book</h3>
<%= f.input :publisher %>
</div>
<div id="school" class="field">
<h3>Schools reading this book (add the name and full address of the school)</h3>
<%= f.simple_fields_for :schools, :wrapper => 'inline' do |builder| %>
<%= render 'school_fields', :f => builder %>
<%= link_to_add_association 'add school', f, :schools, :render_options => {:wrapper => 'inline' }, :class => 'fa fa-plus' %>
<% end %>
</div>
</div>
<%#= f.select( :author_id, Author.all.map {|u| [u.name,u.id]}, {:include_blank => false, prompt: "No Author"} ) %>
<div id="author-inputs">
<h3>Add author</h3>
<%#= link_to 'New Author', new_author_path, :remote => true, :id => "new_author_link" %>
<%= f.simple_fields_for :author, :wrapper => 'inline' do |builder| %>
<%= render 'author_fields', :f => builder %>
<% end %>
</div>
<%= f.simple_fields_for :gallery do |builder| %>
<%= render 'galleries/form', :f => builder %>
<% end %>
<div class="actions">
<%= f.button :submit %>
</div>
<% end %>
When I check in the db console I cannot see any images inside the gallery when I search Gallery.all
I have created a gist file with all the necessary info in it.
Can anyone shed any light into this for me at all?
The main problem is with your parent form and model relationship.
In your book model you should have belongs_to :gallery instead of has_one :gallery. Also check your database. books Table should have gallery_id. As a database concept belongs_to should have parent table id. So model should be :
class Book < ActiveRecord::Base
has_attached_file :jacket_cover, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :jacket_cover, :content_type => /\Aimage\/.*\Z/
validates :jacket_cover, :title, :slug, :synopsis, :body, :age, :publisher, presence: true
validates_uniqueness_of :title
extend FriendlyId
friendly_id :title, use: [:slugged, :finders]
belongs_to :author
belongs_to :gallery
has_many :stories
accepts_nested_attributes_for :author
accepts_nested_attributes_for :gallery
scope :available, ->{ where(available: true) }
scope :unavailable, ->{ where(available: [nil, false]) }
end
and your gallery model should look like :
class Gallery < ActiveRecord::Base
has_many :books
has_many :images
accepts_nested_attributes_for :books
accepts_nested_attributes_for :images, :allow_destroy => true
end
Your parent model in form should be gallery model instead of book. And also make required changes in your gallery controller.

mutiple upload with rails and paperclip

I am following this tutorial here to use multiple uploads with paperclip.
However when I add the files I get the flash notice confirming the gallery was added succesfully but there are no images uploaded. I am sure its the implementation in my controller.
gallery_controller.rb
def update
#gallery = Gallery.friendly.find params[:id]
respond_to do |format|
if #gallery.save
if params[:exhibition_images_attributes]
params[:exhibition_images_attributes].each { |image|
#gallery.exhibition_images.create(image: image)
}
end
format.html { redirect_to #gallery, notice: 'Gallery was successfully updated.' }
format.json { render :show, status: :ok, location: #gallery }
else
format.html { render :edit }
format.json { render json: #gallery.errors, status: :unprocessable_entity }
end
end
end
def edit
#gallery = Gallery.friendly.find params[:id]
#image = #gallery.exhibition_images.new
end
private
def gallery_params
params.require(:gallery).permit(:title, exhibition_images_attributes: [:image])
end
upload form
<%= bootstrap_form_for(#gallery, :html => {:multipart => true}, layout: :horizontal, label_col: "col-sm-2", control_col: "col-sm-10") do |f| %>
<%= f.text_field :title %>
<%= f.fields_for :exhibition_images do |f| %>
<%= f.file_field "image[]", type: :file, multiple: true %>
<% end %>
<%= f.submit "Create/Update", class: "btn btn-primary" %>
<% end %>
gallery.rb
class Gallery < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: :slugged
belongs_to :guide
has_many :exhibition_images, :autosave => true
accepts_nested_attributes_for :exhibition_images
end
exhibition_image.rb
class ExhibitionImage < ActiveRecord::Base
belongs_to :gallery, :autosave => true
has_attached_file :image, styles: { small: "100x100", guide: "500x500" }
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
end

Resources