Nested attributes for has_many relationship - ruby-on-rails

My models are
class History < ActiveRecord::Base
belongs_to :projects_lkp
has_many :pictures
accepts_nested_attributes_for :pictures
end
class Picture < ActiveRecord::Base
belongs_to :history
validates_presence_of :pics
end
history/new.html.erb
<%= form_for(:history, :url => {:action => 'create'}) do |d| %>
<%= render(:partial =>"form",:locals => {:d => d}) %>
<% end %>
history/_form.html.erb
<%= d.fields_for :pictures do |dd| %>
<div class="row form-group"></div>
<div><class='col-md-5 form-label'>Photo</div>
<%= dd.file_field :pic, multiple: true, :class => 'col-md-15' %>
</div>
<% end %>
history_controller
def create
#history = History.new(history_params)
#history.projects_lkp_id = params[:projects_lkps_id]
respond_to do |format|
if #history.save
format.html{ redirect_to histories_path(id: #history.id), notice:"History added" }
else
#history = History.where(item: #history.item).all
format.html { render 'index' }
end
end
end
def history_params
params.require(:history).permit(:history,:date,:pic)
end
But when I tried to submit form, it says that unpermitted parameter :pictures
Parameter passing is:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xE8d/mD1pXh/2AIKrZlRoL552iEBVZ7jkzLJB1kNZyE=", "history"=>{"history"=>" jhafjkaalkds", "date"=>"20/10/2014", "pictures"=>{"pic"=>[#<ActionDispatch::Http::UploadedFile:0x0000000143d1f8 #tempfile=#<Tempfile:/tmp/RackMultipart20150910-2753-1ml2hmf>, #original_filename="Firefox_wallpaper.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"history[pictures][pic][]\"; filename=\"Firefox_wallpaper.png\"\r\nContent-Type: image/png\r\n">]}}, "projects_lkps_id"=>"", "commit"=>"Submit"}
Unpermitted parameters: pictures
Here the :pic is the attachment field created by using paperclip gem

Try this:
def history_params
params.require(:history).permit(:history, :date, pictures_attributes: [:pic])
end
One more problem I can see is with your form. It should be:
<%= form_for(:history, :url => {:action => 'create'}, multipart: true) do |d| %>
<%= render(:partial =>"form",:locals => {:d => d}) %>
<%= d.fields_for :pictures do |dd| %>
<div class="row form-group"></div>
<div><class='col-md-5 form-label'>Photo</div>
<%= dd.file_field :pic, multiple: true, :class => 'col-md-15' %>
</div>
<% end %>
<% end %>
Parameters should be in the form:
"history" => { ... , "photos_attributes" => { "0" => { ... } } }

I have found the answer for that :)
history controller
def new
#histories = History.new
#histories.pictures.build
end
history/new
<%= form_for(#histories, :url => {:action => 'create'}, html: {multipart:true}) do |d| %>
<%= render(:partial =>"form",:locals => {:d => d}) %>
<% end %>
it works :)

Related

