Reordering images in Carrierwave multiple file upload - ruby-on-rails

I'm trying to make a frontend mini admin system to reorder the product images stored as an array by Carrierwave multiple upload.
Frontend is working fine.
In my view, I have:
<%= form_for product, url: product_path(product.id), method: :patch do |form| %>
<div class="field">
<%= form.label :images %>
<div class="image-sortable">
<% product.images.each do |image| %>
<div class="image">
<%= hidden_field :product, :images, multiple: true, value: image.cache_name || image.identifier %>
<%= image_tag(image.url, height: 50) %>
<button type="button" class="remove-image">Quitar</button>
</div>
<% end %>
</div>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Params are being passed correctly
Processing by ProductsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"X0UIytX4V56npfBIrl/fkaUiIgP4BDiJOGpB8tCdAZMeP7kvDXV1z0wsGge4Kch1TJG9Gzhpbtt5hOpQXbMH/Q==", "product"=>{"images"=>["6919-000-6.jpg", "6919-000-2.jpg", "6919-000-3.jpg", "6919-000-4.jpg", "6919-000-5.jpg"]}, "commit"=>"Update Product", "id"=>"1169"}
In the product update, the order of images are not stored, and I'm getting null values appended.
Product Update (0.9ms) UPDATE "products" SET "images" = $1, "updated_at" = $2 WHERE "products"."id" = $3 [["images", "[\"6919-000-2.jpg\",\"6919-000-3.jpg\",\"6919-000-4.jpg\",\"6919-000-5.jpg\",\"6919-000-6.jpg\",null,null,null,null,null]"], ["updated_at", "2023-01-26 21:08:11.373942"], ["id", 1169]]
In my controller, I have the standard update method:
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end

Related

Rails 5: Unpermitted parameter: :image

