I have an app set up with a Wicked Wizard form to create a new post.
The last step allows users to upload pictures to their post.
For image processing I am using Carrierwave and Fog (because I'm hosting the site on heroku and I am using Amazon S3 for storage).
It's all working fine, but the upload to Amazon S3 is very slow.
Following Ryan Bates' Uploading to Amazon S3 railscast (http://railscasts.com/episodes/383-uploading-to-amazon-s3) I tried Carrierwave_Direct (https://github.com/dwilkie/carrierwave_direct) to speed up the painfully slow upload to Amazon S3.
When doing this, however, I get an error:
NoMethodError in PostSteps#show
Showing
/Users/petersonneveld/rails_projects/doamer/doamer2/app/views/property_steps/picture.html.erb where line #1 raised:
undefined method `direct_fog_url' for nil:NilClass
I really don't know what to do to solve this. Does anyone have advice? Thanks a bunch for your help!
In the last step of my wicked wizard form I have
# app/views/post_steps/picture.html.erb
<%= direct_upload_form_for #uploader, url: wizard_path do |f| %>
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
<h2>Let's post some pictures!</h2>
</div>
</div>
<div class="panel-body">
<% 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 |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group col-md-12">
<%= f.label :image, "Upload image" %><br>
<%= image_tag(#post.image_url(:thumb)).to_s if #post.image? %>
<%= f.file_field :image %>
</div>
<div class="form-group col-md-12">
<%= f.label :remote_image_url, "or paste image URL" %>
<%= f.text_field :remote_image_url, class: "form-control" %>
<%= f.hidden_field :image_cache %>
</div>
<div class="form-group col-md-12">
<h4><%= f.check_box :remove_image %>
<span class="label label-danger">Remove image</span></h4>
</div>
<div class="form-group col-md-12">
<%= f.button "Finish", class: "btn btn-primary", data: {disable_with: "<i class='fa fa-spinner fa-spin'></i> Saving post..."} %>
</div>
</div>
</div>
<% end %>
And in my controller
# app/controllers/post_steps_controller.rb
class PostStepsController < ApplicationController
include Wicked::Wizard
steps :description, :picture
def show
#post = Post.find(params[:post_id])
render_wizard
end
def update
#post = Post.find(params[:post_id])
#post.update_attributes(post_params)
render_wizard #post
end
private
def post_params
params.require(:post).permit(...)
end
def redirect_to_finish_wizard(options = nil)
redirect_to #post, notice: "Thanks for submitting a post."
end
end
And my post controller create action
# app/controllers/post_controller.rb
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to post_steps_path(:id => "description", :post_id => #post.id)
else
render :new
end
end
Found the answer: had to update the 'aws-sdk' gem!
Related
I managed to install Mailboxer with this tutorial but i have a recurring error :
N+1 Query detected
Mailboxer::Message => [:sender]
Add to your finder: :includes => [:sender]
N+1 Query method call stack
app/views/conversations/_messages.html.erb:12:in `block in _app_views_conversations__messages_html_erb__3829465222244059655_69982701059040'
app/views/conversations/_messages.html.erb:1:in `_app_views_conversations__messages_html_erb__3829465222244059655_69982701059040'
app/views/conversations/show.html.erb:27:in `_app_views_conversations_show_html_erb__1439517360344897040_69982700516580'
app/views/conversations/_messages.html.erb:12:in `block in _app_views_conversations__messages_html_erb__3829465222244059655_69982701059040'
app/views/conversations/_messages.html.erb:1:in `_app_views_conversations__messages_html_erb__3829465222244059655_69982701059040'
app/views/conversations/show.html.erb:27:in `_app_views_conversations_show_html_erb__1439517360344897040_69982700516580'
I had another one for :message but i fixed the problem with includes. If i try to do the same with :sender, i have this error:
Association named 'sender' was not found on Mailboxer::Receipt; perhaps you misspelled it?
Tutorial original code : conversations_controller.rb
class ConversationsController < ApplicationController
before_action :authenticate_user!
def new
end
def create
recipients = User.where(id: conversation_params[:recipients])
conversation = current_user.send_message(recipients, conversation_params[:body], conversation_params[:subject]).conversation
flash[:success] = "Your message was successfully sent!"
redirect_to conversation_path(conversation)
end
def show
#receipts = conversation.receipts_for(current_user)
# mark conversation as read
conversation.mark_as_read(current_user)
end
def reply
current_user.reply_to_conversation(conversation, message_params[:body])
flash[:notice] = "Your reply message was successfully sent!"
redirect_to conversation_path(conversation)
end
def trash
conversation.move_to_trash(current_user)
redirect_to mailbox_inbox_path
end
def untrash
conversation.untrash(current_user)
redirect_to mailbox_inbox_path
end
private
def conversation_params
params.require(:conversation).permit(:subject, :body,recipients:[])
end
def message_params
params.require(:message).permit(:body, :subject)
end
end
Tutorial original code : show.html.erb
<div class="row">
<div class="spacer"></div>
<div class="col-md-6">
<%= link_to "Compose", new_conversation_path, class: "btn btn-success" %>
</div>
<div class="col-md-6 text-right">
<% if conversation.is_trashed?(current_user) %>
<%= link_to 'Untrash', untrash_conversation_path(conversation), class: 'btn btn-info', method: :post %>
<% else %>
<%= link_to 'Move to trash', trash_conversation_path(conversation), class: 'btn btn-danger', method: :post,
data: {confirm: 'Are you sure?'} %>
<% end %>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-body">
<%= render 'mailbox/folders' %>
</div>
</div>
</div>
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-body">
<%= render partial: 'messages' %>
</div>
<div class="panel-footer">
<!-- Reply Form -->
<%= form_for :message, url: reply_conversation_path(conversation) do |f| %>
<div class="form-group">
<%= f.text_area :body, placeholder: "Reply Message", rows: 4, class: "form-control" %>
</div>
<%= f.submit "Reply", class: 'btn btn-danger pull-right' %>
<% end %>
<div class="clearfix"></div>
</div>
</div>
</div>
</div>
Tutorial original code : _messages.html.erb
<% #receipts.each do |receipt| %>
<% message = receipt.message %>
<div class="media">
<div class="media-left">
<!-- user avators can go here -->
<a href="#">
<img class="media-object" src="http://placehold.it/64x64" alt="...">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">
<%= message.sender.username %> <br>
<small><b>Subject: </b><%= message.subject %></small><br>
<small><b>Date: </b><%= message.created_at.strftime("%A, %b %d, %Y at %I:%M%p") %></small>
</h4>
<%= message.body %>
</div>
</div>
<% end %>
If i delete <%= message.sender.username %> the problem is solved...
Any ideas ?
Normally, to fix these N+1 query problems we use an includes and by passing a hash, we can includes nested associations. So looking at this code, calling receipt.message.sender is triggering the error, so we have a Receipt model, a message association on it and a sender associated to that. So if we can find where we load the Receipt we can add includes(message: :user) like we would for any other model.
Digging into the mailboxer gem, the receipts_for method in your show action is just a wrapper for a couple of scopes on Mailboxer::Receipt. Since this method just runs some scopes for you, we can chain onto the end of it as if it were a normal ActiveRecord where chain.
So with all that in mind, we should be able to add on our includes and avoid the N+1 query problem, ending up with something like
#receipts = conversation.receipts_for(current_user).includes(message: :sender)
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 %>
I am new to Rails. I want to pass parameters to DB via controller, but I receive this error param is missing or the value is empty:retweet. I think the problem is the way of passing parameters in view.
Here is the view
<% for #p in #posts %>
<div class="panel panel-default post-panel">
<div class="panel-body row">
<div class="col-sm-1">
<img src="/avatar.png" class="rounded-img" height="50px" width="50px">
</div>
<div class="col-sm-11">
<p class="post-title"><%= User.find(#p.user_id).username %> <span class="post-creation">- <%= #p.created_at.to_formatted_s(:short) %></span></p>
<p class="post-content"><%= #p.content %></p>
</div>
<div class="col-sm-12">
<p class="post-links">
<span class="glyphicon glyphicon-comment g-links" aria-hidden="true"></span>
**<%= form_for Retweet.new do |f| %>
<%= hidden_field_tag current_user.id, (:user_id) %>
<%= hidden_field_tag #p.id, (:post_id) %>
<%= f.submit "Retweet", class:"btn btn-primary"%>**
<% end %>
And here is the Controller
def new
#retweet = Retweet.new
end
def create
#retweet = Retweet.new(post_params)
redirect_to(:back)
end
private def post_params
params.require(:retweet).permit(:user_id, :post_id)
end
end
You should read up some tutorials on basic REST controllers in Rails. Your create action didn't save the retweet.
def create
#retweet = Retweet.new(post_params)
if #retweet.save
redirect_to(:back)
else
render action: 'new'
end
end
Edit: Just noticed your form is all wrong:
<%= form_for Retweet.new do |f| %>
<%= f.hidden_field :user_id, current_user.id %>
<%= f.hidden_field :post_id, #p.id %>
<%= f.submit "Retweet", class:"btn btn-primary"%>**
<% end %>
Mind you that you shouldn't allow settign the user_id like this, it is very easy to change it and thus mess around with your data. Instead you should add this to retweet#create:
#retweet.user = current_user
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
I am currently teaching myself some RoR and doing the tutorial, but adding some nicer layout and stuff with bootstrap and I am running into a problem which I cant figure out.
I am trying to do the validation part (http://guides.rubyonrails.org/getting_started.html#adding-some-validation), but when I use:
<% #post.errors.any? %>
I get this message:
undefined method `errors' for nil:NilClass
Extracted source (around line #9):
<legend><h1>Add Post</h1></legend>
<%= form_for :post, url: posts_path, html: {class: 'form-horizontal'} do |f| %>
<% if #post.errors.any? %>
<div id="errorExplanation">
Nothing works and I even copied and pasted the parts from the tutorial.
Here is the code for the view:
<p> </p>
<div class="span6"
<fieldset>
<legend><h1>Add Post</h1></legend>
<%= form_for :post, url: posts_path, html: {class: 'form-horizontal'} do |f| %>
<% if #post.errors.any? %>
<div id="errorExplanation">
<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="control-group">
<%= f.label :title, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :title, :class => 'span4' %>
</div>
</div>
<div class="control-group">
<%= f.label :content, :class => 'control-label' %>
<div class="controls">
<%= f.text_area :content, :rows => '7', :class => 'input-block-level' %>
</div>
</div>
<div class="form-actions">
<%= f.submit "Add Post", :class => 'btn btn-success' %>
<%= link_to "Cancel", posts_path, :class => 'btn', :style => 'float:right;' %>
</div>
<% end %>
</fieldset>
</div>
And my posts_controller:
class PostsController < ApplicationController
def new
end
def create
#post = Post.new(params[:post].permit(:title, :content))
if #post.save
redirect_to #post
else
render 'new'
end
end
def show
#post = Post.find(params[:id])
end
def index
#posts = Post.order("created_at desc")
end
private
def post_params
params.require(:post).permit(:title, :content)
end
end
What am I missing? Thanks in advance!
You need to define #post in your new action too.
def new
#post = Post.new
end
You're getting the NilClass error because #post has no value (it's nil) when you first load the form on the new action.
When you do the render :new in your create action there is no problem because it's using the #post you've defined at the top of create.
Update the create method in posts.controller.rb file with the below piece of code. It worked for me.
def create
#post = Post.new(params[:post].permit(:title, :text))
#post.save
redirect_to #post
end
In your posts_controller, add this :
def new
#post = Post.new
end
If you have made the changes to edit/create etc. and it still gives you ActionView::Template::Error (undefined method `errors' for nil:NilClass):
Try restarting rails server
I kept receiving the error even after correcting the files in articles_controller.rb
and still got the error. It was fixed after i restarted rails server.