Ruby on Rails error showing when posting - ruby-on-rails

I am a beginner in RoR (8 hours old) and was faced with a problem I can't get past. The tutorial presented in the get started guide on their site goes through setting a post entry example. I get the following error:
NoMethodError in Posts#show
Showing /Users/khalidalghamdi/blog/app/views/posts/show.html.erb where line #3 raised:
undefined method `title' for nil:NilClass
Extracted source (around line #3):
1
2
3
4
5
6
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
Rails.root: /Users/khalidalghamdi/blog
Application Trace | Framework Trace | Full Trace
app/views/posts/show.html.erb:3:in `_app_views_posts_show_html_erb__4427112910992919114_2164032300'
Request
Parameters:
{"id"=>"4"}
and this is the tutorial link http://guides.rubyonrails.org/getting_started.html and I am following section 5.6. It is not showing the posted details in the show.html.erb page. What am I doing wrong?
Update: Controller code:
class PostsController < ApplicationController
def new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
private
def post_params
params.require(:post).permit(:title, :text)
end
def show
   #post = Post.find(params[:id])
end
end

Set the instance variable #post in PostsController#show action.
Currently, #post variable is set as nil so you are getting undefined method 'title' for nil:NilClass error.
Remove the show action from private. Its not getting called as you have made it private. Hence #post is not set.
For example: (As you haven't shared the code, I am giving an example)
class PostsController < ApplicationController
## ...
def show
#post = Post.find(params[:id])
end
## ...
private
def post_params
params.require(:post).permit(:title, :text)
end
end
Also, a better approach is to add a before_action in your controller where you can set the #post variable in order to avoid redundant code across multiple actions. This makes your code DRY too.
For example:
class PostsController < ApplicationController
## set_post would be called before show, edit, update and destroy action calls only
before_action :set_post, only: [:show, :edit, :update, :destroy]
## ...
def show
## No need to set #post here
end
## ..
private
def set_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :text)
end
end

Seeing your controller code,you have defined your show action after the private method.
Put it above the private method like this
class PostsController < ApplicationController
def new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
def show
#post = Post.find(params[:id])
end
private
def post_params
params.require(:post).permit(:title, :text)
end
end
Note:
Any method defined after the private method is also treated as private.

Related

i am trying to show my posts title on show page but it shows this error again and again . i am beginner in rails

**I made a controller and model for post and not able to show my post's
title on the show page but repeatedly i am getting the same error **
my posts_controller code :
class PostsController < ApplicationController
def index
end
def new
end
def create
#render plain: params[:post][:body].inspect
#post = Post.new(post_params)
if #post.save
redirect_to posts_path
else
render "new"
end
end
def show
#post= Post.find(:id=>params[:id])
# #article = "prateek"
end
private
def post_params
params.require(:post).permit(:title,:body)
end
end
my show.html.erb file :
<h1><%= #post.title %></h1>
my post.rb file:
class Post < ApplicationRecord
end
**I expect the result but I didn't get anything right
error = NoMethodError in Posts#show
undefined method `title' for nil:NilClass**
You're passing an hash to find, while you're suppose to pass just the id.
#post= Post.find(params[:id])
or use find_by if you want to pass an hash
#post= Post.find_by(:id => params[:id])

Why am I getting "AbstractController::DoubleRenderError" when calling redirect_to in after_action?

In the comments controller, I am redirecting to the articles show page after both create and destroy.
So I decided to write an after_action which would do the redirect_to.
class CommentsController < ApplicationController
before_action :find_article
before_action :find_comment, only: [:destroy]
after_action :goto_articles_page, only: [:create, :destroy]
def create
#comment = #article.comments.create(comment_params)
end
def destroy
#comment.destroy
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
def find_article
#article = Article.find(params[:article_id])
end
def find_comment
#comment = #article.comments.find(params[:id])
end
def goto_articles_page
redirect_to article_path(#article) and return
end
end
But this gives me AbstractController::DoubleRenderError after both create and destroy.
Why am I getting this error?
By default, Rails will render views that correspond to the controller action. See Rails Guides.
So in your create and destroy actions, Rails is performing a render by default. Then your after_action (which happens after the action) is redirecting, so it's double rendering.
Instead of an after_action, you could call the goto_articles_page method in your controller actions.
For example:
def destroy
#comment.destroy
goto_articles_page
end
def goto_articles_page
redirect_to article_path(#article) #return not needed
end
I think using return when rendering any action but when redirect_to use then not need to use return then finally you can remove and return
Rails guide very nicely explained that you can follow this carefully
redirect_to explanation
Hope to help

undefined method `user_name' for nil:NilClass