I have a two forms inside my edit action, one is to update an item inside the item.rb model(which works fine)... and the other one is to create an image in a attachment.rb model. The problem is that it creates a row inside the db images with null values and does not save the actually image along with the correct values.
items_contoller.rb
def edit
#attachment = Attachment.new
end
this is the form for the image create:
<%= form_for #attachment, url: create_attachment_path(#attachment), :html => {:id => "form", :multipart => true }, method: :post do |form| %>
<% if #attachment.errors.any? %>
<div class="centerList">
<div id="error_explanation">
<h2><%= pluralize(item.errors.count, "error") %> <%= t 'store_item_edit_4' %></h2>
<% #attachment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</div>
</div>
<% end %>
<%= hidden_field_tag :item_id, value: #item.id %>
<div class="form-group">
<div class="text-center">
<label class="btn btn-primary"><%= t 'store_item_edit_5' %><span style="display:none;">
<%= form.file_field :image, multiple: true, id: "uploads" %></span></label>
<%= form.submit '', :style => "display: none;" %>
<% end %>
this is the route:
post "attachments/create"=> "attachments#create", :as => :create_attachment
attachments_controller.rb
def create
#attachment = Attachment.new(attachment_params)
respond_to do |format|
if #attachment.save
format.html { redirect_back fallback_location: root_path, notice: 'Image was successfully uploaded.' }
format.json { render :show, status: :created, location: #attachment }
else
format.html { render :new }
format.json { render json: #attachment.errors, status: :unprocessable_entity }
end
end
end
def attachment_params
params.require(:attachment).permit(:item_id, :account_id, :image)
end
and this is what I get inside the console... at some point as you can see I get a Unpermitted parameter: :image:
started POST "/attachments/create" for 127.0.0.1 at 2018-03-14 17:20:23 +0200
Processing by AttachmentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"6kgGVoUf2tlM2YdxZis6xavw//zC4azttYi4FFshgw4swiFUIOfb58hCtZxf0If2ihOXz3SCETQSnci6l1IFIA==", "item_id"=>"{:value=>44}", "attachment"=>{"image"=>[#<ActionDispatch::Http::UploadedFile:0x007fc6e4acfb18 #tempfile=#<Tempfile:/var/folders/hq/pr4rt14n7s31v3f6292wtjm00000gn/T/RackMultipart20180314-4193-1jrij48.jpg>, #original_filename="image1.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"attachment[image][]\"; filename=\"image1.jpg\"\r\nContent-Type: image/jpeg\r\n">]}}
Store Load (0.5ms) SELECT "stores".* FROM "stores" WHERE "stores"."id" = $1 ORDER BY "stores"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Unpermitted parameter: :image
(0.2ms) BEGIN
SQL (0.4ms) INSERT INTO "attachments" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2018-03-14 15:20:23.368574"], ["updated_at", "2018-03-14 15:20:23.368574"]]
(1.2ms) COMMIT
Redirected to https://localhost:3000/store/items/edit/44
Completed 302 Found in 8ms (ActiveRecord: 2.3ms)
Any ideas how to fix this:
You should add:
def attachment_params
params.require(:attachment).permit(:item_id, :account_id, image: {})
end

Ruby on rails form doesn't write into database

I am suffering, because I don't get why my form doesn't write data into my database. If I submit the form I get a new line in the database, which only contains "id", "created at" and "updated at". All other parameters are not submitted. In the log file I get a "unpermitted parameters" message. Where can I change this?
I would be very happy for help. Thanks a lot!
Here is the view to the "new institute" page, which contains the form.
<% provide(:title, 'Institut erstellen') %>
<div class="small_jumbotron jumbotron">
<h1>Institut erstellen</h1>
<div class="row">
<div class="Links">
<%= form_for(#institute) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<br>
<%= f.label :Institutsname %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :Professorenanzahl %>
<%= f.number_field :professors, class: 'form-control' %>
<%= f.label "Anzahl wissenschaftlicher Mitarbeiter" %>
<%= f.number_field :employees, class: 'form-control' %>
<%= f.label "Anzahl an Masterarbeiten" %>
<%= f.number_field :master_theses, class: 'form-control' %>
<%= f.label "Anzahl Lehrveranstaltungen" %>
<%= f.number_field :classes, class: 'form-control' %>
<%= f.label "Minimale Bachelorarbeitenzuordnung" %>
<%= f.number_field :min_workload, class: 'form-control' %>
<%= f.label "Überkapazitätsbereitschaft" %>
<%= f.number_field :overload, class: 'form-control' %>
<%= f.label "Aversion gegen Überkapazitäten" %>
<%= f.number_field :overload_aversion, class: 'form-control' %>
<%= f.label "Kapazität" %>
<%= f.number_field :capacity, class: 'form-control' %>
<br>
<%= f.submit "Erstelle das Institut", class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
Here is the institutes controller
class InstitutesController < ApplicationController
before_action :set_institute, only: [:show, :edit, :update, :destroy]
# GET /institutes
# GET /institutes.json
def index
#institutes = Institute.all
end
# GET /institutes/1
# GET /institutes/1.json
def show
end
# GET /institutes/new
def new
#institute = Institute.new
end
# GET /institutes/1/edit
def edit
end
# POST /institutes
# POST /institutes.json
def create
#institute = Institute.new(institute_params)
respond_to do |format|
if #institute.save
format.html { redirect_to #institute, notice: 'Das Institut wurde erstellt.'}
format.json { render :show, status: :created, location: #institute }
else
format.html { render :new }
format.json { render json: #institute.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /institutes/1
# PATCH/PUT /institutes/1.json
def update
respond_to do |format|
if #institute.update(institute_params)
format.html { redirect_to #institute, notice: 'Die Institutsdaten wurden aktualisiert.' }
format.json { render :show, status: :ok, location: #institute }
else
format.html { render :edit }
format.json { render json: #institute.errors, status: :unprocessable_entity }
end
end
end
# DELETE /institutes/1
# DELETE /institutes/1.json
def destroy
#institute.destroy
respond_to do |format|
format.html { redirect_to institutes_url, notice: 'Das Institut wurde gelöscht.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_institute
#institute = Institute.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def institute_params
params.permit(:name, :professors, :employees, :master_theses, :classes, :min_workload, :overload, :overload_aversion, :capacity)
end
end
And now a snippet of the log file
Started POST "/institutes" for 127.0.0.1 at 2018-02-18 16:15:02 +0100
Processing by InstitutesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ufyuHL2iXZpQg1ZmfG1pleuY7aL3JIl+eGn36UJeibML8U5R1sOgw8jd6geBB60XchttET2T3I1SndFgGsR2uA==", "institute"=>{"name"=>"wsd", "professors"=>"", "employees"=>"4", "master_theses"=>"", "classes"=>"", "min_workload"=>"", "overload"=>"", "overload_aversion"=>"", "capacity"=>""}, "commit"=>"Erstelle das Institut"}
Unpermitted parameters: :utf8, :authenticity_token, :institute, :commit
[1m[35m (0.5ms)[0m [1m[36mbegin transaction[0m
[1m[35mSQL (0.6ms)[0m [1m[32mINSERT INTO "institutes" ("created_at", "updated_at") VALUES (?, ?)[0m [["created_at", "2018-02-18 15:15:02.619018"], ["updated_at", "2018-02-18 15:15:02.619018"]]
[1m[35m (17.0ms)[0m [1m[36mcommit transaction[0m
Redirected to http://localhost:3000/institutes/12
Completed 302 Found in 30ms (ActiveRecord: 18.1ms)
You're not using strong_params correctly. Should be like this:
def institute_params
params.require(:institute).permit(:name, :professors, ...)
# ^^^^^^^^^^^^^^^^^^^^
end

Foreach input array param then save 1 record per element in Rails

i'm making a form to upload multiple images with carrierwave. Save array to db work fine but i want to save 1 array element as 1 record, to make it easier to manage later.
I tried to do as below but it return nilClass err.
All picture use the same description, name is image file name
Anyone has done this kind of stuff before :'(
views/_form
<%= form_for [:admin, #picture], :html => {multipart: true, :class => 'form-horizontal'} do |f| %>
<div class="box-body">
<div class="form-group">
<%= f.label :link, :class => 'col-sm-2 control-label' %>
<div class="col-sm-10">
<%= f.file_field :link, multiple: true, :class => 'form-control', :id => 'imgInp' %>
</div>
</div>
<div class="form-group">
<%= f.label :description, :class => 'control-label col-sm-2' %>
<div class="col-sm-10">
<%= f.text_area :description, :class => 'form-control' %>
</div>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<%= link_to admin_pictures_path do %>
<button class="btn btn-default">Back</button>
<% end %>
<%= f.submit nil, :class => 'btn btn-info pull-right' %>
</div>
<!-- /.box-footer --> <% end %>
controller
def create
if params[:link]
params[:link].each { |image|
#picture = Picture.new(name: image.file.filename, description: params[:description], link: image)
#picture.save
}
end
end
respond_to do |format|
if #picture.save
format.html { redirect_to admin_pictures_path, notice: ' picture was successfully created.' }
format.json { render :show, status: :created, location: #picture }
else
format.html { render :new }
format.json { render json: #picture.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_picture
#picture = Picture.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def picture_params
params.require(:picture).permit(:name, :description, :link)
end
end
param[:link] console
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"2KMy3lPMnf3MqLLHpJAH+Ei40nja+KAJGsx2twyP5L05A95b7rLsZHEFoUSu+CMJQunQ4yUq6kmppdK6I7NQkw==",
"picture"=>{"album_id"=>"3", "team_id"=>"", "link"=>[#<ActionDispatch::Http::UploadedFile:0x007f9095ea1c08 #tempfile=#<Tempfile:/tmp/RackMultipart20160331-6776-1h8i98y.jpg>,
#original_filename="images.jpg", #content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"picture[link][]\";
filename=\"images.jpg\"\r\nContent-Type: image/jpeg\r\n">, #<ActionDispatch::Http::UploadedFile:0x007f9095ea1be0 #tempfile=#<Tempfile:/tmp/RackMultipart20160331-6776-y6d6ug.jpg>, #original_filename="images (1).jpg", #content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"picture[link][]\";
filename=\"images (1).jpg\"\r\nContent-Type: image/jpeg\r\n">, #<ActionDispatch::Http::UploadedFile:0x007f9095ea1bb8 #tempfile=#<Tempfile:/tmp/RackMultipart20160331-6776-hizrku.jpg>,
#original_filename="lulu.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"picture[link][]\";
filename=\"lulu.jpg\"\r\nContent-Type: image/jpeg\r\n">],
"description"=>"abc"}, "commit"=>"Create Picture"}
User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
params:
Completed 500 Internal Server Error in 3ms (ActiveRecord: 0.4ms)
This will solve your issue :
def create
if params[:picture][:link]
params[:picture][:link].each { |image|
#picture = Picture.new(:name => image.original_filename,:description => params[:description])
#picture.store!(image.tempfile)
#picture.save
}
end
end
respond_to do |format|
if #picture.save
format.html { redirect_to admin_pictures_path, notice: ' picture was successfully created.' }
format.json { render :show, status: :created, location: #picture }
else
format.html { render :new }
format.json { render json: #picture.errors, status: :unprocessable_entity }
end
end
end
Try
...
#picture = Picture.new(picture_params)
respond_to do |format|
if #picture.save...
so that #picture.save will not result to nil

Rails don't render layout when create record with Ajax

My problem is after I create a new record with ajax I get a NOMETHODERROR and I must reload the page to see the new record.
The Error I get in terminal.
Rendered time_entries/_time_entry.html.erb (3.4ms) Rendered
time_entries/create.js.erb (4.9ms) Completed 500 Internal Server Error
in 41ms (ActiveRecord: 4.4ms)
NoMethodError - undefined method `each' for nil:NilClass:
app/views/time_entries/_time_entry.html.erb:1:in '_app_views_time_entries__time_entry_html_erb___4086905375499854267_70174828432680'
What I do wrong?
time_entries_controller.erb
class TimeEntriesController < ApplicationController
...
respond_to :html, :js
def index
#time_entries = current_user.time_entries.all.order("date DESC")
#time_entries_days = #time_entries.group_by{ |t| t.date.beginning_of_day }
respond_with(#time_entry)
end
def create
#time_entry = TimeEntry.new(timeentry_params)
#time_entry.user_id = current_user.id
respond_to do |format|
if #time_entry.save
format.html { redirect_to #time_entry, notice: 'Arbeitszeit wurde eingetragen' }
format.json { render :show, status: :created, location: #time_entry }
format.js
else
format.html { render :new }
format.json { render json: #time_entry.errors, status: :unprocessable_entity }
format.js
end
end
end
...
_time_entry.html.erb
the partial
<% #time_entries_days.each do |day, time_entries| %>
<% if day.today? %>
<div class="column-12 list-group">Today, <%= l day, format: :dm %></div>
<% else %>
<div class="column-12 list-group"><%= l day, format: :dm %></div>
<% end %>
<ul class="lists">
<% time_entries.each do |time_entry| %>
<li class="list-item" id="time_entry_<%= time_entry.id %>">
<div class="list-item__content">
<h3 class="list-item__title">
<%= link_to time_entry.category.name, time_entry %>
<span><%= l time_entry.start_time, format: :hm %></span> - <span><%= l time_entry.end_time, format: :hm %></span>
</h3>
<p><%= time_entry.note %></p>
</div>
<span class="list-item__label"><%= time_entry.hours %>h</span>
</li>
<% end %>
</ul>
<% end %>
index.html.erb
<% if can? :create, TimeEntry %>
<%= link_to 'Add new Time Entry', new_time_entry_path, remote: true, class: 'btn btn-primary', :data => { :'popup-open' => 'popup-1' } %>
<% end %>
...
<div class="row" id="container_time_entries">
<%= render "time_entry" %>
</div>
create.js.erb for testing
I don't get an alert after I create a new time entry.
alert("HALLO");
create.js.erb normal
$('.modal-bg').hide();
$('.popup').fadeOut(350);
$('#container_time_entries').html("<%= j(render 'time_entry') %>");
You do not set the variable #time_entries_days in your create method, but you need it in your _time_entry.html.erb .
Set it and you should be good to go.

How to make ajax call and show error messages

Two of the action of My registration controller is new and create.
def new
#regist = Regist.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #regist }
end
end
def create
#regist = Regist.new(regist_params)
respond_to do |format|
if #regist.save
format.html { redirect_to #regist, notice: 'Regist was successfully created.' }
format.json { render json: #regist, status: :created, location: #regist }
else
format.html { render action: "new" }
format.json { render json: #regist.errors, status: :unprocessable_entity }
end
end
end
And the new form contain following code.
<%= form_for(#regist) do |f| %>
<% if #regist.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#regist.errors.count, "error") %> prohibited this regist from being saved:</h2>
<ul>
<% #regist.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.collection_select :student_id, Student.all, :id, :name %><br />
</div>
<div class="field">
<%= f.collection_select :semester_id, Semester.all, :id, :name %><br />
</div>
<div class="field">
<% for subject in Subject.find(:all) %>
<%= check_box_tag "regist[subject_ids][]", subject.id %>
<%= subject.name %><br>
<% end %>
</div>
<div class="field">
<%= f.label :date_of_birth %><br />
<%= f.text_field :date_of_birth %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Now, when someone click on submit button I want to make ajax call using remote true if there are validation errors and show the errors without reloading the page. And if there are no validation errors I want the user to be redirected to show page. How can I do this?
First of all you should add a remote: true to your existing form to allow remote action.
TODO this just add on the first line of your form the remote: true,
<%= form_for(#regist, remote: true) do |f| %>
the rest leave it as it is. Then you need to make your controller to respond to remote calls, therefore you need to alter the responds_to block of create action:
respond_to do |format|
if #regist.save
format.html { redirect_to #regist, notice: 'Regist was successfully created.' }
format.json { render json: #regist, status: :created, location: #regist }
format.js { render js: "window.location.href='"+regists_path+"'"}
else
format.html { render action: "new" }
format.json { render json: #regist.errors, status: :unprocessable_entity }
format.js
end
end
The last step you have to do is to add a file to your app/views/regists/ directory
where you should add a create.js.erb file:
<% if #regist.errors.any? %>
$('#new_regist').effect('highlight', { color: '#FF0000'}, 1000); // for highlighting
// or add here whatever jquery response you want to have to your views.
<% end %>
You will get your validation errors displayed like before above the form.
You have to add the redirect to your controller to the desirable action of your choice. I have added for you a window.location.href as a response to the regists_path.

Resources