NoMethodError (undefined method `name' for nil:NilClass)

I am trying to upload images without gem to a model called "Course Classifications", before I was using the gem "Paperclip".
Rails Version is Rails 3.0.10
When I am trying to create a "Course Classification", I get the following error:
undefined method `name 'for nil: NilClass
I suppose it must be something regarding the image that I am trying to upload, because when I do not load an image, the model is created normally.
according to my console the error is in the line of the method 'create' 'if #course_clasification.save'
What can be?
The 'puts' throw me the following:
"PARAMS: {\"name\"=>\"Prueba12312\", \"description\"=>\"\", \"status\"=>\"1\", \"picture\"=>#<ActionDispatch::Http::UploadedFile:0x0055ffb16c36d8 #original_filename=\"Selección_250.png\", #content_type=\"image/png\", #headers=\"Content-Disposition: form-data; name=\\\"course_clasification[picture]\\\"; filename=\\\"Selecci\\xC3\\xB3n_250.png\\\"\\r\\nContent-Type: image/png\\r\\n\", #tempfile=#<Tempfile:/tmp/RackMultipart20210722-21412-xnr47e>>}"
"NAME: Prueba12312"
My code is the following:
Controller:
def create
#course_clasification = CourseClasification.new(params[:course_clasification])
p "PARAMS: #{params[:course_clasification]}"
if params[:course_clasification].present?
file = params[:course_clasification][:picture]
File.open(Rails.root.join('public','uploads', file.original_filename), 'wb') do |f|
f.write(file.read)
end
end
respond_to do |format|
if #course_clasification.save
format.html { redirect_to(course_clasifications_path, :notice => 'Classification was created') }
format.xml { render :xml => #course_clasification, :status => :created, :location => #course_clasification }
else
format.html { render :action => "new" }
format.xml { render :xml => #course_clasification.errors, :status => :unprocessable_entity }
end
end
end
def upload
uploaded_io = params.require(:course_clasification).permit(:picture)
File.open(Rails.root.join('public','uploads',uploaded_io.original_filename), 'wb') do |file|
file.write(uploaded_io.read)
end
end
Model:
class CourseClasification < ActiveRecord::Base
has_many :courses
has_many :enrollments
validates :name, presence: true
=begin
has_attached_file :avatar
# Validate content type
validates_attachment_content_type :avatar, content_type: /\Aimage/
# Validate filename
validates_attachment_file_name :avatar, matches: [/png\Z/, /jpe?g\Z/]
# Explicitly do not validate
do_not_validate_attachment_file_type :avatar
=end
scope :actives, -> { where('status = 1') }
scope :inactives, -> { where('status = 0') }
end
Form:
<%= form_for(#course_clasification, html: { style: "flex-direction: column; width: 50%;", :multipart => true }) do |f| %>
<div class="actions">
<%= link_to '<i class="fa fa-chevron-circle-left" aria-hidden="true"></i> Regresar'.html_safe, course_clasifications_path, class: "btn-button button--indigo" %>
<%= f.submit((" " + t('action.save')).html_safe, :alt => "Guardar", :title => "Guardar", :class => "button__submit btn-button button--green", :style => "font-family: FontAwesome, verdana, sans-serif; float: right; margin-top: 0; margin-right: 7px;") %>
</div>
<% lang = current_user.localization.languaje %>
<% if #course_clasification.errors.any? %>
<div id="error_explanation">
<h2><%= t('activerecord.errors.template.header', count: #course_clasification.errors.size, model: t('activerecord.models.course_clasification')) %>:</h2>
<p>
<%= t('activerecord.errors.template.body') %>
</p>
<ul>
<% #course_clasification.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field field-full" style="margin-top: 40px;">
<%= f.label t('str_name_areas_'+ lang) %><br />
<%= f.text_field :name %>
</div>
<div class="field field-full">
<%= f.label "Agregar imágen a player" %><br />
<%= f.file_field :picture %>
<%# if #course_clasification.avatar? %>
<%# image_tag #course_clasification.avatar.url(:thumb) %>
<%# end %>
</div>
<% end %>
Schema:
class CreateCourseClasification < ActiveRecord::Migration
def self.up
create_table :course_clasifications do |t|
t.string :name
t.text :description
t.boolean :status
t.string :picture
t.timestamps
end
end
end
One problem that I'm seeing is that you're not using Strong Parameters.
That means that
#course_clasification = CourseClasification.new(params[:course_clasification])
Will basically try to create an empty object since non of the params is whitelisted (whatever is not whitelisted is basically omitted by Rails), so the ActiveRecord object is invalid and the save fails.
Change it to something like
def course_classification_params
# make sure to list all the save params!
params.permit(:name, :description, :status, ...)
end
#course_clasification = CourseClasification.new(course_classification_params[:course_clasification])

carrierwave multiple uploader for single model

I have created a gallery module with the help of this tutorial https://kolosek.com/carrierwave-upload-multiple-images/ and now I want to add one more image attribute has a master image to the same model. So I thot of creating one more uploader but I'm bit confused about how to call that the controller can anybody help me out?
My code looks like this:
MOdel Code:
class Image < ApplicationRecord
belongs_to :gallery
mount_uploader :image, ImageUploader
mount_uploader :avatar, AvatarUploader
end
class Gallery < ApplicationRecord
has_many :images
accepts_nested_attributes_for :images
end
gallery_controller.rb
class GalleriesController < AdminController
def index
#galleries = Gallery.all
end
def show
#images = #gallery.images.all
end
def new
#gallery = Gallery.new
#image = #gallery.images.build
end
def create
#gallery = Gallery.new(gallery_params)
respond_to do |format|
if #gallery.save
params[:images]['image'].each do |a|
#images = #gallery.images.create!(:image => a, :gallery_id => #gallery.id)
end
format.html { redirect_to #gallery, notice: 'Gallery was successfully created.' }
format.json { render :show, status: :created, location: #gallery }
else
format.html { render :new }
format.json { render json: #gallery.errors, status: :unprocessable_entity }
end
end
end
def gallery_params
params.require(:gallery).permit(:title, :details, :status, images_attributes:[:id, :gallery_id, :image, :avatar])
end
Image Controller code:
class ImagesController < AdminController
def image_params
params.require(:image).permit(:gallery_id, :slideshow_id,:image, :avatar)
end
end
form.html.erb
<%= form.fields_for :images do |p| %>
<div class="field">
<%= form.label :master_image, class: "col-2 col-form-label" %>
<%= form.file_field :avatar, :multiple => true, name: "images[avatar][]" %>
</div>
<% end %>
<%= form.fields_for :images do |p| %>
<div class="field">
<%= form.label :image, class: "col-2 col-form-label" %>
<%= form.file_field :image, :multiple => true, name: "images[image][]" %>
</div>
<% end %>
I am confused in modifing the gallery controller create part.
You can add the images creation 2 times in the create method if you have 2 uploaders
params[:images]['image'].each do |a|
#gallery.images.create!(:image => a, :gallery_id => #gallery.id)
end
params[:images]['avatar'].each do |a|
#gallery.images.create!(:avatar => a, :gallery_id => #gallery.id)
end
but i think it's a little bit verbose and it not really prevents if you don't want to upload any image in your form (return params[:images]['...'] nil)
Btw your form is not correct for the form.fields_for. It's :
<%= form.fields_for :images_attributes do |p| %>
<div class="field">
<%= p.label :master_image, class: "col-2 col-form-label" %>
<%= p.file_field :avatar, :multiple => true, name: "images[avatar][]" %>
</div>
<% end %>
<%= form.fields_for :images_attributes do |p| %>
<div class="field">
<%= p.label :image, class: "col-2 col-form-label" %>
<%= p.file_field :image, :multiple => true, name: "images[image][]" %>
</div>
<% end %>

Rails 4, Cocoon, ERB Template, how to make selected an options_from_collection_for_select in Edit Action?

This is my first time with Cocoon, and maybe this is a really dumb question, but I already spend many time looking how to do this with ERB template and avoid using simple_form or other helper.
Take a look of my models:
models/loot.rb
class Lot < ActiveRecord::Base
has_many :colindanciums, dependent: :destroy
has_many :cardinal_points, through: :colindanciums
accepts_nested_attributes_for :colindanciums, allow_destroy: true
end
models/colindancium.rb
class Colindancium < ActiveRecord::Base
belongs_to :cardinal_poing
belongs_to :lot
end
models/cardinal_point.rb
class CardinalPoint < ActiveRecord::Base
has_many :colindanciums
has_many :lots, through: :colindanciums
end
The form:
views/lots/_form.html.erb
<%= form_for(#lot, remote: true) do |f| %>
<%= render 'shared/error_messages', object: #lot %>
...
...
...
<fieldset id="colindancium-orientation">
<ol>
<%= f.fields_for :colindanciums do |colindancium| %>
<%= render 'colindancium_fields', f: colindancium %>
<% end %>
</ol>
<%= link_to_add_association 'Nueva Colindancia', f, :colindanciums, 'data-association-insertion-node' => "#colindancium-orientation ol", 'data-association-insertion-method' => "append" %>
</fieldset>
...
...
...
<% end %>
The partial:
views/lots/_colindancium_fields.html.erb
<li class="control-group nested-fields">
<div class="controls">
<%= f.label :description, "Descripcion:" %>
<%= f.text_field :description %>
<%= f.label :linear_meters, "Metros Lineales:" %>
<%= f.text_field :linear_meters %>
<%= f.label :cardinal_point_id, "Orientacion:" %>
<%= f.select :cardinal_point_id,
options_from_collection_for_select(CardinalPoint.all, :id, :name), { }, { :class => "form-control", :prompt => "Seleccione un Punto Cardinal" } %>
<%= link_to_remove_association "Eliminar", f %>
</div>
</li>
Everything works great when I insert new fields, it saves it in DB, it Update it in DB, my problem is in the options_from_collection_for_select when I open the form in Edit Action, the fourth parameter of this helper is the selected value... I can't find the way to make selected the value that is stored in my db, it always show the 1 index... I can't access the #... object from the _form, the other fields (:description, :linear_meters) are working quite good my problem is in the f.select, I don't know how to do it.
EDIT My controller:
# GET /lots/new
def new
#lot = Lot.new
#lot.colindanciums.build
authorize #lot
end
# PATCH/PUT /lots/1
# PATCH/PUT /lots/1.json
def update
authorize #lot
respond_to do |format|
if #lot.update(lot_params)
format.html { redirect_to #lot, notice: 'Lot was successfully updated.' }
format.json { render :show, status: :ok, location: #lot }
format.js
else
format.html { render :edit }
format.json { render json: #lot.errors, status: :unprocessable_entity }
format.js { render json: #lot.errors, status: :unprocessable_entity }
end
end
end
I change my logic in the select, i made it works in this way:
<div class="form-group">
<%= f.label :cardinal_point_id, "Orientacion:", :class => "control-label" %>
<%= f.select :cardinal_point_id , CardinalPoint.all.collect {|p| [ p.name, p.id ] }, { :include_blank => 'Seleccione un Punto Cardinal'}, :class => "form-control" %>
</div>
I post my answer in case anybody have the same issue.
You forgot to put the parenthesis correctly
<%= f.select (:cardinal_point_id,
options_from_collection_for_select(CardinalPoint.all, :id, :name), { }, { :class => "form-control", :prompt => "Seleccione un Punto Cardinal" }) %>

Rails custom route form_for error: param is missing or the value is empty

I am getting this error: param is missing or the value is empty: character. I am baffled. There must be a problem with form_for somewhere, but I just can't find it. I'm updating Character attributes in the Users controller but that shouldn't matter I think?
Parameters:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"...",
"picturethings"=>{"picture"=>[#<ActionDispatch::Http::UploadedFile:0x000001100087f8 #tempfile=#<Tempfile:/var/folders/19/_vdcl1r913g6fzvk1l56x4km0000gn/T/RackMultipart20150524-4855-1eieu5j.jpeg>,
#original_filename="GOT1.jpeg",
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"picturethings[picture][]\"; filename=\"GOT1.jpeg\"\r\nContent-Type: image/jpeg\r\n">]},
"commit"=>"Upload pictures",
"callsign"=>"bazzer"}
views/users/edit.html.erb
<%= form_for #character, url: update_pictures_user_path do |f| %>
<%= f.fields_for :picturethings, html: { multipart: true } do |p| %>
<%= p.label :picture %>
<%= p.file_field :picture, multiple: true, name: "picturethings[picture][]" %>
<% end %>
<%= f.submit "Upload pictures" %>
<% end %>
users_controller.rb
def edit
#character = Character.find_by(callsign: params[:callsign])
#user = #character.sociable
#picturething = #character.picturethings.build
end
def update_pictures
#character = Character.find_by(callsign: params[:callsign])
if #character.update_attributes(update_pictures_user_params)
flash[:success] = "Pictures updated"
params[:picturethings]['picture'].each do |p|
#picturething = #character.picturethings.create!(picture: p, character_id: #character.id)
end
render 'edit'
else
render 'edit'
end
end
def update_pictures_user_params
params.require(:character).permit(picturethings_attributes: [:picture])
end
character.rb
belongs_to :sociable, polymorphic: true
has_many :picturethings
accepts_nested_attributes_for :picturethings
user.rb
has_one :character, as: :sociable, dependent: :destroy
routes.rb
patch '/users/:callsign/update_pictures', to: 'users#update_pictures', as: :update_pictures_user
Your file input name is incorrect. If you look at the form data:
form-data; name=\"picturethings[picture][]\"; filename=\"GOT1.jpeg\"\r\nContent-Type: image/jpeg\r\n"
There is no character param.
The correct name attribute would look something like this:
character[picturethings_attributes][1][picture][]
When Rails parses the form data it will convert it into the following hash:
character: {
picturethings_attributes: {
0 => {
picture : [] # an array of files.
}
}
}
You don't need to specify the name manually:
<%= form_for #character, url: update_pictures_user_path do |f| %>
<%= f.fields_for :picturethings, html: { multipart: true } do |p| %>
<%= p.label :picture %>
<%= p.file_field :picture, multiple: true %>
<% end %>
<%= f.submit "Upload pictures" %>
<% end %>
Rails will give you the correct name attribute. You also don't need to manually create the associated records - that's the whole point of accepts_nested_attributes_for:
def update_pictures
#character = Character.find_by(callsign: params[:callsign])
if #character.update_attributes(update_pictures_user_params)
flash[:success] = "Pictures updated"
render 'edit'
else
render 'edit'
end
end

How to solve the error in uploading an image in level 2 deeper model

Models in my app
class Category < ActiveRecord::Base
has_many :dishes, :dependent => :destroy
end
class Dish < ActiveRecord::Base
attr_accessible :assets_attributes
belongs_to :category
has_many :assets
accepts_nested_attributes_for :assets, :allow_destroy => true
end
class Asset < ActiveRecord::Base
belongs_to :dish
has_attached_file :asset, :styles => { :large => "640x480", :medium => "300x300>", :thumb => "100x100>" }
end
In Gemfile
source 'http://rubygems.org'
gem 'rails', '3.0.11'
gem 'sqlite3', '1.3.3'
gem 'paperclip'
app/controllers/dishes_controller.rb
class DishesController < ApplicationController
def new
#category = Category.find(params[:id])
#dish = #category.dishes.new(:category_id => params[:id])
#dish.assets.build
#title = "Create dish"
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #category }
end
end
def create
#category = Category.find(params[:category_id])
#dish = #category.dishes.create(params[:dish])
respond_to do |format|
format.html {
flash[:success] = "Dish created successfully!"
redirect_to(#category) }
format.json { render :json => #category }
end
end
end
app/views/categories/show.html.erb
<p><%= notice %></p>
<h1> Category Details </h1>
...
<hr />
<h2>Dishes</h2>
<table>
<tr>
...
</tr>
<%= render #category.dishes %>
</table>
<%= link_to 'New Dish', newdish_path(:id => #category.id) %>
app/views/dishes/new.html.erb
<h1>New Dish</h1>
<%= render 'form' %>
app/views/dishes/_form.html.erb
<%= form_for([#category, #dish]), :html => { :multipart => true } do |f| %>
...# Here the fields for dishes table will come
<div class="field">
<h4>New Files</h4>
<% f.fields_for :assets do |asset_fields| %>
<% if asset_fields.object.new_record? %>
<p>
<%= asset_fields.file_field :asset %>
</p>
<% end %>
<% end %>
<h4>Old Files</h4>
<% f.fields_for :assets do |asset_fields| %>
<% unless asset_fields.object.new_record? %>
<div class="thumb">
<%= link_to image_tag(asset_fields.object.asset.url(:thumb)), asset_fields.object.asset.url(:original) %>
<%= asset_fields.check_box :_destroy %>
</div>
<% end %>
<% end %>
</div>
...
<div class="actions">
<%= f.submit %>
</div>
<% end %>
While trying to run these code I got an error
SyntaxError in Dishes#new
Showing /home/ragunathjawahar/Desktop/PROJECT/karaikudi-before-send/app/views/dishes/_form.html.erb where line #1 raised:
/home/ragunathjawahar/Desktop/PROJECT/karaikudi-before-send/app/views/dishes/_form.html.erb:1: syntax error, unexpected tASSOC, expecting keyword_end
...r([#category, #dish]), :html => { :multipart => true } do |f...
... ^
/home/ragunathjawahar/Desktop/PROJECT/karaikudi-before-send/app/views/dishes/_form.html.erb:1: syntax error, unexpected keyword_do_block, expecting keyword_end
...ml => { :multipart => true } do |f| #output_buffer.safe_conc...
... ^
/home/ragunathjawahar/Desktop/PROJECT/karaikudi-before-send/app/views/dishes/_form.html.erb:51: syntax error, unexpected keyword_ensure, expecting $end
How to solve this problem?
Thanks in advance...
Correct this line first and tell
<%= form_for([#category, #dish], :html => { :multipart => true }) do |f| %>
use this line for create dish
#dish = Dish.create!(:dishCode => params[:dish][:dishCode] ,:name => params[:dish][:name])
instead of
#dish = #category.dishes.create(params[:dish])
but first check params[:dish][:dishCode] give you value or not.
And chill.......
Try changing this:
<%= form_for([#category, #dish]), :html => { :multipart => true } do |f| %>
to this:
<%= form_for([#category, #dish], :html => { :multipart => true }) do |f| %>
i.e., you are closing the bracket too early.

Resources