rails paperclip: param is missing or the value is empty - ruby-on-rails

I am working on a rails app and making a nested resource for pictures. The model is Picture, and it is polymorphic and interacts with a couple different tables.
I am working on the controller action, and the create method. According to this answer and other things I have seen with paperclip, the params should follow the format of table_name and then file. Even when doing that, I am still getting a param is missing or the value is empty: picture error.
Here is my code:
Picture.rb
class Picture < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
has_attached_file :image, style: { small: '64x64', medium: '100x100', large: '200x200' }
validates_attachment :image, presence: true, content_type: { content_type: /\Aimage\/.*\Z/ },
size: { in: 0..5.megabytes }, default_url: 'missing_img.png'
acts_as_list scope: [:imageable_id, :imageable_type]
end
pictures_controller.rb
class PicturesController < ApplicationController
before_action :authorize_user!
before_action :set_resource!
def index
#pictures = #resource.pictures
end
def create
#picture = #resource.pictures.new(picture_params) do |pic|
pic.imageable_type = #resource
pic.imageable_id = #resource.id
end
if #picture.save
redirect_to :back
flash[:success] = 'Image Saved!'
else
redirect_to :back
flash[:danger] = "#{#picture.errors.full_messages.to_sentence}"
end
end
def destroy
#picture = Picture.find(params[:id])
#resource.pictures.delete(#picture)
redirect_to :back
flash[:success] = "Picture deleted"
end
private
def set_resource!
klass = [Gym, User, Location, Product].detect { |c| params["#{c.name.underscore}_id"] }
#resource = klass.find(params["#{klass.name.underscore}_id"])
end
def picture_params
params.require(:picture).permit(:image)
end
end
pictures/index.html
<h6>Upload Pictures</h6>
<%= form_for(current_user, url: url_for(controller: 'pictures', action: 'create'), method: :post, html: { multipart: true, class: 'form-horizontal' }) do |f| %>
<%= f.file_field :image, type: :file, multiple: true, style: 'padding-bottom: 25px;' %>
<%= f.submit "Upload", class: "btn btn-gen" %>
<% end %>
And here is the param request on form submit:
{"utf8"=>"✓",
"authenticity_token"=>"+fsA6liECF7pkUp/0BA0wDHq9Vv63jB+WBb7O/uUEDhhmIOZ22Rb1rNWDwuwPTDPNS7jg7vP/fVCVllDV21wDw==",
"user"=>{"image"=>[#<ActionDispatch::Http::UploadedFile:0x007f87b138acf8 #tempfile=#<Tempfile:/var/folders/9c/1_0mk00n297f560_fpv9jzl40000gn/T/RackMultipart20161020-25582-3qt3gc.jpg>,
#original_filename="b4lROOR.jpg",
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"user[image][]\"; filename=\"b4lROOR.jpg\"\r\nContent-Type: image/jpeg\r\n">]},
"commit"=>"Upload",
"user_id"=>"15"}
Even with this, I am still getting the error. Does anyone see anything wrong I'm doing in my code that I could fix? Any help is much appreciated.

The problem is that your picture_params method requires the route param key picture while your form has the key user.
Lets do some refactoring:
private
def set_resource!
#resource = resource_class.find(params[param_key + "_id"])
end
def resource_class
#resource_class ||= [Gym, User, Location, Product].detect do |c|
params[ param_key(c) + "_id" ]
end
end
def param_key(klass = resource_class)
ActiveModel::Naming.param_key(klass)
end
def picture_params
params.require(param_key).permit(:image)
end
Instead of klass.name.underscore we use ActiveModel::Naming which is how rails figures out how to use models for stuff like routes, params or translations.

I figured out a temporary work around. Definitely not ideal, and if anyone has a better suggestion I would love to hear it. But here is what I currently have that does work.
def create
pic = nil
if params[:user]['image']
params[:user]['image'].each do |image|
pic = #resource.pictures.create(image: image, imageable_type: #resource, imageable_id: #resource.id)
end
if pic.save
redirect_to :back
flash[:success] = 'Image Saved!'
else
redirect_to :back
flash[:danger] = "#{pic.errors.full_messages.to_sentence}"
end
else
flash[:danger] = "Picture file not found"
redirect_to :back
end
end

