i am creating a form where you can upload the image file, but whenever i submit the form, it dosent permit the image and in the terminal it shows
"Unpermitted parameter: :image. Context: { controller: InstrumentsController, action: update, request: #ActionDispatch::Request:0x00007f1955b24b50, params: {"_me................."
also if i check using the rails console if the image is being uploaded or not by typing the Instrument.all (Instrument is a table in database), it shows that it is nil,
i have permitted the :image in params
instruments_controller.rb
class InstrumentsController < ApplicationController
before_action :set_instrument, only: %i[ show edit update destroy ]
before_action :authenticate_user!, except: [:index, :show]
# GET /instruments or /instruments.json
def index
#instruments = Instrument.all.order("created_at desc")
end
# GET /instruments/1 or /instruments/1.json
def show
end
# GET /instruments/new
def new
#instrument = current_user.instruments.build
end
# GET /instruments/1/edit
def edit
end
# POST /instruments or /instruments.json
def create
#instrument = current_user.instruments.build(instrument_params)
respond_to do |format|
if #instrument.save
format.html { redirect_to instrument_url(#instrument), notice: "Instrument was successfully created." }
format.json { render :show, status: :created, location: #instrument }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #instrument.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /instruments/1 or /instruments/1.json
def update
respond_to do |format|
if #instrument.update(instrument_params)
format.html { redirect_to instrument_url(#instrument), notice: "Instrument was successfully updated." }
format.json { render :show, status: :ok, location: #instrument }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #instrument.errors, status: :unprocessable_entity }
end
end
end
# DELETE /instruments/1 or /instruments/1.json
def destroy
#instrument.destroy
respond_to do |format|
format.html { redirect_to instruments_url, notice: "Instrument was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_instrument
#instrument = Instrument.find(params[:id])
end
# Only allow a list of trusted parameters through.
def instrument_params
params.require(:instrument).permit(:brand, :model, :description, :condition, :finish, :tiitle, :price, :image)
end
end
and inside the model (ignore 'tiitle' as i have already done a typo and continue to use it instead of 'title')
instrument.rb
class Instrument < ApplicationRecord
mount_uploader :image, ImageUploader
belongs_to :user, optional: true
validates :tiitle, :brand, :price, :model, presence: true
validates :description, length: { maximum: 1000, too_long: "%{count} is the maximum allowed characters" }
validates :tiitle, length: { maximum: 140, too_long: "%{count} is the maximum allowed characters" }
validates :price, numericality: { only_integer: true }, length: { maximum: 7 }
BRAND = %w{ Fender Gibson Epiphone ESP Martin Dean Taylor Jackson PRS Ibanez Charvel Washburn }
FINISH = %w{ Black White Navy Blue Red Clear Satin Yellow Seafoam }
CONDITION = %w{ New Excellent Mint Used Fair Poor }
end
_form.html.erb
<%= simple_form_for #instrument, html: { multipart: true } do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="form-inputs">
<div class="row ">
<div class="col mx-auto">
<div class="card mt-2 mx-auto p-4 bg-light">
<div class="card-body bg-light">
<div class = "container">
<div class="controls">
<div class="row">
<div class="col-md-10">
<div class="form-group">
<%= f.input :tiitle, input_html: {class: "form-control"} %>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<%= f.input :model, input_html: {class: "form-control"} %>
</div>
</div>
<div class="col-sm-2">
<div class="form-group">
<%= f.input :price %>
</div>
</div>
</div>
</div>
</div>
<%= f.input :description %>
<%= f.label :condition %>
<div class="row">
<div class="col-sm-1">
<div class="form-group">
<%= f.input_field :condition, collection: Instrument::CONDITION, prompt: "Select Condition" %>
</div>
</div>
</div>
<%= f.label :brand %>
<div class="row">
<div class="col-sm-1">
<div class="form-group">
<%= f.input_field :brand, collection: Instrument::BRAND, prompt: "Select Brand" %>
</div>
</div>
</div>
<%= f.label :finish %>
<div class="row">
<div class="col-sm-1">
<div class="form-group">
<%= f.input_field :finish, collection: Instrument::FINISH, prompt: "Select Finish" %>
</div>
</div>
</div>
<%= f.input :image, as: :file, input_html:{ multiple: true, class:"file-input instrument-image" }, label: false, wrapper: false %>
</div>
</div>
</div>
</div>
</div>
<div class="form-actions">
<div class="row">
<div class="col-sm-1">
<%= f.button :submit, "Create instrument", class: "btn btn-success create-instrument-btn" %>
</div>
<div class="col-sm-2">
<%= link_to "Cancel", instruments_path, class: "btn btn-danger cancel-instrument-btn" %>
</div>
</div>
</div>
<% end %>
image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url(*args)
# # For Rails 3.1+ asset pipeline compatibility:
# # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
# Process files as they are uploaded:
# process scale: [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
version :thumb do
process resize_to_fit: [400, 300]
end
version :default do
process resize_to_fit: [800, 600]
end
# Add an allowlist of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_allowlist
%w(jpg jpeg gif png)
end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
i am a newbie, according to the knowledge what i have understood is that we have to use html: {multipart: true} in the form initializing so that it accepts the uploader as file and permit the ':image' in controller's file and it should work but when i click the "Create" button, it dosen't upload the image and shows unpermitted params in terminal while i submit it and creates a new instrument with all fields except the uploader.
Any fixes? :')
UPDATE: i fixed it by using
sudo apt-get install libmagickwand-dev
sudo apt-get install imagemagick --fix-missing
and the image is now being saved to the database
Related
Apologies in advance if this is a stupid question. I am learning Rails from scratch, so thanks for bearing with me.
So, I have a 'Person' model, shown below
class Person < ActiveRecord::Base
belongs_to :team
has_and_belongs_to_many :events, through: :event_people
validates :first_name, presence: true, length: { maximum: 255 }
validates :last_name, presence: true, length: { maximum: 255 }
validates :email, presence: true, length: { maximum: 255 }
end
and have created a form to create a new person, with associated team ID
<h1>Add new person</h1>
<div class="row">
<div class="col-md-8">
<%= form_with url: new_person_path do |person| %>
<div class="form-group">
<%= person.label :first_name %>
<%= person.text_field :name, id: :person_first_name, class:"form-control" %>
</div>
<div class="form-group">
<%= person.label :last_name %>
<%= person.text_field :name, id: :person_last_name, class:"form-control" %>
</div>
<div class="form-group">
<%= person.label :email %>
<%= person.text_field :email, id: :person_email, class:"form-control" %>
</div>
<div class="form-group">
<%= person.label :job_title %>
<%= person.text_field :job_title, id: :person_job_title, class:"form-control" %>
</div>
<div class="form-group">
<% #teams = Team.all %>
<%= person.label :team %>
<%= person.select(:team_id, #teams.collect{|a| [a.name, a.id]}, { include_blank: true }, {:class => "form-control"}) %>
</div>
<div class="actions">
<%= person.submit 'Submit button', {:class => 'btn btn-primary'}%>
</div>
<% end %>
</div>
</div>
and my routes.rb file is set up like this:
Rails.application.routes.draw do
resources :people
resources :teams
resources :organisations
resources :events
end
But whenever I submit the form to create a new person, I get the following error in the console:
POST http://localhost:3000/people/new 404 (Not Found)
Event though the relevant methods exist in my people_controller.rb:
class PeopleController < ApplicationController
def index
#people = Person.all
end
def show
#people = Person.find(params[:id])
end
def new
#people = Person.new
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #people }
end
end
def create
#people = Person.new(params[:person])
respond_to do |format|
if #people.save
format.html { redirect_to(#people,
:notice => 'Person was successfully created.') }
format.json { render :json => #people,
:status => :created, :location => #people }
else
format.html { render :action => "new" }
format.json { render :json => #people.errors,
:status => :unprocessable_entity }
end
end
end
Can anyone suggest what I might be doing wrong?
When you have an underlying model you will want to use <%= form_with model: #people do |person| %>
Reference: http://api.rubyonrails.org/v5.1/classes/ActionView/Helpers/FormHelper.html#method-i-form_with
You are posting to a method which, at least as far as I can tell, is supposed to output an empty form for entering attributes of your person.
Try a GET first, which would be in keeping with the rails interpretation of is REST URLs. Likely, the correct route also has no /new at the end.
Next, try rails routes to list all available routes.
By the way, if in development, rails should give you a meaningful, large help page, likely including available routes. Check your development.rb for some flag to enable that.
I really have no idea what to do now. Image is showing up as nil in database. There are no errors showing up.
Model
class Resource < ActiveRecord::Base
mount_uploader :image, ImageUploader
attr_accessible :title, :url, :description, :tag
validates :title, presence: true, uniqueness: true
validates :url, presence: true
validates :description, presence: true
validates :tag, presence: true
belongs_to :user
acts_as_votable
validates_processing_of :image
validate :image_size_validation
private
def image_size_validation
errors[:image] << "should be less than 500KB" if image.size > 0.5.megabytes
end
end
Image Uploader
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :thumb do
process :resize_to_fill => [100, 100]
end
def extension_white_list
%w(jpg jpeg gif png)
end
end
Form Partial
<%= form_for #resource, html: { multipart: true } do |f| %>
<% if #resource.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#resource.errors.count, "error") %> prohibited this pet
from being saved:</h2>
<ul>
<% #resouce.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :url %><br>
<%= f.text_area :url%>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :tag %><br>
<%= f.text_area :tag %>
<div class="field">
<%= f.label :image %><br>
<%= f.file_field :image %>
<% if f.object.image? %>
<%= image_tag f.object.image.thumb.url %>
<%= f.label :remove_image %>
<%= f.check_box :remove_image %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
Image tag in show
<%= image_tag #resource.image.thumb.url %>
Controller
class ResourcesController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
def index
#resources = Resource.page(params[:page]).per(15)
end
def show
#resource = Resource.where(:id => params[:id]).first
end
def edit
#resource = Resource.where(:id => params[:id]).first
end
def new
#resource = current_user.resources.build
end
def update
#resource = Resource.where(:id => params[:id]).first
respond_to do |format|
if #resource.update_attributes(resources_params)
format.html { redirect_to #resource, :notice => 'Resource was successfully
updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #resource.errors, :status =>
:unprocessable_entity }
end
end
end
def destroy
#toDelete = Resource.where(:id => params[:id]).first
puts #toDelete.id
if #toDelete.destroy
flash[:notice] = "Successfully deleted post!"
redirect_to root_path
else
flash[:alert] = "Error updating post!"
end
end
def create
#resource= current_user.resources.build(resources_params)
if #resource.save
redirect_to root_path
flash[:alert] = "Successfully created new resource!"
else
render "new"
end
end
def upvote
#resource = Resource.find(params[:id])
#resource.upvote_by current_user
redirect_to :back
end
def downvote
#resource = Resource.find(params[:id])
#resource.downvote_from current_user
redirect_to :back
end
private
def resources_params
params.require(:resource).permit(:title, :url, :description, :image, :tag)
end
end
If there is any other file you would like to see, I will post it.
Thank You.
EDIT
It was just a versioning problem......
I'm very new to Rails development and having a problem saving multiple images/attachments to a model. My problem is that the code below is not actually saving to the item_images table when I submit the form. I am following This Article as a guide, though it seems to be a bit out of date. I feel I'm in a little over my head at this point so I hope someone can point out what I'm missing. Thanks!
I have the following models:
item.rb
class Item < ActiveRecord::Base
has_many :item_images, :dependent => :destroy
accepts_nested_attributes_for :item_images, :reject_if => lambda { |t| t['item_image'].nil? }
end
item_image.rb
class ItemImage < ActiveRecord::Base
belongs_to :item
has_attached_file :image,
:styles => { thumb: "100x100#", small: "400x400#", large: "700x700" }
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
end
My controller looks like this:
items_controller.rb
class ItemsController < ApplicationController
before_action :set_item, only: [:show, :edit, :update, :destroy]
# GET /items
# GET /items.json
def index
#items = Item.all
end
# GET /items/1
# GET /items/1.json
def show
end
# GET /items/new
def new
#item = Item.new
4.times {#item.item_images.build}
end
# GET /items/1/edit
def edit
4.times {#item.item_images.build}
end
# POST /items
# POST /items.json
def create
#item = Item.new(item_params)
respond_to do |format|
if #item.save
format.html { redirect_to #item, notice: 'Item was successfully created.' }
format.json { render :show, status: :created, location: #item }
else
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /items/1
# PATCH/PUT /items/1.json
def update
respond_to do |format|
if #item.update(item_params)
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: #item }
else
format.html { render :edit }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /items/1
# DELETE /items/1.json
def destroy
#item.destroy
respond_to do |format|
format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_item
#item = Item.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def item_params
params.require(:item).permit(:title, :description, :price, :available, :sort_shop, :sort_gallery, :item_type, :size)
end
end
form.html.erb
<%= form_for #item, html: { multipart: true } do |f| %>
<% if #item.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#item.errors.count, "error") %> prohibited this item from being saved:</h2>
<ul>
<% #item.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :price %><br>
<%= f.text_field :price %>
</div>
<div class="field">
<%= f.label :available %><br>
<%= f.check_box :available %>
</div>
<div class="field">
<%= f.label :sort_shop %><br>
<%= f.number_field :sort_shop %>
</div>
<div class="field">
<%= f.label :sort_gallery %><br>
<%= f.number_field :sort_gallery %>
</div>
<div class="field">
<%= f.label :item_type %><br>
<%= f.text_field :item_type %>
</div>
<div class="field">
<%= f.label :size %><br>
<%= f.text_field :size %>
</div>
<%= f.fields_for :item_images do |builder| %>
<% if builder.object.new_record? %>
<div class="field">
<%= builder.label :image, "Image File" %>
<%= builder.file_field :image %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Try this in strong parameters in Items controller
params.require(:item).permit(:title, :description, :price, :available, :sort_shop, :sort_gallery, :item_type, :size,item_images_attributes: [:image ])
than in ItemImage.rb add this line
belongs_to :item, optional: true,
and remove this line from Item.rb
:reject_if => lambda { |t| t['item_image'].nil? }
`
If you get any error please reply
I'm trying to upload image using paperclip. But the exception "NoMethodError in Shop::ProductsController#create undefined method `chomp' for nil:NilClass" occurs. Can anyone see and highlight the problem please?
Here is Gemfile code
gem 'paperclip', '~> 4.2.1'
Controller
class Shop::ProductsController < ApplicationController
layout "shop"
def index
#products = Product.find_by_shop_id(session[:shop_id]).sort_by_name
# #products = Product.products.sort_by_name
end
def show
#product = Product.find(params[:id])
end
def new
#product = Product.new
end
def edit
#product = Product.find(params[:id])
end
def create
#product = Product.new(product_params)
#product.shop = Shop.find(session[:shop_id].to_i)
if #product.save
redirect_to :action => 'new'
else
render 'new'
end
end
def update
#product = Product.find(params[:id])
if #product.update(product_params)
redirect_to admin_products_path
else
render 'edit'
end
end
def destroy
#product = Product.find(params[:id])
#product.destroy
redirect_to admin_products_path
end
private
def product_params
params.require(:product).permit(:name, :desc, :price, :display, :status)
end
end
View
<%= form_for [:shop, #product] do |f| %>
<div class="box-body">
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, :class => 'form-control', :placeholder => 'City name' %>
</div>
<div class="form-group">
<%= f.label "Description" %>
<%= f.text_area :desc, :class => 'form-control', :placeholder => 'Write description here...', :rows => 5 %>
</div>
<div class="form-group">
<%= f.label :price %>
<%= f.text_field :price, :class => 'form-control', :placeholder => '0.0' %>
</div>
<div class="form-group">
<%= f.label :display %>
<%= f.file_field :display %>
</div>
<div class="checkbox">
<label>
<%= f.check_box :status %> Is enabled?
</label>
</div>
</div><!-- /.box-body -->
<div class="box-footer">
<%= f.submit :class => "btn btn-primary" %>
</div>
<% end %>
Model
class Product < ActiveRecord::Base
has_attached_file :display, :styles => {:thumb => "500x500>"}
validates_attachment_content_type :display, :content_type => /\Aimage\/.*\Z/
scope :enabled, lambda {where("products.status = 1")}
scope :sort_by_name, lambda { order("products.name asc")}
end
You need to install ImageMagik in your machine
Install ImageMagik
And for windows 7+
Install File.exe
i am using carrierwave for multiple file uploads.
My post model:
class Post < ActiveRecord::Base
has_many :post_attachments
accepts_nested_attributes_for :post_attachments
end
post_attachment.rb:
class PostAttachment < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
belongs_to :post
end
posts_controller.rb:
def show
#post_attachments = #post.post_attachments.all
end
def new
#post = Post.new
#post_attachment = #post.post_attachments.build
end
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
params[:post_attachments]['avatar'].each do |a|
#post_attachment = #post.post_attachments.create!(:avatar => a, :post_id => #post.id)
end
format.html { redirect_to #post, notice: 'Post was successfully created.' }
else
format.html { render action: 'new' }
end
end
end
private
def post_params
params.require(:post).permit(:title, post_attachments_attributes: [:id, :post_id, :avatar])
end
and my posts/_form is:
<%= form_for(#post, :html => { :multipart => true }) do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<%= f.fields_for :post_attachments do |p| %>
<div class="field">
<%= p.label :avatar %><br>
<%= p.file_field :avatar, :multiple => true, name: "post_attachments[avatar][]" %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Actually the above code is referred from Rails 4 multiple image or file upload using carrierwave.
Initially i have done single file upload using http://richonrails.com/articles/allowing-file-uploads-with-carrierwave where I used to download the file. For this I used to write a method in my controller as:
def download
respond_to do |format|
format.html {
if params[:post_id].nil?
redirect_to :back
else
begin
post = Post.find(params[:post_id])
attachment_file = File.join('public', post.attachment.url)
if File.exists?(attachment_file)
send_file attachment_file, :disposition => 'attachment'
else
redirect_to :back
end
rescue Exception => error
redirect_to :back
end
end
}
end
end
and in posts/index.html.erb:
<% #posts.each do |post| %>
<tr>
<td align="center">
<%= link_to image_tag("download.png"), download_post_path(post.id) %>
</td>
</tr>
<% end %>
attachment_uploader.rb:
class AttachmentUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
How can I download multiple files for a post_id as a zip with my code?