I'm having an issue with my form_for - ruby-on-rails

I'm currently running into a problem with my form.
First argument in form cannot contain nil or be empty
in my comments/new which is a partial as _new.html.erb. This is the file:
<% form_for #comment do |f| %>
<%= f.label :body %>
<%= f.text_field :body, placeholder: "Write Message here.." %>
<% end %>
What I'm trying to do is render add a comment to an Article#Show page.
My code:
Comments Controller
class CommentsController < ApplicationController
before_action :find_comment, only: [:show, :edit, :update, :destroy]
def index
#comments = Comment.all
end
def new
#comment = Comment.new
end
def create
#comment = current_user.comments.build(comment_params)
if #comment.save
redirect_to :back
else
redirect_to '/'
end
end
def show
end
def edit
end
def update
if #comment.update(comment_params)
redirect_to '/'
else
redirect_to :back
end
end
def destroy
#comment.destroy
redirect_to "/"
end
private
def find_comment
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:body)
end
end
Articles#Show
<%= render '/comments/new' %>
If there is additional code required on my part. Please ask and I'll edit/update the question with additional files.
All help/explanation is appreciated. Thank you in advance.

First question:
Add into Article#Show
def show
#comment = Comment.new
end

Related

Simple_form_for action hitting wrong URL on edit in rails

