In my app a user can upload a picture(with paperclip) or a link from youtube. The link is able to be submitted but now when I try to upload a picture I get a validation error saying the link is invalid. I have been going after this for like an hour now and I'm just going in circles at this point, any help would be awesome.
post.rb
class Post< ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
YT_LINK_FORMAT = /\A.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*\z/i
validates :link, allow_nil: true, format: YT_LINK_FORMAT
before_create :set_content_type
has_attached_file :pic, :styles => { :thumb => "600x600#", :medium => "300x300#", :small => "160x160#"}
validates_attachment_content_type :pic, :content_type => ["image/jpg", "image/jpeg", "image/png" ]
def set_content_type
self.is_pic = !self.pic_file_name.nil?
self.is_link = !self.link.nil?
# parse link
if self.is_link
uid = link.match(YT_LINK_FORMAT)
self.uid = uid[2] if uid && uid[2]
if self.uid.to_s.length != 11
self.errors.add(:link, 'is invalid.')
false
elsif Post.where(uid: self.uid).any?
self.errors.add(:link, 'is not unique.')
false
else
get_additional_info
end
end
end
Post_controller.rb
def create
#post= Post.create(post_params) do |post|
post.is_pic = true if params[:post][:pic]
post.is_link = true if params[:post][:link]
end
#post.user = current_user
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'post was successfully created.' }
format.json { render json: #post, status: :created, location: #post}
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
The form
<%= form_for #post, :html => { :multipart => true } do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="uploads">
<h3>Upload Photo</h3>
<div class="visible-xs">
<%= f.file_field :pic %>
<h3>YouTube Link</h3>
<div class="visible-xs">
<%= f.label :link %>
<%= f.text_field :link, required: false %>
</div>
<div class="center">
<%= f.submit :class => "btn btn-info" %>
</div>
</div>
<% end %>
Related
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])
I have a weird problem with "nested_form" in Rails. I made a model "evaluate" associated to other model "proyect", but when I try to show theres fields, on "proyects" form, just show fields from "proyects".
Here is my code:
Models:
proyect.erb
class Proyect < ActiveRecord::Base
belongs_to :user
has_many :vercions #I know is versions
has_many :evaluates #I know is evaluators
accepts_nested_attributes_for :evaluates, allow_destroy: true
validates :titulo,:presence => true,
:length => { :minimum => 3 }
validates :descripcion,:presence => true,
:length => { :minimum => 3 }
end
evaluate.erb
class Evaluate < ActiveRecord::Base
belongs_to :proyect
has_and_belongs_to_many :users
end
Controller
proyects_controller.erb
class ProyectsController < ApplicationController
before_action :set_proyect, only: [:show, :edit, :update, :destroy]
# GET /proyects
# GET /proyects.json
def index
if current_user.tipo == 'i'
#proyects = Proyect.where(:user_id => current_user.id)
else
#proyects = #Proyect.where(:id_user => current_user.id)
Proyect.all
end
end
# GET /proyects/1
# GET /proyects/1.json
def show
#vercion = Vercion.new
end
# GET /proyects/new
def new
#proyect = Proyect.new
#proyect.evaluates.build
end
# GET /proyects/1/edit
def edit
end
# POST /proyects
# POST /proyects.json
def create
#proyect = current_user.proyects.new(proyect_params)
respond_to do |format|
if #proyect.save
format.html { redirect_to #proyect, notice: 'Proyecto creado!.' }
format.json { render :show, status: :created, location: #proyect }
else
format.html { render :new }
format.json { render json: #proyect.errors, status: :unprocessable_entity }
end
# Llamamos al ActionMailer que creamos
Usermailer.bienvenido_email(current_user,#proyect).deliver
end
end
# PATCH/PUT /proyects/1
# PATCH/PUT /proyects/1.json
def update
respond_to do |format|
if #proyect.update(proyect_params)
format.html { redirect_to #proyect, notice: 'Proyect was successfully updated.' }
format.json { render :show, status: :ok, location: #proyect }
else
format.html { render :edit }
format.json { render json: #proyect.errors, status: :unprocessable_entity }
end
end
end
# DELETE /proyects/1
# DELETE /proyects/1.json
def destroy
#proyect.destroy
respond_to do |format|
format.html { redirect_to proyects_url, notice: 'Proyect was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_proyect
#proyect = Proyect.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def proyect_params
params.require(:proyect).permit(
:titulo, :descripcion,:evaluador, :id_user, :codigo, :user_assign,evaluates_attributes: [:id,:nombre, :prioridad, :_destroy, user_ids: [] ])
end
end
Views
_form.html.erb (Proyects)
<%= nested_form_for(#proyect) do |f| %>
<% if #proyect.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#proyect.errors.count, "error") %> prohibited this proyect from being saved:</h2>
<ul>
<% #proyect.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :titulo %><br>
<%= f.text_field :titulo %>
</div>
<div class="field">
<%= f.label :descripcion %><br>
<%= f.text_area :descripcion %>
</div>
<div class="field">
<%= f.hidden_field :id_user, :value => current_user.id %>
</div>
<!--Aqui añadi algo-->
<fieldset id="evaluates">
<%= f.fields_for :evaluates do |evaluates_form| %>
<div class="field">
<%= evaluates_form.label :status %><br>
<%= evaluates_form.text_field :status %>
</div>
<%= evaluates_form.link_to_remove "Eliminar esta tarea" %>
<% end %>
<p><%= f.link_to_add "Agregar una tarea", :evaluates %></p>
</fieldset>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
_evaluate_fields.html.erb
<div class="field">
<%= f.label :status, 'Nombre de la tarea' %><br>
<%= f.text_field :status %>
</div>
<div class="field">
<%= f.collection_check_boxes :user_ids, User.where(:tipo => 'e'), :id, :cedula %>
</div>
<%= f.link_to_remove "Eliminar Evaluador" %>
I have a form which allows a user to invite multiple people via adding emails in a comma separated list. In my "Participant" model, I have a call to validate the uniqueness of the email entered (scoped by "project_id"). In the model validation, it gives a place to explain the error (message), but I can't get that error to show up on my form if the validation fails.
If a user enters the email of a person that has already been added, how can I get the errors message to render?
participant.rb
class Participant < ActiveRecord::Base
validates :email, uniqueness: {case_sensitive: false, scope: :project_id, message: "Looks like you\'ve already added this person."}
end
participant_controller.rb
def new_participant
#new_participants = Participant.new
#participants = Participant.where(project_id: #project.id).includes(:user)
#template = Template.find(#project.template_id)
#address = Address.where(project_id: #project.id).first
#food = ProjectRestriction.where(project_id: #project.id)
end
def add_participant
#added_by = User.find(current_user.id)
#new_participants = params[:new_participants][:email].split(/,\s*/)
#new_participants.each do |t|
newpart = Participant.new(:email => t, :project_id => #project.id, :level => 4,
:participant_cat_id => 2, :last_updated_by => current_user.id, :added_by => current_user.id, :status => 'unseen')
respond_to do |format|
if newpart.save
ProjectMailer.notify_recipient(newpart, #project, #added_by, #participant_invite ).deliver_later
self.response_body = nil
redirect_to participants_path(p: #project.id, w: 'recipient')
else
format.html { redirect_to new_participant_path(p: #project.id)}
format.json { render json: #new_participants.errors, status: :unprocessable_entity }
end
end
end
end
form
<%= form_for :new_participants, url: add_participant_path( :p => #project.id), html: { :multipart => true, :class=> "form-horizontal", id: "basicForm" } do |f| %>
<% if #new_participants.errors.any? %>
<h2>OOPS!</h2>
<ul>
<% #new_participants.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul></div>
<% end %>
<div class="form-group ">
<label class="form-label dk-aqua"> Email: <span class="asterisk">*</span></label>
<%= f.text_field :email, :autofocus => true, :required => true, :maxlength => 55, :placeholder => 'Email(s)', :class => 'form-control' %>
</div>
<%= f.submit 'INVITE', :class => 'btn btn-aqua btn-lg btn-block',
:style => 'margin-bottom:-5px' %>
<% end %>
Your main issues are:
you are creating a respond block for each email in the request. 1 request = 1 response.
The objects in stored in memory in #new_participants are not actually saved.
In your views your are treating #new_participants as if it where a single resource.
Pay attention to pluralization when naming routes, variables and actions.
def add_participants
#added_by = User.find(current_user.id)
#new_participants = params[:new_participants][:email].split(/,\s*/)
#new_participants.map do |email|
newpart = Participant.new(
:email => email,
:project_id => #project.id,
:level => 4,
:participant_cat_id => 2,
:last_updated_by => current_user.id,
:added_by => current_user.id,
:status => 'unseen'
)
if newpart.save
ProjectMailer.notify_recipient(newpart, #project, #added_by, #participant_invite ).deliver_later
end
new_part
end
#invalid = #new_participants.reject(&:valid?)
if #invalid.any?
respond_to do |format|
format.html { redirect_to new_participant_path(p: #project.id)}
format.json { render json: #new_participants.map(&:errors), status: :unprocessable_entity }
end
else
respond_to do |format|
redirect_to participants_path(p: #project.id, w: 'recipient')
end
end
end
<ul>
<% #new_participants.each |p| %>
<% p.errors.messages.each do |msg| %>
<li><%= msg %></li>
<% end if p.errors.any? %>
<% end %>
</ul>
Not really any error messages, just no file uploaded!
Please help!!!!
everything get created and is fine apart from the file upload.
Models:
class Assets < ActiveRecord::Base
belongs_to :assetable, :polymorphic => true
delegate :url, :to => :attachment
attr_accessible :asset, :asset_file_name
end
class Video < ActiveRecord::Base
attr_accessible :body, :title, :url, :covers, :assets
has_many :covers, :as => :assetable, :class_name => "Video::Cover", :dependent => :destroy
accepts_nested_attributes_for :covers, :allow_destroy => true
class Video::Cover < Assets
has_attached_file :attachment, :styles => { :small => "300x0>", :large => "800x0>" }
end
end
video controller:
class VideosController < ApplicationController
#load_and_authorize_resource
# GET /videos
# GET /videos.xml
def index
#videos = Video.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #videos }
end
end
# GET /videos/1
# GET /videos/1.xml
def show
#video = Video.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #video }
end
end
# GET videos/new
# GET /videos/new.xml
def new
#video = Video.new
1.times do #video.covers.build end
#40.times do #video.images.build end
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #video }
end
end
# GET /collections/1/edit
def edit
#video = Video.find(params[:id])
1.times do #video.covers.build end
#1.times do #video.images.build end
end
# POST /videos
# POST /videos.xml
def create
#video = Video.new(params[:video])
respond_to do |format|
if #video.save
format.html { redirect_to(#video, :notice => 'Video was successfully created.') }
format.xml { render :xml => #video, :status => :created, :location => #video }
else
format.html { render :action => "new" }
format.xml { render :xml => #video.errors, :status => :unprocessable_entity }
end
end
end
# PUT /videos/1
# PUT /videos/1.xml
def update
#video = Video.find(params[:id])
respond_to do |format|
if #video.update_attributes(params[:video])
format.html { redirect_to(#video, :notice => 'Video was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #video.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /videos/1
# DELETE /videos/1.xml
def destroy
#video = Video.find(params[:id])
#video.destroy
respond_to do |format|
format.html { redirect_to(videos_url) }
format.xml { head :ok }
end
end
end
Views:
form
<div id="form_bk">
<div id="field_left">
<%= form_for #video, :html => {:multipart => true} do |f| %>
<% if #video.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#video.errors.count, "error") %> prohibited this video from being saved:</h2>
<ul>
<% #video.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div id="cover">
<br />
<h2>Cover Image</h2>
<%= f.fields_for :covers do |cover_image| %>
<% if cover_image.object.new_record? %>
<p><%= cover_image.file_field :attachment %></p>
<% end %>
<% end %>
<%= f.fields_for :covers do |cover_image| %>
<% unless cover_image.object.new_record? %>
<br />
<p>
<%=image_tag cover_image.object.url(:small) %><br />
<br /> Delete cover <%= cover_image.check_box :_destroy %><br /><br />
</p>
<% end %>
<% end %>
</div>
<div id="form_right">
<div class="field">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div></div>
<div class="field">
<%= f.label :url %><br />
<%= f.text_area :url %>
</div></div>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<br />
</div>
Index view
<% #videos.each do |video| %>
<div class="video">
<%- video.covers.each do |cover| %>
<div class="video_cover"><%=link_to image_tag (cover.url(:small)), video %></div>
<% end %>
<div class="video_title">
<%=link_to video.title, video %>
<%= video.body %>
<%= link_to 'Show', video %>
<%= link_to 'Edit', edit_video_path(video) %>
<%= link_to 'Destroy', video, :confirm => 'Are you sure?', :method => :delete %>
</div>
</div>
<% end %>
<br /><br /><br />
<%= link_to 'New Video', new_video_path %>
<%= debug #videos %>
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.