carrierwave whitelist error isn't displayed - ruby-on-rails

in my Rails app i've got the carrierwave gem to upload stuff. Now I want a validation of fileformats
so I've added this in uploader:
def extension_white_list
%w(jpg jpeg gif png)
end
When I try to upload a pdf it dosn't upload the pdf but no error is printed to screen. What is missing?
I think the page should go back so the user has the oportunity to select a different file ?
Thanks
UPDATE - Form View Code:
<%= form_for(#channel, :html => {:multipart => true, :class => "form-horizontal", :role => "form"}, :method => :post, :url => url_for(controller: 'channels', action: 'edit', id: #channel.id)) do |f| %>
<div class="col-md-4">
<div class="form-group col-md-12">
<label><%= f.label :channelimage %></label>
<%= f.file_field :channelimage, :class => "form-control", :placeholder => :image%>
<br>
<% if #channel.channelimage.present? %>
<div clasS="thumbnail">
<img src="<%= #channel.channelimage %>" alt="<%= #channel.channelname %>"/>
</div>
<% end %>
</div>
</div>
UPDATE: Controller function
#Speichert die geƤnderten Werte eines Channels
def edit
#user = User.find_by_id session[:user_id]
#knowledgeproviderList = #user.knowledgeprovider
#channel = Channel.find params[:id]
#channelList = Channel.where(knowledgeprovider_id: #knowledgeproviderList.pluck(:id))
if request.post?
#channel.update_attributes(channel_edit_params)
if #channel.save
flash[:notice] = t("flash.saved")
redirect_to action: :index
else
redirect_to action: :edit, :id => #channel.id
end
end
end

Validation - Guides
So essentially you're not outputting errors, so using the format from the guides you need to add:
<% if #channel.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#channel.errors.count, "error") %> prohibited
this channel from being saved:
</h2>
<ul>
<% #channel.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

Related

form_with produces first record as nil

comment controller
class CommentsController < ApplicationController
before_action :load_commentable
before_action :checked_logged_in, only: [ :create]
def new
#comment = #commentabl.comments.new
end
def create
#comment = #commentable.comments.new(comment_params)
#comment.user_id = current_user.id
#comment.commenter = current_user.username
if #comment.blank? || #comment.save
flash[:success] = "Commented was created"
ActionCable.server.broadcast 'comment_channel',
commenter: current_user.username,
comment: #comment.content
redirect_to #commentable
else
flash[:danger] = render_to_string(:partial => 'shared/error_form_messaging',
:locals => {obj: #comment},
format: :html)
redirect_to #commentable
end
end
private
def comment_params
params.require(:comment).permit(:content, :commenter, :user_id)
end
def load_commentable
resource, id = request.path.split('/')[1,2]
#commentable = resource.singularize.classify.constantize.find(id)
end
def checked_logged_in
unless logged_in?
flash[:danger] = 'please log in to be able to comment'
redirect_to login_path
end
end
end
my form for creating a comment:
<%= form_with model:[commentable, commentable.comments.new], :html => {class: "form-horizontal", role:"form"} , local: true do |form| %>
<div class="form-group">
<div class="control-label col-sm-2">
<%= form.label :content, 'Comment' %>
</div>
<div class="col-sm-8">
<%= form.text_field :content , class: 'form-control', placeholder: "enter your comment here", autofocus: true %>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<%= form.submit 'Comment' , class: ' btn btn-primary' %>
</div>
</div>
<% end %>
the form is called in show.html.erb
<h2 class="text-center">
Title: <%= #article.title %>
</h2>
<div class="well col-xs-8 col-xs-offset-2">
<div id="user-info-showpage" align="center">
Created by: <%= render 'shared/user-info', obj: #article.user %>
</div>
<h4 class="text-center">
<strong>Description:</strong>
</h4>
<hr />
<%= simple_format(#article.description) %>
<% if #article.categories.any? %>
<p>Categories: <%= render #article.categories %></p>
<% end %>
<div class="article-actions">
<% if logged_in? && (current_user == #article.user || current_user.admin?) %>
<%= link_to "Delete", article_path(#article), method: :delete,
data: {confirm: "Are you sure you want to delete the article?"},
class: 'btn btn-xs btn-danger' %>
<%= link_to "Edit", edit_article_path(#article), class: 'btn btn-xs btn-success'%>
<%end%>
<%= link_to "View All Articles", articles_path , class: 'btn btn-xs btn-primary'%>
</div>
</div>
<% if logged_in? %>
<div class="col-xs-8 col-xs-offset-2">
<%#= render partial: 'comments/form', :locals => {commentable: #article} %>
</div>
<%end%>
<div class="col-xs-8 col-xs-offset-2">
<div id="comments"></div>
<%= #article.comments.inspect %>
<% #article.comments.each do |c| %>
<div class="well">
<%= c.content %> by
<%= c.commenter %>
</div>
<%end%>
<div id="comments"></div>
</div>
my result is in view is
Please if more info needed, ask me so I can provide
Note: I am not sure this empty record is owing to commentable.comments to be nil or I miss something
I commented render form in show page and now the empty record is gone, so my issue must be related to form_with
From my understanding, you
Expect:
in your articles#show page to not show the empty by _________ <div> HTML because the comment is still built (still in-memory), and not yet saved (not yet in DB).
Solution 1:
app/views/articles/show.html.erb
...
<div class="col-xs-8 col-xs-offset-2">
<div id="comments"></div>
<% #article.comments.each do |c| %>
<!-- ADD THIS LINE -->
<% if c.persisted? %>
<div class="well">
<%= c.content %> by
<%= c.commenter %>
</div>
<% end %>
<%end%>
<div id="comments"></div>
</div>
...
Solution 2 (better but still is a workaround):
app/views/comments/_form.html.erb
<%= form_with model:[commentable, Comment.new(commentable: commentable)], :html => {class: "form-horizontal", role:"form"} , local: true do |form| %>
Explanation:
The reason the page is displaying an empty by _________ <div> is that because you "built" a new comment before .each is called. Because they are sharing same memory space, the build basically also adds it to the array in-memory. See the following:
# rails console
article = Article.create!
comment1 = Comment.create!(commentable: article)
# from here, comment1 is then saved already in the DB
# now let's see what happens when you use "build" or "new"
# They have differences, it seem: for details: https://stackoverflow.com/questions/1253426/what-is-the-difference-between-build-and-new-on-rails/1253462
# redefine (to simulate your #article = Article.find(params[:id])
article = Article.find(article.id)
comment2 = article.comments.build
puts article.comments.count
# SQL: Select count(*) FROM ...
# => 1
puts article.comments.size
# => 2
# notice how `count` and `size` are different. `count` value is "DB-based" while `size` is "memory-based". This is because `count` is an `ActiveRecord` method while `size` is a delegated `Array` method.
# now let's simulate your actual problem in the view, where you were looping...
article.comments.each do |comment|
puts comment
end
# => <Comment id: 1>
# => <Comment id: nil>
# notice that you got 2 comments:
# one is that which is already persisted in DB
# and the other is the "built" one
# the behaviour above is to be expected because `.each` is a delegated `Array` method
# which is agnostic to where its items come from (DB or not)
This is the reason why in your page, the "built" comment is shown in the page because you are calling
<%= render partial: 'comments/form', :locals => {commentable: #article} %>
... which calls commentable.comments.build
BEFORE the <% "article.comments.each do |c| %>
If this is not clear enough yet, try putting
<%= render partial: 'comments/form', :locals => {commentable: #article} %>
... which calls commentable.comments.build
AFTER the <% "article.comments.each do |c| %> ... <% end %>
... and the by _________ <div> should already not show up.

Rails: Two different NoMethodError's when trying to display files

I'm making a basic application and I made it so a user can attach a file to a form post. That all works perfectly fine, but now I'm trying to display a link to the file and it doesn't seem to work.
I'm getting two errors. One if I attach a file and another if I don't attach a file. They both say undefined method 'doc=' for nil:NilClass but are on different lines of code.
If I don't upload a file this is what I get: NoMethodError in Projects#index on this line of code <% if #project.doc %>.
If I do upload a file this is what I get: NoMethodError in ProjectsController#create on this line of code #project.doc = uploaded_io.original_filename
projects_controller.rb
class ProjectsController < ApplicationController
def index
#projects = Project.all
end
def show
end
def new
#projects = Project.new
end
def create #no view
#projects = Project.new(project_params)
uploaded_io = params[:doc]
if uploaded_io.present?
File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'wb') do |file|
file.write(uploaded_io.read)
#project.doc = uploaded_io.original_filename
end
end
if #projects.save
redirect_to projects_path, :notice => "Your project was sent!"
else
render "new"
end
end
def edit
#projects = Project.find(params[:id])
end
def update #no view
#projects = Project.find(params[:id])
if #projects.update_attributes(project_params)
redirect_to projects_path, :notice => "Your project has been updated."
else
render "edit"
end
end
def destroy #no view
#projects = Project.find(params[:id])
#projects.destroy
redirect_to projects_path, :notice => "Your project has been deleted."
end
private
def project_params
params.require(:project).permit(:title, :description)
end
end
index.html.erb
<div class="container">
<div class="page-header">
<h1>Projects<small> Here are all of your projects.</small></h1>
</div>
</div>
<% #projects.each do |project| %>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<%= project.title %>
</div>
</div>
<div class="panel-body">
<p>
<%= project.description %>
</p>
<br>
<%= link_to "Discuss", new_project_discussion_path(project) %> |
<%= link_to "Tasks", new_project_task_path(project) %> |
<%= link_to "Edit", edit_project_path(project) %> |
<%= link_to "Delete", project, :method => :delete %>
<% if #project.doc %>
<p>Document: <%= link_to #project.doc, "/uploads/#{#project.doc}", :target => "_blank" %></p>
<% end %>
</div>
</div>
<%end%>
<br>
<br>
<div class="container">
<p><a class="btn btn-primary btn-lg" href="/projects/new" role="button">Create project</a></p>
</div>
_form.html.erb
<%= form_for(#projects, :html => { :multipart => true}) do |f| %>
<% if #projects.errors.any? %>
<ul>
<% #projects.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
<div class="container">
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, class: "form-control" %>
</div>
<%= label_tag :doc, 'Files (optional)' %>
<%= file_field_tag :doc %>
<br>
<div class="form-group">
<%= f.submit "Submit Project", class: "btn btn-primary" %>
</div>
<% end %>
Updated :
You have many errors, here are a few that I found :
uploaded_io = params[:doc]
Should be
uploaded_io = params[:project][:doc]
Also delete this line
#project.doc = uploaded_io.original_filename
You don't need that.
Finally, in your views, you should have project.doc instead of #project.doc

File upload in Ruby doesn't work when rendering it to another form

I am new to ruby and I would appreciate any kind of help. I have created a file uploader in ruby. When I test it separately, it works perfectly fine! But when I render it into another form, It just doesn't work! Here is my code:
upload/_index.html.erb
<h4>Upload File </h4>
<%= form_tag({:controller => 'upload', :action => 'upload_image'}, :multipart => true, remote: true) do %>
<p><label for="upload_file">Select file..</label>
<%= file_field 'upload', 'datafile' %></p>
<%= submit_tag "Upload", :class => "btn btn-default btn-lg active", :method => 'post' %>
<% end %>
data_file.rb
class DataFile < ActiveRecord::Base
attr_accessor :upload
belongs_to :event
def self.save_file(upload)
file_name = upload['datafile'].original_filename if (upload['datafile'] !='')
file = upload['datafile'].read
file_type = file_name.split('.').last
new_name_file = Time.now.to_i
name_folder = new_name_file
new_file_name_with_type = "#{new_name_file}." + file_type
directory = 'public/data'
Dir.mkdir(directory + "#{name_folder}");
File.open(directory + "#{name_folder}/" + new_file_name_with_type, "wb") do |f|
f.write(file)
end
end
end
upload_controller.rb
class UploadController < ApplicationController
before_filter :authenticate_user!
before_filter do
redirect_to :root unless current_user && current_user.isAdmin?
end
def index
# #users = User.find(params[:id])
redirect_to new_event_path
end
def upload_image
DataFile.save_file(params[:upload])
#redirect_to new_event_path
end
end
I have rendered upload/index into events/new.html.erb
<div style="margin-left: 360px;"><h1>New event</h1></div>
<br/>
<br/>
<div style="margin-left: 360px;">
<%= form_for(:event, :url => {:controller => 'events', :action => 'new'}, html: { method: :post }) do |f| %>
<% if #event.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#event.errors.count, "error") %> prohibited this event from being saved:</h2>
<ul>
<% #event.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :event_Day %><br>
<select name="event_day_id">
<option value="0">-Choose agenda item-</option>
<% for agenda_item in #agenda_items %>
<option value="<%= agenda_item.id %>"><%= agenda_item.name %></option>
<% end %>
</select>
</div>
<%= link_to 'Add new agenda item', new_agenda_item_path %>
<br/>
<br/>
<div class="field">
**<%= render :partial => 'upload/index' %>**
</div>
<br/>
<div class="field">
<div class="field">
<%= f.label :Survey %><br>
<select name="survey_id">
<option value="0">-Choose survey-</option>
<% for survey in #surveys %>
<option value="<%= survey.id %>"><%= survey.title %></option>
<% end %>
</select>
</div>
<%= link_to 'Create new survey', new_survey_path %>
</div>
<div class="actions">
<%= f.submit :class => "btn btn-default btn-lg active", :method => 'post' %>
</div>
<% end %>
</div>
<%= button_to 'Back', events_path, :class => 'btn btn-primary btn-lg active', :method => 'get' %>
Thanks!
Sorry I just noticed that the question was incomplete. I have answered the question though. When rendering the upload file form into another form, it does not work. So I removed it from the form and put it on top and everything is working fine.
Unless there is a way to nest once form inside the other?
Thanks!

How do I re-populate form fields when validation fails?

This is the erb template:
<div id='recipe-form'>
<% if #recipe.errors %>
<div id='errors'>
<% #recipe.errors.messages.each do |field, messages| %>
<div class='error'>
<div class=field'><%= field %></div>
<div class='messages'>
<ul>
<% messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
</div>
<% end %>
<%= form_for #recipe, :html => {:multipart => true}, :url => '/recipes' do |f| %>
<%= f.label :title, 'title' %>
<%= f.text_field :title %>
<div id="photo-upload">
<%= file_field :photo0, :image, :id => 0 %>
</div>
<div id='existing-photos'>
<% recipe.photos.each do |photo| %>
<div id='<%= photo.id %>'>
<img src='<%= photo.image.url(:thumb) %>' />
<ul>
<li>
<%= link_to 'delete',
recipe_photo_url(
:recipe_id => #recipe.slug,
:id => photo.id
),
:method => :delete,
:remote => true
%>
</li>
</ul>
</div>
<% end %>
</div>
<%= f.label :body, 'body' %>
<%= f.cktext_area :body, :ckeditor => {:width => "500"} %>
<%= f.label :tags, 'tags (comma separated)' %>
<%= text_field_tag :tags %>
<%= submit_tag 'submit' %>
<% end %>
</div>
This is the create action:
def create
#recipe = Recipe.new(params[:recipe])
photo_keys = params.keys.select{|k|k.match(/^photo/)}
#photos = []
photo_keys.each do |photo_key|
#photos << Photo.new(params[photo_key])
end
#recipe.tags = Tag.parse(params[:tags])
#recipe.author = current_user
if #recipe.save &&
#photos.all?{|photo|photo.save}
#photos.each do |photo|
photo.recipe_id = #recipe.id
photo.save
end
flash[:notice] = 'Recipe was successfully created.'
redirect_to recipe_url(#recipe.slug)
else
flash[:error] = 'Could not create recipe. '
flash[:error] += 'Please correct any mistakes below.'
render :action => :new
end
end
And this is the new action:
def new
#recipe = Recipe.new
end
I read that if I use form_for as I am using above, the fields will be re-populated automatically.
When I inspect #recipe.errors from within the erb template, I can see that the errors generated by create are also available when the new action is rendered, but the fields do not re-populate.
I'm actually not sure about what render action: does but what I do and works is: Instead of rendering the action just render the template using render :new.
You need to set the same instance variables (those with #), which you already in your create action.

In which controller should I place elements that persist throughout the application?

Everything after #posts should persist throughout the application (Like the left sidebar you find on Facebook).
def index
#title = "Posts"
default_order = "content_changed_at DESC"
params[:order_by] ||= default_order
#posts = current_user.subscribed_posts.paginate(:page => params[:page],
:per_page => 5,
:order => params[:order_by])
#subscribed_tags = current_user.subscribed_tags
#recent_posts = current_user.posts.limit(5).order("created_at DESC")
#tags= Tag.limit(20).order("ID asc")
#user = current_user
end
views/layout/_sidebar.html.erb:
<div class="user-profile">
<% avatar = image_tag(current_user.avatar.url(:thumb), :class => "authenticated-avatar") %>
<%= link_to avatar, "/users/#{current_user.id}" %>
<%= link_to "#{current_user.username}", "/users/#{current_user.id}", :class => "authenticated-username" %>
</div>
<%= form_for(#user, :remote => true) do |f| %>
<div class="field">
<%= f.label :subscribed_tag_names %><br />
<%= f.autocomplete_field :subscribed_tag_names, autocomplete_tag_name_posts_path, :"data-delimiter" => ' ', :class => "autocomplete_field" %>
</div>
<div class="actions">
<%= f.submit :class => "user_subscribed_tag_names_submit" %>
</div>
<% end %>
<div class="user-subscribed_tags">
<% #subscribed_tags.each do |subscribed_tag| %>
<%= link_to "#{subscribed_tag.name}(#{subscribed_tag.posts.count})", unsubscribe_tags_path(:unsubscribed_tag_name => subscribed_tag.name) %>
<% end %>
</div>
<div class="user-recent-posts">
<h4>Recent Posts</h4>
<ul>
<% #recent_posts.each do |recent_post| %>
<li><%= link_to recent_post.title, recent_post %></li>
<% end %>
</ul>
</div>
<div class="top-tags">
<% #tags.each do |tag| %>
<span class="tag-name"><%= tag.name %></span>
<span class="tag-count"><%= tag.posts.count %></span>
<% end %>
</div>
<% end %>
Where should I place the code in the controller if I want them to persist throughout the application? (I would like to see some example code if possible).
If it persists throughout the application, i.e. for every actions of all controllers, you might place it in a before_filter in the application controller.
Add a before_filter to the application controller as :
before_filter :find_recent_posts_and_tags
And define it (as private) :
private
def find_recent_posts_and_tags
# define your instance variables
end
More about filters here and here.

Resources