Related

Keep getting ActionController::UnknownFormat for nested resource view

Every time I go to this link /books/2/chapter I get this error:
ChaptersController#index is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: []
Please show me where I am going wrong and any other improvements I can make to my code.
These are my controllers
class ChaptersController < ApplicationController
def show
#chapter =Chapter.find(params[:id])
#sections = Section.all
end
def index
#chapters = Chapter.all
#book = Book.find(params[:book_id])
end
def new
#chapter = Chapter.new
#book = Book.find(params[:book_id])
end
def edit
#chapter = Chapter.find(params[:id])
end
def create
#chapter = Chapter.new(chapter_params)
#book = Book.find(params[:book_id])
if #chapter.save
redirect_to #chapter
else
render 'new'
end
end
def update
#chapter = Chapter.find(params[:id])
if #chapter.update(chapter_params)
redirect_to #chapter
else
render 'edit'
end
end
def destroy
#chapter = Chapter.find(params[:id])
#chapter.destroy
redirect_to chapters_path
end
private
def chapter_params
params.require(:chapter).permit(:title,:text)
end
end
and
class BooksController < ApplicationController
def show
#book = Book.find(params[:id])
#chapters = Chapter.all
end
def index
#books = Book.all
end
def new
#book = Book.new
end
def edit
#book = Book.find(params[:id])
end
def create
#book = Book.new(book_params)
if #book.save
redirect_to #book
else
render 'new'
end
end
def update
#book = Book.find(params[:id])
if #book.update(book_params)
redirect_to #book
else
render 'edit'
end
end
def destroy
#book = Book.find(params[:id])
#book.destroy
redirect_to books_path
end
private
def book_params
params.require(:book).permit(:title,:text,:bookcover,:authorpic,:author)
end
end
These are my models
class Chapter < ApplicationRecord
has_many :sections, dependent: :destroy
belongs_to :book
validates :title, presence: true,
length:{minimum: 5}
end
and
class Book < ApplicationRecord
has_many :chapters, dependent: :destroy
has_attached_file :bookcover, styles: { medium: "300x300>", thumb: "100x100>" }
has_attached_file :authorpic, styles: { medium: "300x300>", thumb: "100x100>" }
validates_attachment_content_type :bookcover, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
validates_attachment_content_type :authorpic, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
validates :title, presence: true,
length:{minimum: 5}
end
These are my routes
Rails.application.routes.draw do
devise_for :users
root to: 'pages#home'
get 'about', to: 'pages#about'
resources :contacts, only: :create
get 'contact-us', to: 'contacts#new', as: 'new_contact'
get 'bookclub', to: 'pages#bookclub'
get 'podcast', to: 'pages#podcast'
resources :essays do
resources :comments
end
resources :podcasts do
resources :podcomments
end
resources :books do
resources :chapters do
resources :sections do
resources :bookcomments
end
end
end
end
This is my chapters/_index.html.erb file
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col"><h3>Chapters</h3>
</div>
</div>
<%= link_to 'New chapter', new_book_chapter_path(#book) %>
<% #chapters.each do |chapter| %>
<ul class="demo-list-item mdl-list">
<li class="mdl-list__item">
<span class="mdl-list__item-primary-content">
<%=link_to chapter.title, book_chapter_path(#book, chapter)%>
</span>
</li>
</ul>
<%= link_to 'Edit', edit_book_chapter_path(#book, chapter) %>
<%= link_to 'Destroy', book_chapter_path(#book, chapter),
method: :delete,
data: { confirm: 'Are you sure?' } %>
<%end%>
This is my books/show.html.erb file
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col"><h3><%= #book.title %></h3>
</div>
<%= render 'chapters/index', chapters: #chapters %>
<p>
<%= link_to 'Edit', edit_book_path(#book) %> |
<%= link_to 'Back', books_path %>
</p>
Why chapters/_index and not chapters/index? This must be the error.
I think you have some errors in your controllers.
def index
# Do you really want all chapters? (from all books)
# #chapters = Chapter.all
#book = Book.find(params[:book_id])
# I think you want only this book's chapters
#chapters = #book.chapters
end
def show
#chapter =Chapter.find(params[:id])
# The same thing. You want only sections from this chapter
# #sections = Section.all
#sections = #chapter.sections
end
EDIT
I see you are using chapters/_index as a partial from book/show. But you are also using the same in ChaptersController#index. Although not very nice you could do this:
chapters/index.html.erb
<%= render partial: 'chapters/_index', locals: { book: #book, chapters: #chapters } %>
in chapters/_index, replace #chapters by chapters (without #) and #book by book (without #)

Image does not upload carriewave / simple_form / Rails

When I try to create new record image doesn't upload but when I try to edit everything working fine. No errors, after create I have nil in DB after Update I have a link to a picture and everything fine. What I did wrong? Before I used form_for and everything was working fine, then I change form_for to simple_form. Maybe problem here?
Controller:
def create
#byebug
#bar = current_user.bars.new(bar_params)
if #bar.save
UserMailer.admin_verify_email(#bar.id).deliver_now
flash[:success] = t(".bar_created_successfully")
# if admin_verified add bar to the search bos
if #bar.admin_verified
Barsearchsuggestion.index_bar(#bar)
redirect_to bars_path(my_bar: true)
else
redirect_to bar_status_user_path(current_user)
end
else
flash.now[:alert] = #bar.errors.full_messages
render 'users/add_bar'
end
end
def edit
#bar = Bar.find(params[:id])
end
def update
#bar = Bar.find(params[:id])
if #bar.update_attributes(bar_params)
flash[:success] = "Bar updated."
redirect_to bar_status_user_path(current_user)
else
flash.now[:error] = I18n.t("simple_form.error_notification.default_message")
# flash[:error] = #bar.errors.to_array
render 'edit'
end
end
private
def bar_params
params.require(:bar).permit!
end
View:
=simple_form_for(#bar) do |f|
.form-group
= f.label :profile_picture
= t(".profile_picture_ext_html")
%br
= image_tag f.object.profile_picture.bar_detail.url
= f.file_field :profile_picture, class: 'form-control'
Model:
mount_uploader :profile_picture, BarPictureUploader
You have to permit the profile_picture parameter like this:
def bar_params
params.require(:bar).permit(:profile_picture)
end
Try setting multipart: true in your form

Ruby On Rails Nokogiri gem importing orders from xml working not fully. Possibly permitted perimeters

I'm having some trouble with Nokogiri.
I'm new to this xml parsing and I seem to get no errors. I get the order imported alert.
Which means it may be permitted perimeters. If I'm right then, Could I create a model that allows all permitted perimeters. So please take a look, thank you for your time, here is my code:
Routes.rb
resources :orders do
collection { post :import }
get "/confirm" => "confirmations#show"
get 'dconfirmation' => 'orders#confirmation'
end
Model
class Order < ActiveRecord::Base
belongs_to :user
scope :not_completed_orders, -> {
where(:complete => false)
}
require 'nokogiri'
def self.import(file)
doc = Nokogiri::XML.parse(file)
#your processing code goes here
end
end
Controller Order
class OrdersController < ApplicationController
before_filter :authenticate_user!
def new
#order = Order.new
end
def create
#order = current_user.orders.new(order_params)
#order.email = current_user.email
#order.name = current_user.name
#order.address_line_1 = current_user.address_line_1
#order.address_line_2 = current_user.address_line_2
#order.postcode = current_user.postcode
#order.city = current_user.city
#order.country = current_user.country
if #order.save
redirect_to dconfirmation_path
end
end
def order_params
params.require(:order).
permit(
:email,
:delivery_name,
:company_name,
:delivery_address1,
:delivery_address2,
:delivery_address3,
:delivery_city,
:delivery_postcode,
:delivery_country,
:phone,
:package_contents,
:description_content,
:restricted_items,
:terms_conditions,
:insurance,
:contents_value,
:cf_reference,
:reference_number,
:service
)
end
def show
#user = User.find(params[:id])
end
def confirmation
end
def import
Order.import(params[:file])
redirect_to root_url, notice: "Order imported."
end
end
View
= form_tag import_orders_path, multipart: true do
= file_field_tag :file
= submit_tag "Import"

Can't write params to Model. Ruby on Rails

I trying write params to Company model. But I have error undefined method `model_name' for NilClass:Class in this point = simple_form_for #company, url: update_settings_company_path do |f|. Where I must set #company?
Controller
def change_settings
#vacation_days = current_company.vacation_days
#illnes_days = current_company.illnes_days
end
def update_settings
if #company.update(company_params)
redirect_to account_company_path, notice: t('company.settings_changed')
else
render action: 'change_settings'
end
end
private
def company_params
params.require(:company).permit(:vacation_days, :illnes_days)
end
View
.company_settings
= simple_form_for #company, url: update_settings_company_path do |f|
= f.error_notification
= f.input :vacation_days
= f.input :illnes_days
%br
= f.submit t('common.save'), class: 'btn'
= link_to t('common.back'), account_company_path, class: 'btn'
routes
resource :company, only: :all do
get :change_settings
post :update_settings
patch :update_settings
end
What's wrong? Help me please
You don't set #company instance variable in both your actions. You can do it using before_filter, like this:
before_filter :find_company
def change_settings
#vacation_days = current_company.vacation_days
#illnes_days = current_company.illnes_days
end
def update_settings
if #company.update(company_params)
redirect_to account_company_path, notice: t('company.settings_changed')
else
render action: 'change_settings'
end
end
private
def company_params
params.require(:company).permit(:vacation_days, :illnes_days)
end
def find_company
#company = current_company
end
Try this instead, You need to set the instance variable before you use it. By default the instance variable is set to nil.
def update_settings
#company = current_company
if #company.update(company_params)
redirect_to account_company_path, notice: t('company.settings_changed')
else
render action: 'change_settings'
end
end

How do I fix the fields_for error: # "is not allowed as an instance variable n" in Rails?

My goal is to enable a user to be able to submit multiple NewsImages from a parent Blog form.
My Blog model looks like this:
# == Schema Information
# Schema version: 20091006171847
#
# Table name: blogs
#
# id :integer(4) not null, primary key
# title :string(255)
# body :text
# profile_id :integer(4)
# created_at :datetime
# updated_at :datetime
#
class Blog < ActiveRecord::Base
has_many :comments, :as => :commentable, :order => "created_at asc"
has_many :news_images, :dependent => :destroy
belongs_to :profile
accepts_nested_attributes_for :news_images
validates_presence_of :title, :body
attr_immutable :id, :profile_id
def after_create
feed_item = FeedItem.create(:item => self)
([profile] + profile.friends + profile.followers).each{ |p| p.feed_items << feed_item }
end
def to_param
"#{self.id}-#{title.to_safe_uri}"
end
end
My NewsImage model looks like this:
class NewsImage < ActiveRecord::Base
belongs_to :blog
validates_each :blog do |news_image, attr, value|
news_item.errors.add attr, "You are only limited to 5 images." if news_item.blog.news_items.size >= 5
end
has_attached_file :image, :styles => { :original => "1920x1080>", :square => "158x158#", :thumb => "386x155#", :slide_thumb => "165x67#"},
:url => "/system/:attachment/:id/:style/:basename.:extension",
:path => ":rails_root/public/system/:attachment/:id/:style/:basename.:extension"
def validate
dimensions = Paperclip::Geometry.from_file(self.image.queued_for_write[:original])
self.errors.add(:image, "Please upload an image that is at least 476 pixels wide") if dimensions.width < 476
self.errors.add(:image, "Please upload an image that is at least 319 pixels high") if dimensions.height < 319
end
end
My Blog controller looks like this:
class BlogsController < ApplicationController
skip_filter :login_required, :only => [:index, :show]
prepend_before_filter :get_profile
before_filter :setup
def index
if #p && #p == #profile && #p.blogs.empty?
flash[:notice] = 'You have not create any blog posts. Try creating one now.'
redirect_to new_profile_blog_path(#p) and return
end
respond_to do |wants|
wants.html {render}
wants.rss {render :layout=>false}
end
end
def create
#blog = #p.blogs.build params[:blog]
respond_to do |wants|
if #blog.save
wants.html do
flash[:notice] = 'New blog post created.'
redirect_to profile_blogs_path(#p)
end
else
wants.html do
flash.now[:error] = 'Failed to create a new blog post.'
render :action => :new
end
end
end
end
def show
render
end
def edit
render
end
def update
respond_to do |wants|
if #blog.update_attributes(params[:blog])
wants.html do
flash[:notice]='Blog post updated.'
redirect_to profile_blogs_path(#p)
end
else
wants.html do
flash.now[:error]='Failed to update the blog post.'
render :action => :edit
end
end
end
end
def destroy
#blog.destroy
respond_to do |wants|
wants.html do
flash[:notice]='Blog post deleted.'
redirect_to profile_blogs_path(#p)
end
end
end
protected
def get_profile
#profile = Profile[params[:profile_id]]
end
def setup
#user = #profile.user
#blogs = #profile.blogs.paginate(:page => #page, :per_page => #per_page)
if params[:id]
#blog = Blog[params[:id]]
else
#blog = Blog.new
3.times {#blog.news_images.build }
end
end
def allow_to
super :owner, :all => true
super :all, :only => [:index, :show]
end
end
My form currently is this:
<%
#locals
blog ||= #blog
%>
<div id="blog">
<% less_form_for [#profile, blog], :html => {:multipart => true} do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body %>
<% f.fields_for :news_images do |builder| %>
<%= builder.label :caption %>
<%= builder.text_field :caption %>
<%= builder.label :image %>
<%= builder.file_field :image %>
<% end %>
To include a youtube video use: [youtube: address_of_video]
<div class="row button">
<%= f.submit 'Save', :class=>'button' %>
</div>
<% end %>
</div>
I keep getting the following error:
ActionView::TemplateError (`#blog[news_images_attributes][0]' is not allowed as an instance variable name) on line #12 of app/views/blogs/_form.html.erb:
If I remove:
<%= builder.text_field :caption %>
the error goes away. In fact if i change the text field to a file field the error goes away.
I'm really confused here as I'm not sure why one form helper works fine and the other doesn't.
Thank you very much for looking =)
Update:
This is my less_form_builder.rb file:
class LessFormBuilder < ActionView::Helpers::FormBuilder
include ActionView::Helpers::ActiveRecordHelper
def method_missing *args
options = args.extract_options!
label = get_label '', options
front(label) + super(*args) + back(label)
end
def wrap method, options = {}
s = front(method, options)
s += yield if block_given?
s += back(method, options)
end
# Generates a label
#
# If +options+ includes :for,
# that is used as the :for of the label. Otherwise,
# "#{this form's object name}_#{method}" is used.
#
# If +options+ includes :label,
# that value is used for the text of the label. Otherwise,
# "#{method titleized}: " is used.
def label method, options = {}
text = options.delete(:label) || "#{method.to_s.titleize}: "
if options[:for]
"<label for='#{options.delete(:for)}'>#{text}</label>"
else
#need to use InstanceTag to build the correct ID for :for
ActionView::Helpers::InstanceTag.new(#object_name, method, self, #object).to_label_tag(text, options)
end
end
def select method, options = {}
front(method, options) + super + back(method, options)
end
def text_field method, options = {}
front(method, options) + super + back(method, options)
end
def password_field method, options = {}
front(method, options) + super + back(method, options)
end
def text_area method, options = {}
front(method, options) + super + back(method, options)
end
def check_box method, options = {}
front(method, options) + super + back(method, options)
end
def calendar_field method, options = {}
expired = options.delete(:expired) || false
if not expired; options.merge!(:class => 'calendar'); else; options.merge!(:disabled => true); end
text_field method, options
end
def front method = '', options = {}
"<div class='row clear'>#{label(method, options)}"
end
def back method = '', options = {}
"#{error_messages_on( object_name, method ) unless method.blank?}
<div class='clear'></div>
</div>"
end
end

Resources