I have created a simple_form_For common for both new and update,
currently, it's working fine for new but for edit/update, it calling the wrong URL.
class NewsfeedsController < ApplicationController
before_action :find_post, only: [:show, :destroy, :edit, :update]
def index
#posts = Post.all.order("created_at DESC")
end
def show
# before_action is taking care of all 4 i.e(sho,edit,update and destroy)..Keeping it DRY
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to root_path
else
render 'new'
end
end
def edit
end
def update
if #post.update(post_params)
redirect_to newsfeed_path(#post)
else
render 'edit'
end
end
def destroy
end
private
def post_params
params.require(:post).permit(:content)
end
def find_post
#post = Post.find(params[:id])
end
end
In Form.html
<%= simple_form_for #post, url: newsfeeds_path(#post) do |f| %>
<%= f.input :content,label: false, placeholder: "write your post here..." %>
<%= f.button :submit %>
<% end %>
on inspect element on browser,
i am getting action wrong,
it needs to be action="/newsfeeds/7"
Please guide
As you are using common _form for new and update, you need to add condition in url respectively,
<%= simple_form_for #post, url:(#post.new_record? ? newsfeeds_path : newsfeed_path(#post)) do |f| %>
This will help you using both new and update method.
Hope this will help.
Update action should be newsfeed_path(#post) and not newsfeeds_path(#post). Please correct it and try again!
<%= simple_form_for #post, url: newsfeed_path(#post) do |f| %>
Hope that helps!

Adding a comment model to associate with a post/user model

I finally was able to associate a user model with a post model with:
def create
#post = Post.new(post_params)
#post.user = current_user
Right now I'm trying to create a comment in the Post#Show page but continue to receive an error regarding my form. The two errors I'm running into are:
NoMethodError in Posts#show undefined method `comments_path'
when I have #comment = Comment.new in Post#show. When it's removed I get:
ArgumentError in Posts#show First argument in form cannot contain nil or be empty
What could possibly be wrong with my form? Also if someone can recommend a better way to associate my 3 models (basically have a user_id and a post_id when comment is created I'm open for suggestions). My comment form is going to appear within the Post#Show page. My current code is:
Comment Model
belongs_to :user
belongs_to :post
User Model
has_many :posts
has_many :comments
Post Model
has_many :comments
belongs_to :user
Comment Controller
class CommentsController < ApplicationController
before_action :find_comment, only: [:show, :edit, :update, :destroy]
def index
#comments = Comment.all
end
def new
#comment = Comment.new
end
def create
#post = Post.find(params[:id])
#comment = #post.comments.build(comment_params)
#comment.user = current_user
if #comment.save
flash[:notice] = "Successfully created..."
redirect_to comments_path
else
flash[:alert] = "failed"
redirect_to root_path
end
end
def show
end
def edit
end
def update
if #comment.update
flash[:notice] = "You updated your comment"
else
flash[:alert] = "Failed to update"
end
def destroy
#comment.destroy
redirect_to '/'
end
private
def find_comment
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:comment)
end
end
Post Controller
class PostsController < ApplicationController
before_action :find_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.user = current_user
if #post.save!
flash[:notice] = "Successfully created..."
redirect_to posts_path
else
flash[:danger] = "failed to add a post"
render 'new'
end
end
def show
end
def edit
end
def update
if #post.update
flash[:notice] = "Successfully updated"
redirect_to post_path
else
flash[:alert] = "Failed to update Post"
redirect_to :back
end
end
def destroy
if #post.destroy
flash[:notice] = "Successfully delete"
redirect_to posts_path
else
flash[:danger] = "Wasn't able to delete Blog post."
redirect_to :back
end
end
private
def find_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :body, :description)
end
end
Post#Show View
<%= render '/comments/form' %>
Comment#form
<%= form_for #comment do |f| %>
<%= f.label :comment, "Title" %>
<%= f.text_field :comment, placeholder: "Write a comment" %>
<%= f.submit "Submit" %>
<% end %>
If there is something missing please ask me to update my post. Thank you all who help me better understand my problem.
Your associations seem fine. The error
NoMethodError in Posts#show undefined method `comments_path'
means that you don't have the route comments_path or Comments#Create. Basically, when you have a form_for with a Comment as the parameter, it assumes you are wanting to go to the create or update route, depending if it's a new record. The easiest thing to do would be to add
resources :comments
to your routes file. However, since you want a comment associated with a post, you want to modify your routes file to have:
resources :posts do
resources :comments
end
Then, change your form to look like this:
<%= form_for [#post, #comment] do |f| %>
So when you submit a form, you will have a params[:post_id] and a params[:id] to play with. Find the Post with the params[:post_id]. Ignore the params[:id] when you're creating a comment, but use it when you're updating a comment.
Edit: Here is a link to some help regarding Nested Resourcing.

Ability for users to add images to comments in Rails forum

So i have added the ability for users to add images to posts in my rails forum. I now want users to be able to add images to comments to posts.
I began with a migration add_attachment_image_to_comments.rb
class AddAttachmentImageToComments < ActiveRecord::Migration
def self.up
change_table :comments do |t|
t.attachment :image
end
end
def self.down
remove_attachment :comments, :image
end
end
Edited the view file:
= simple_form_for([#post, #post.comments.build]) do |f|
= f.input :comment
= f.input :image
%br
= f.submit
Here is the posts_controller file:
class PostsController < ApplicationController
before_action :find_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#posts = Post.all.order("created_at DESC").paginate(page: params[:page], per_page: 7)
end
def show
end
def new
#post = current_user.posts.build
end
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def edit
end
def update
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
def destroy
#post.destroy
redirect_to root_path
end
private
def find_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content, :image)
end
end
Here is the comments_controller file:
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment].permit(:comment, :image))
#comment.user_id = current_user.id if current_user
#comment.save
if #comment.save
redirect_to post_path(#post)
else
render 'new'
end
end
def edit
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
end
def update
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
if #comment.update(params[:comment].permit(:comment, :image))
redirect_to post_path(#post)
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
end
This give users the ability to add the attachment. The problem i have now is getting the image to show in the comments section on the post.
This is my show file:
#post_content
%h1= #post.title
%p= #post.content
= image_tag #post.image.url(:medium)
#comments
%h2
= #post.comments.count
Comment(s)
= render #post.comments
= image_tag #comment.image.url(:medium)
I get the error - undefined method `image' for nil:NilClass. Highlighing this row - = image_tag #comment.image.url(:medium)
Any help much appreciated.
undefined method `image' for nil:NilClass
The problem is #comment is nil at this line = image_tag #comment.image.url(:medium) because you haven't declared #comment in the show method of posts_controller.
Solution
As post can have many comments and since #post is available, you can iterate through the #post's comments in the view like below.
- #post.comments.each do |comment|
= image_tag comment.image.url(:medium)

ActionController::UrlGenerationError in Valuations#new

I've read other SO articles relating to UrlGenerationError's which seem to point to singularization or plurization of a word, but I don't think that's the issue here.
It works when I remove from valuations/_form.html.erb:
<%= render "comments/comments" %>
<%= render "comments/form" %>
Submit the _form with :name & :tag_list, readd
<%= render "comments/comments" %>
<%= render "comments/form" %>
and then refresh. What's the deal when nil?
routes
resources :valuations do
resources :comments
end
comments_controller
class CommentsController < ApplicationController
before_action :load_commentable
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_action :logged_in_user, only: [:create, :destroy]
def index
#comments = #commentable.comments
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(comment_params)
if #comment.save
#comment.create_activity :create, owner: current_user
redirect_to #commentable, notice: "comment created."
else
render :new
end
end
def edit
#comment = current_user.comments.find(params[:id])
end
def update
#comment = current_user.comments.find(params[:id])
if #comment.update_attributes(comment_params)
redirect_to #commentable, notice: "Comment was updated."
else
render :edit
end
end
def destroy
#comment = current_user.comments.find(params[:id])
#comment.destroy
#comment.create_activity :destroy, owner: current_user
redirect_to #commentable, notice: "comment destroyed."
end
private
def set_comment
#comment = Comment.find(params[:id])
end
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
def comment_params
params.require(:comment).permit(:content, :commentable)
end
end
valuations_controller
class ValuationsController < ApplicationController
before_action :set_valuation, only: [:show, :edit, :update, :destroy]
before_action :logged_in_user, only: [:create, :destroy]
def index
if params[:tag]
#valuations = Valuation.tagged_with(params[:tag])
else
#valuations = Valuation.order('RANDOM()')
end
end
def show
#valuation = Valuation.find(params[:id])
#commentable = #valuation
#comments = #commentable.comments
#comment = Comment.new
end
def new
#valuation = current_user.valuations.build
#commentable = #valuation
#comments = #commentable.comments
#comment = Comment.new
end
def edit
end
def create
#valuation = current_user.valuations.build(valuation_params)
if #valuation.save
redirect_to #valuation, notice: 'Value was successfully created'
else
#feed_items = []
render 'pages/home'
end
end
def update
if #valuation.update(valuation_params)
redirect_to #valuation, notice: 'Value was successfully updated'
else
render action: 'edit'
end
end
def destroy
#valuation.destroy
redirect_to valuations_url
end
private
def set_valuation
#valuation = Valuation.find(params[:id])
end
def correct_user
#valuation = current_user.valuations.find_by(id: params[:id])
redirect_to valuations_path, notice: "Not authorized to edit this valuation" if #valuation.nil?
end
def valuation_params
params.require(:valuation).permit(:name, :private_submit, :tag_list, :content, :commentable, :comment)
end
end
comments/_form.html.erb
<%= form_for [#commentable, #comment] do |f| %>
<% if #comment.errors.any? %>
<div class="error_messages">
<h2>Please correct the following errors.</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="america">
<div class="form-group">
<%= f.text_area :content, rows: 4, class: 'form-control', placeholder: 'Enter Comment' %>
</div>
<div class="america2">
<%= button_tag(type: 'submit', class: "btn") do %>
<span class="glyphicon glyphicon-plus"></span> Comment
<% end %>
</div>
<% end %>
Thank you so much for your time.
When you have a nested resource like that, the url for creating a comment looks like /valuations/123/comments where 123 is the id of the valuation - without a valuation id this url cannot be generated.
On your Valuations#new page, the valuation (i.e. #commentable) is an unsaved object, so it has no id yet, hence the error about a missing valuation_id. In addition having one form nested within another is invalid html and will lead to odd behaviour. On your show page on the other hand, the valuation does have an id and so things should work as they are.
If you want to create a valuation and its initial comment(s) in one go then you should use accepts_nested_attributes_for and fields_for to add the fields for the comments to your valuation form (There are other ways, but accepts_nested_attributes_for is what is built into rails)

First argument in form cannot contain nil or be empty.Rails 4

I want to create a comments controller.But when rails render form, browser show an error 'First argument in form cannot contain nil or be empty', though the variable is defined.
there is comments_controller
class CommentsController < ApplicationController
def new
end
def create
#comment = current_user.comments.build(comment_params)
if #comment.save
redirect_to root_url
else
render 'static_pages/home'
end
end
private
def comment_params
params.require(:comment).permit(:text)
end
end
new.html.erb
<%= form_for(#comment) do |f| %>
<%= f.text_field :text %><br><br>
<% end %>
how fix?
sorry for my bad English
Fix :-
class CommentsController < ApplicationController
def new
#comment = Comment.new
end
# ....
end

Resources