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])
Related
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 %>
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 :)
I've read through lots of posts here and still cant figure this one out.
I have a forum_post model and a links model. I want to nest the links form with the forum_post form but keep getting a Can't mass-assign protected attributes: links.
ForumPost Model
class ForumPost < ActiveRecord::Base
attr_accessible :content, :links_attributes
has_many :links, :as => :linkable, :dependent => :destroy
accepts_nested_attributes_for :links, :allow_destroy => true
end
Links Model
class Link < ActiveRecord::Base
attr_accessible :description, :image_url, :link_url, :linkable_id, :linkable_type, :title
belongs_to :linkable, :polymorphic => true
end
Forum_post View
<%= form_for(#forum_post) do |f| %>
<% if #forum_post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#forum_post.errors.count, "error") %> prohibited this forum_post from being saved:</h2>
<ul>
<% #forum_post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content, :rows => 5 %>
</div>
<%= f.fields_for :link do |link| %>
<%= render :partial => 'links/link', :locals => { :f => link} %>
<% end%>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Link View Partial
<div class="field">
<%= f.label :link_url %><br />
<%= f.text_field :link_url, :id => "url_field" %>
</div>
<div id="link_preview">
</div>
ForumPosts Controller
class ForumPostsController < ApplicationController
def new
#forum_post = ForumPost.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #forum_post }
end
def create
#forum_post = ForumPost.new(params[:forum_post])
respond_to do |format|
if #forum_post.save
format.html { redirect_to #forum_post, notice: 'Forum post was successfully created.' }
format.json { render json: #forum_post, status: :created, location: #forum_post }
else
format.html { render action: "new" }
format.json { render json: #forum_post.errors, status: :unprocessable_entity }
end
end
end
Links Controller
class LinksController < ApplicationController
def find_linkable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
def index
#linkable = find_linkable
#links = #linkable.links
end
def create
#linkable = find_linkable
#link = #linkable.links.build(params[:link])
if #link.save
flash[:notice] = "Successfully saved link."
redirect_to :id => nil
else
render :action => 'new'
end
end
end
Well, according to your question the protected attributes that you can't mass-assign is :links.
Not sure how that happened, but have you tried attr_accessible :links?
As for the security implications, it is the reason github got hacked once https://gist.github.com/1978249, and I would highly discourage setting whitelist_attributes to false.
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.
I'm new to RoR and having an issue when trying to save from multiple dropdowns. I have three objects - books, genres, and authors. A book object has a genre and author associated to it, but the issue is I can only manage to save either a genre or author to my book object, and not both. Here's where I'm at:
class Author < ActiveRecord::Base
validates :name, :presence => true
validates :biography, :presence => true
has_many :books
end
class Genre < ActiveRecord::Base
validates :description, :presence => true
has_many :books
end
class Book < ActiveRecord::Base
belongs_to :genre
belongs_to :author
has_many :cartitems
validates :name, :presence => true
validates :price, :presence => true
validates :description, :presence => true
end
Controller:
def create
##book = Book.new(params[:book])
#author = Author.find(params[:author].values[0])
#genre = Genre.find(params[:genre].values[0])
#book = #author.books.create(params[:book])
#one or the other saves, but not both
##book = #genre.books.create(params[:book])
respond_to do |format|
if #book.save
format.html { redirect_to(#book, :notice => 'Book was successfully created.') }
format.xml { render :xml => #book, :status => :created, :location => #book }
else
format.html { render :action => "new" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
end
Not sure if this will help out or not, but here's what the dropdowns look like in the View:
<div class="field">
<%= f.label :genre %><br />
<%= #items = Genre.find(:all)
select("genre", "description", #items.map {|u| [u.description,u.id]}, {:include_blank => true})%>
Appreciate any help with this.
EDIT - Here's my full form.
<%= form_for(#book) do |f| %>
<% if #book.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#book.errors.count, "error") %> prohibited this book from being saved:</h2>
<ul>
<% #book.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :price %><br />
<%= f.text_field :price %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :genre %><br />
<%= #items = Genre.find(:all)
select("genre", "description", #items.map {|u| [u.description,u.id]}, {:include_blank => true})%>
</div>
<div class="field">
<%= f.label :author %><br />
<%=#items = Author.find(:all)
select("author", "name", #items.map {|u| [u.name,u.id]}, {:include_blank => true}) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Update your select fields to be defined like this:
<div class="field">
<%= f.label :genre %><br />
<%= f.select( :genre_id, Genre.all.map {|u| [u.description,u.id]}, {:include_blank => true}) %>
</div>
<div class="field">
<%= f.label :author %><br />
<%= f.select( :author_id, Author.all.map {|u| [u.name,u.id]}, {:include_blank => true}) %>
</div>
And your controller action should be like this:
def create
#book = Book.new(params[:book])
respond_to do |format|
if #book.save
format.html { redirect_to(#book, :notice => 'Book was successfully created.') }
format.xml { render :xml => #book, :status => :created, :location => #book }
else
format.html { render :action => "new" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
Also, remove the format.xml calls if you don't need them, they're just cluttering your controller action.
There are lots of different ways to fix your problem, it would help to see exactly what's in your params hash and what your full form looks like, but no matter. Here is one way:
#book = #author.books.create(:genre => #genre)
Here is another (essentially the same thing):
#book = #author.books.create {|book| book.genre = #genre}
You could also instantiate the book separately:
#author = Author.find(params[:author].values[0])
#genre = Genre.find(params[:genre].values[0])
#book = Book.create(:author => #author, :genre => #genre)
My guess is you didn't quite build your form correctly, otherwise your params hash would look similar to this {:book => {:author => 1, :genre => 5}} and you would be able to do this:
#book = Book.create(params[:book])
And you would not look up the author using params[:author], but would instead do params[:book][:author] if you needed to do it at all.