This is quite a common error and I have went through many answers but nothing worked for me. Can you please help, where I am going wrong?
Scenario: I have an item and image table and when user adds an item, he/she must add at least one image. When I save the form after attaching an image it gives an error. The code snippets and error screenshot are attached below:
item.rb
class Item < ApplicationRecord
belongs_to :user, class_name: 'User', foreign_key: :user_id
has_many :images, class_name: 'Image', foreign_key: :item_id, dependent: :destroy
accepts_nested_attributes_for :images, allow_destroy: true
end
image.rb
class Image < ApplicationRecord
belongs_to :item, foreign_key: :item_id, optional: true
has_attached_file :image, styles: { small: '64x64', med: '100x100', large: '200x200' },
default_url: '/images/:id/:filename'
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end
items_controller.rb
class ItemsController < ApplicationController
def new
#item = Item.new
#item.images.build
#new.html.erb
end
def create
#item = Item.new(item_params.merge(user_id: current_user.id))
if #item.save
redirect_to items_path
else
render :new
end
end
private
def item_params
params.require(:item).permit(:name, :category, :qty, :cost, :description,
:city, :postal_code, :country,
images_attributes: [:id, :item_id, :_destroy, image: []])
end
end
new.html.erb
<div class="container">
<h2> <% if current_user.items.blank? %> Become a seller! <% end %> Add a new item </h2> <br>
<%= form_for #item, url: {action: :create}, html: { multipart: true } do |f| %>
<%= item_error_messages! %>
<div class="form-group">
<%= f.label :name, class:'control-label col-sm-2' %>
<div class="col-sm-10">
<%= f.text_field :name, class: 'form-control', placeholder: 'Enter name' %>
</div>
</div>
<%= f.fields_for :images, #item.images.build do |img| %>
<%= img.file_field :image, multiple: true %>
<% end%>
<br><br>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10" style="margin-bottom: 40px;">
<%= f.submit 'Save', class:'btn btn-default' %>
</div>
</div>
<% end %>
</div>
Error:
What could be the possible issue? Most of the solutions I've read suggest adding multipart: true in form tag but it is already there.
Thanks
I think you problem is related with the fact that you are trying to save more than one attached file per model. Apparently, Paperclip don't treat this case very well, so you need to do it by your own hand.
If you want to save multiples files at the same time, you can follow the accept answer in the link below that example how to achieve that:
Just a resume from the link below:
1 - To save multiple files in the above example you, do not need add
multiple: true option, it will cause an error when saving.
2 - About params: This will cause an error because the model does not know what to do with an array of images
3 - To save more than one file at the same time, you need to use your own
handler
Rails 4 multiple file attachments with Paperclip
Good luck!
#UPDATE
Ideas about to how save multiples file at once:
1 - You will need to have a form with a dynamically input for files.
So each input can get the entry for each file. You can achieve that
writing your own .js lib or using a gem like "Cocoon". You will be
using nested attributes here.
2 - The strong parameter in your controller will be accepting you Item
model and an array of files.
3 - You will have to edit your method to save your data. E.g (in your
case #item.save won't work because paperclips it's not design to
accept an array of files). So, in your Item model you will have to
write a method similar to the below:
(pseudo-code)
def save(item_attributes, array_of_files)
#item = Item.new( -- add here only Item attributes --)
#item.save
# Here you are creating a model file for each file you are saving.
# So there will be N file model for 1 item.
for file in array_of_files
#file = File.new( #item.id, file)
#file.save
end
# here you can implement transaction in case a error occurs.
# and shows the error to your client through Item model
# google how to do this (transaction and Active Record class).
end
Related
Error Overview
There is a Github URL of a simple app that reproduces the problem in the bottom paragraph.
I'm creating an application that allows article submission. To make it easier to submit articles, I introduced Rails Action text. I also decided to add a tagging feature, so I have a tags table, an article table, and a user table in the database. The article form looks like the following image.
The article form
I was able to submit an article, but I wanted to check the validation of the condition that the article could not be submitted with a blank field, so I submitted it with a blank field, but I got the following error.
NoMethodError
I don't know how to solve this problem and I need your help.
The relevant source code
This is the view file of the corresponding section.↓
<%= render "shared/header" %>
<%= form_with model: #article, url: articles_path, class:'form-wrap', local: true do |f| %>
<%= render 'shared/error_messages', model: f.object %>
<div class='article-form'>
<div class="title-field">
<%= f.label :title, "題名" %>
<%= f.text_area :title, class:"input-title" %>
</div>
<div class="tag-field", id='tag-field'>
<%= f.label :name, "タグ" %>
<%= f.text_field :name, class:"input-tag" %>
</div>
<div class="content-field">
<%= f.label :content, "記事本文" %>
<%= f.rich_text_area :content %>
</div>
<div id="search-result">
</div>
</div>
<div class="submit-post">
<%= f.submit "Send", class: "submit-btn" %>
</div>
<% end %>
This is the controller code.↓
class ArticlesController < ApplicationController
before_action :authenticate_user!, only: [:new, :create]
def index
#article = Article.all.order(created_at: :desc)
end
def new
#article = ArticlesTag.new
end
def create
#article = ArticlesTag.new(article_params)
if #article.valid?
#article.save
return redirect_to root_path
else
render :new
end
end
def search
return nil if params[:keyword] == ""
tag = Tag.where(['name LIKE ?', "%#{params[:keyword]}%"] )
render json:{ keyword: tag }
end
private
def article_params
params.require(:articles_tag).permit(:title, :content, :name).merge(user_id: current_user.id)
end
end
This is the code of the Article model.↓
class Article < ApplicationRecord
has_rich_text :content
belongs_to :user
has_one_attached :image
has_many :article_tags
has_many :tags, through: :article_tag_relations
end
This is the code of The Tag model. ↓
class Tag < ApplicationRecord
has_many :article_tag_relations
has_many :articles, through: :article_tag_relations
validates :name, uniqueness: true
end
This is the intermediate model between The Tag model and The Article model.↓
class ArticleTagRelation < ApplicationRecord
belongs_to :article
belongs_to :tag
end
This is the Form object class that collects the tags and articles tables.
class ArticlesTag
include ActiveModel::Model
attr_accessor :title, :name, :content, :user_id
with_options presence: true do
validates :title
validates :name
validates :content
validates :user_id
end
def save
article = Article.create(title: title, content: content, user_id: user_id)
tag = Tag.where(name: name).first_or_initialize
tag.save
ArticleTagRelation.create(article_id: article.id, tag_id: tag.id)
end
end
Database Status
Action text table
Article Tag Relation table
Article table
Tag table
Please help me.
A simple application that reproduces the error.
github URL
A simple app that reproduce the error
This is the error you are getting
undefined method `body' for "":String
That says that it is trying to call the method body on an empty string.
Why is it trying to call that method? Because you wrote this:
<%= f.rich_text_area :content %>
So the form helper is expecting that content contains an instance of a RichText (https://api.rubyonrails.org/classes/ActionText/RichText.html)
However, content actually just contains an instance of String, because your ArticlesTag model does not declare that it has_rich_text (like your Articles Model does)
I note that your ArticlesTag model is not persisted. I am not sure how to use rich text with a model that is not persisted - I suspect it might not be possible.
I would like to make my app upload multiple files with Shrine, but one doc suggests two file_fields whereas the other suggests only one. After posting a question to their discourse forum, it was suggested that I hide the one named files[]. Whether I do this or not, the first file_field always fails to render. Why does this field not display?
<%= form_for #item, html: { enctype: "multipart/form-data" } do |f| %>
<%= f.fields_for :photos do |i| %>
<%= i.label :image %>
<%= i.hidden_field :image, value: i.object.cached_photos_data, class: "upload-data" %>
<%= i.file_field :image, class: "upload-file" %> /// why is this not rendering?😢
<% end %>
<%= file_field_tag "files[]", multiple: true %> // what purpose does this one serve?
<%= f.text_field :title %>
<%= f.submit "Submit" %>
<% end %>
Models:
class Item < ApplicationRecord
has_many :photos, as: :imageable, dependent: :destroy
end
class Photo < ApplicationRecord
include ImagesUploader::Attachment(:image)
belongs_to :imageable, polymorphic: true
validates_presence_of :image
end
Controller:
class ItemsController < ApplicationController
def new
#item = current_user.items.new
end
def create
#item = current_user.items.create(item_params)
#item.save
end
private
def item_params
params.require(:item).permit(:title, photos_attributes: { image: [] })
end
end
Read the first link carefully: It says that the single field (i.file_field :image) is used to display existing images (which is why it's wrapped in f.fields_for :photos in the example) and the multiple field (file_field_tag "files[]", multiple: true) is used to upload new files. So if your #item doesn't have an :image, then the field isn't shown.
Let me know if this needs any further clarification – happy to help!
I know there are alot of these kinds of posts on SO, and I think Ive read and tried each of them, all without success.
I have Post and Image models that I need to work together with a many to one relationship.
class Post < ActiveRecord::Base
has_many :images
end
class Image < ActiveRecord::Base
belongs_to :post
mount_uploader :file, images_uploader
end
Here is the post_parms declaration in my posts controller, which includes all of the fields in my image model migration.
private
def post_params
params.require(:post).permit(:title, :content, image_attributes: [:id, :post_id, :file])
end
and here is my post creation form where, I hope to allow multiple image asset creation with each post.
<%= form_for #post, html: {class: "pure-form pure-form-stacked"} do |post| %>
<%= post.fields_for :image, :html => { :multipart => true } do |image| %>
<%= image.label :file, "Upload Image:" %>
<%= image.file_field :file, multiple: true %>
<% end %>
<fieldset class="post-form">
<%= post.label :title %>
<%= post.text_field :title %>
<%= post.label :content %>
<%= post.text_area :content, :class => "redactor", :rows => 40, :cols => 120 %>
</fieldset>
<div class = "button-box">
<%= post.submit class: "pure-button pure-button-primary" %>
<%= link_to "Cancel", posts_path, :class => "pure-button" %>
</div>
Despite repeated effort and reading every post I can find on this topic, I'm still getting:
Unpermitted parameters: image
The trouble here is that this error provides no clue where to start looking for the problem. Since Im not really sure where to look next I thought I would post it here looking for more professional opinions.
Update the Post model as below:
class Post < ActiveRecord::Base
has_many :images
accepts_nested_attributes_for :images ## Add this
end
This way upon form submission you would receive the image attributes in key images_attributes and not image which you are currently receiving which is causing the warning as Unpermitted parameters: image
As you have 1-M relationship between Post and Image
You need to update post_params as below:
def post_params
params.require(:post).permit(:title, :content, images_attributes: [:id, :post_id, :file])
end
Use images_attributes (Notice plural images) and NOT image_attributes (Notice singular image)
And change fields_for in your view as
<%= post.fields_for :images, :html => { :multipart => true } do |image| %>
Use images (Notice plural) and NOT image (Notice singular)
UPDATE
To resolve uninitialized constant Post::Image error
Update Image model as below:
class Image < ActiveRecord::Base
belongs_to :post
## Updated mount_uploader
mount_uploader :file, ImagesUploader, :mount_on => :file
end
Also, suggested to remove multiple: :true from
<%= ff.file_field :file, multiple: true %>
I am using Rails 4.
In my project, include nested form for has_many relationship. From UI point of view, I got it. But nested form values are not inserting into database.
class Newspaper < ActiveRecord::Base
has_to :newspaper_categories, :dependent_destroy => true
accepts_nested_attributes_for :newspaper_categories, :allow_destroy => true, :reject_if => :all_blank
end
class NewspaperCategory < ActiveRecord::Base
belongs_to :newspaper
end
Newspaper form contents like,
<%= nested_form_for(#newspaper) do |f| %>
# Newspaper form fields
# Include `Newspaper category` form from the file.
<%= f.fields_for :newspaper_categories do |nc|%>
<%= render "newspaper_category" %>
<% end %>
# For add new form using JS
<%= f.link_to_add "Add New", :newspaper_categories %>
<%= f.submit %>
<% end %>
In my Newspaper Controller,
# add build in new method,
def new
#newspaper = Newspaper.new
#newspaper.newspaper_categoried.build
end
# In params set task_attributes,
def newspaper_params
params.require(:newspaper).permit(:name, :logo, task_attributes[:cat_link, :_destroy])
end
Where I goes wrong, still i'm confusing to insert
Update this
params.require(:newspaper).permit(:name, :logo, {newspaper_categories_attributes: [ :_destroy, :category_id, :rss_link, :image_url]})
This is actually a two part question
For the record - I am using Simple_form, Carrierwave and awesome_nested_fields gems.
In my app I have events, each event has a speaker, and each speaker has a picture. Pictures are not a separate table, they're stored under 'speakers'
event.rb
class Event < ActiveRecord::Base
belongs_to :type
...
has_many :speakers
accepts_nested_attributes_for :speakers, allow_destroy: true
...
speaker.rb
class Speaker < ActiveRecord::Base
belongs_to :event
mount_uploader :photo, PhotoUploader
end
strong parameters (events controller):
private
def event_params
params.require(:event).permit(:title, :description, :type_id, :price, :program,
:start_date, :end_date, :image, category_ids: [],
speakers_attributes: [ :id, :name, :photo, :status, :description, :url, '_destroy'])
end
The photos are uploaded and replaced no problem, however when it comes to editing, troubles begin:
edit form:
<%= simple_form_for #event, html: {multipart: true} do |f| %>
<%= f.other_stuff %>
<%= f.nested_fields_for :speakers do |f| %>
#Problem 1 - deleting uploaded images
<%= f.check_box :remove_avatar %> # DOES NOT WORK
<%= f.check_box :_destroy %> # DOES NOT WORK
Problem 2 - showing an uploaded image
<%= image_tag(#event.speaker.photo_url) if #event.speaker.photo? %> # Error - undefined method `photo?'
<% end %>
<% end %>
I am pretty sure the first problem is connected to strong parameters, and I have tried many variations, but so far I couldn't figure out the correct ones (:photo_remove, [photos_attributes['_destroy']], etc).
The second problem with displaying uploaded images can be solved by inserting
<%= image_tag #event.speakers[0].photo %>
in my code, however if there are several speakers, I need to change the array integer, and I cant seem to figure out how to do that (tried writing a helper method, but nothing good so far).
Any help would be appreciated, thank you