I'm trying to make a simple rails app, where useres can leave comments on posts.
When I make a new post, I run into a undefined method 'user_name' for nil:NilClass error.
Specifically, the following:
As you can see in the picture, #post.comments seems to contain a single comment with nil variables.
my comment controller is as follows:
before_action :set_post
def create
#comment = #post.comments.build(comment_params)
#comment.user_id = current_user.id
if #comment.save
flash[:success] = "You commented the hell out of that post!"
redirect_to #post
else
flash[:alert] = "Check the comment form, something went horribly wrong."
redicect_to #post
end
end
#...
private
def comment_params
params.require(:comment).permit(:content)
end
def set_post
#post = Post.find(params[:post_id])
end
And my post controller:
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :owned_post, only: [:edit, :update, :destroy]
#...
def create
#post = current_user.posts.build(post_params)
if #post.save
flash[:success] = "Your post has been created!"
redirect_to #post
else
flash.now[:alert] = "Your new post couldn't be created! Please check the form."
render :new
end
end
#...
private
def post_params
params.require(:post).permit(:image, :description)
end
def set_post
#post = Post.find(params[:id])
end
Thanks for the help. Sorry for and grammatical errors, I've been up for a while working on this, and am not a great speller when I'm awake.
try change
#comment.user_id = current_user.id
to
#comment.user = current_user
You need to either make sure comment does not get saved without an user/user_id, or you have to handle the case in view where user/user_id is nil
You are asking for the name of the user but you are not currently permitting a user_id in your comment_params:
This:
def comment_params
params.require(:comment).permit(:content)
end
Should be:
def comment_params
params.require(:comment).permit(:content, :user_id)
end
It is also possible that your code should be:
comment.user.name
instead of
comment.user.user_name
we would need to see your model to confirm. I would not use user_name as an attribute of user.
One of the comments for that post might not have a user. You can use try method here.
#comment.try(:user).try(:user_name)
But the ideal way to handle this would be to add a presence validation to the user model so that all comments created by any user in future will have a name.

Ruby on Rails "SystemStackError Stack level too deep" error [duplicate]

This question already has an answer here:
SystemStackError (stack level too deep)
(1 answer)
Closed 7 years ago.
I'm pretty new to Ruby on Rails and i'm trying to build a simple blogging platform that allows user authentication using devise. When I fill out the posts form which takes a title and content field, when I press the "create post" button i get an error that reads
SystemStackError in PostsController#create stack level too deep
It seems as if the "create" action in my PostsController is where the problem stems from. Can any one help me? This is how my PostsController looks:
class PostsController < ApplicationController
before_action :authenticate_user!
def index
#posts = Post.all
end
def new
#post = Post.new
end
def create
#post = Post.new(params[:post])
end
def show
#post = Post.find(params[:id])
end
private
def params
params.require(:post).permit(:title, :content)
end
end
Easy, you call params method in the body of params method (recursively) - boom, infinite loop. Change the name of your custom params method:
def create
#post = Post.new(post_params)
# etc.
end
# ...
def post_params
params.require(:post).permit(:title, :content)
end

Rails - Listing records of a model in a static page

I am trying to call records of a model (listing all records like Posts.all) to a view that is binded to another controller.
So, I want to reach the index action of Posts_controller which contains the .all listing and .group_by listing that I want to reach and list them in a static page that is listed in Pages_controller (named as yonetim)
This is just for listing the posts for admin view (like the listing in active admin).
I think, I dont need to post any code because the question is quite abstract, but if needed I will edit the question.
* Edit for clarifying*
This is my posts_controller.rb
class PostsController < ApplicationController
before_action :find_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
load_and_authorize_resource
def index
#posts = Post.all.order('postdate DESC')
#posts_by_month = #posts.group_by { |post| post.postdate.strftime('%m - %Y')}
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 post_params
params.require(:post).permit(:id, :title, :body, :postdate)
end
def find_post
#post = Post.find(params[:id])
end
end
As it can be seen it is a basic blog application. Visitors that reach the root_path (posts#index routed) can see the post records based on grouping of month and year.
What I want to add is reaching the new, edit destroy and index.#posts from a static page that I create for the purpose of admin interface (similar to active Admin gem).
** This is the pages_controller.rb **
class PagesController < ApplicationController
def yonetim
end
end
So when I hit /yonetim (routed to get pages#yonetim), I want the user to see the index action of posts controller with link to new, show, edit and destroy of the record.
***The system also have devise with admin boolean and cancan so if the user not signed in or don't have the authorization for admin usage, they are moved to root_path with an exception.
My problem rises that, I have tried nearly everything to list the #posts records of posts#index method in the pages/yonetim view or in the pages_controller.rb yonetim method.
So that I can list them in my admin view and work around with them.
If anything else is required just let me know.
Thanks in advance,
Mustafa
Multiple options here for pages#yonetim:
Just Redirect to 'posts#index'
Assign view variables (#posts and #posts_by_month) like in posts#index and render template posts/index.
Assign view variables (#posts and #posts_by_month) like in posts#index and render template pages/index (the default view in this case).
The drawback for the first two options is that all links (new/edit/destroy) will link to the PostsController and not to the PagesController, because you are re-using the views that were created for the PostsController.

Resources