Undefined method in User_Controller - To do List - ruby-on-rails

I'm working on a to-do list in rails and I'm getting the following: undefined method items for nil:NilClass in my users_controller.rb.
The program was working to the point where I could delete and create the list and have it take me to the new_list_path. However, after I came back a day later, I got the undefined method.
Currently, the user is logged in and there is no list. I tried to add a list via rails console but that didn't work.
users_controller.rb
class UsersController < ApplicationController
def show
return redirect_to new_list_path unless current_user
#list = current_user.list
#items = #list.items
end
end
I am directing everything to go the View/Users/Show page with some partials:
users/show.html.erb
<h1><%= #list.title %></h1>
<%= link_to "Delete List", #list, method: :delete %>
<h2 class="media-heading"><%= current_user.name %></h2>
<%= render partial: 'items/form'%>
<%= render partial: 'items/item', collection: #items %>
Partials are here
items/_form.html.erb
<%= form_for [#list, #list.items.new] do |f| %>
<div class="form-group">
<h4>Add an Item:</h4><br/>
</div>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control', placeholder: "Add an Item:" %>
</div>
<div class= "form-group">
<%= f.submit "Create Item", class: 'btn btn-success' %>
</div>
<% end %>
items/_item.html.erb
<small class="media-heading">
<p><%= item.name %></p>
<%# time_ago_in_words(item.created_at) %>
</small>
Here are my other two controllers:
lists_controller.rb
class ListsController < ApplicationController
before_action :authenticate_user!
def new
#list = List.new
end
def create
#list = List.new(list_params)
#list.user = current_user
if #list.save
flash[:notice] = "List was saved."
redirect_to current_user
else
flash[:error] = "There was a problem saving your list."
redirect_to user_path(current_user)
end
end
def destroy
#list = List.find(params[:id])
if #list.destroy
redirect_to new_list_path
else
redirect_to current_user
end
end
def edit
end
private
def list_params
params.require(:list).permit(:title)
end
end
items_controller.rb
class ItemsController < ApplicationController
def show
#items = Item.all
end
def create
#list = List.find(params[:list_id])
#item = Item.new(item_params)
#item.list = #list # after initializiation, before saving
if #item.save
flash[:notice] = "Item was saved."
redirect_to current_user
else
flash[:error] = "There was a problem saving your item."
redirect_to current_user
end
end
private
def item_params
params.require(:item).permit(:name)
end
end
I'm wondering how it's broken when it worked previously.
Models are as follows:
list.rb
class List < ActiveRecord::Base
belongs_to :user
has_many :items
end
user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_one :list
end
item.rb
class Item < ActiveRecord::Base
belongs_to :list
end

In the users_controller.rb, maybe you should define:
def show
#user = User.find(params[:id])
#list = #user.lists
#items = #list.items
end
You need to find the specific user first so it know what lists to show. I realize you are trying to do that with devise helpers, but it isn't really necessary.

Related

Rails: link_to delete from different controller

Right now I have a like button that allows you to like foods. When you try to unlike the food, I get this error:
The action 'destroy' could not be found for UsersController
I'm not sure why it is looking for the destroy action in the users controller. My only guess is because the button is on the user show page, so I assume it defaults to that controller, but how would I access the delete method from my votes controller?
Shared like form
<% unless current_user.votes.empty? || current_user.votes.pluck(:food_id).include?(food.id) %>
<%= form_for #vote do |f| %>
<%= f.hidden_field 'food_id', food.id %>
<%= f.hidden_field 'user_id', food.user.id %>
<%= f.submit "Vote", :class => "like_button" %>
<% end %>
<% else %>
<% vote = food.votes.where(user_id: current_user.id).first %>
<div class="unlike_button">
<%= button_to "Unlike", vote, method: :delete %>
</div>
<% end %>
class VotesController < ApplicationController
def index
#votes = Vote.all
end
def new
#vote = Vote.new
end
def create
#vote = Vote.new(vote_params)
if #vote.save
puts #vote
flash[:notice] = "Thanks for voting!"
redirect_back(fallback_location: root_path)
else
puts "No"
flash[:notice] = "Something went wrong"
redirect_back(fallback_location: root_path)
end
end
def destroy
#vote = Vote.find(params[:id])
if #vote.destroy!
flash[:notice] = "Unvoted!"
redirect_back(fallback_location: root_path)
end
end
private
def vote_params
params.require(:vote).permit(:food_id, :user_id)
end
end
class Vote < ApplicationRecord
belongs_to :user
belongs_to :food
end

Avatar is not showing for users

I am using devise as my user authentication and carrierwave gem for image uploading. Now everything works well and the avatar gets saved in the users table and is shown inside the index view; but not inside the show view.
To make my question a bit more clear:
Inside the index view, the avatar get's successfully shown.
Inside the show view, the avatar falls to the default image because #user.avatar is blank/nil
Show code:
<div class="well">
<div class="media">
<a class="pull-left">
<% if #user.avatar.blank? %>
<img src="http://www.adtechnology.co.uk/images/UGM-default-user.png" style="width: 75px;">
<% elsif #user.avatar %>
<%= image_tag #user.avatar, :style => "width:75px;" %>
<% end %>
</a>
<div class="media-body">
<p>About <%= link_to #question.user.username, #question.user, :class => " bg" %></p>
</div>
<p class="text-muted small">Apparently this user doesn't like to share his information.</p>
</div>
</div>
Question controller:
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#questions = Question.all
respond_with(#questions)
end
def show
#user = User.find(params[:id])
respond_with(#question)
end
def new
if user_signed_in?
#question = current_user.questions.build
respond_with(#question)
else
redirect_to new_user_session_path
end
end
def edit
end
def create
#question = current_user.questions.build(question_params)
#question.save
respond_with(#question)
end
def update
#question.update(question_params)
respond_with(#question)
end
def destroy
#question.destroy
respond_with(#question)
end
private
def set_question
#question = Question.find(params[:id])
end
def question_params
params.require(:question).permit(:title, :description)
end
end
User model:
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
has_many :questions, :dependent => :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Question model:
class Question < ActiveRecord::Base
belongs_to :user
end
I fixed it by changing these lines inside the show.html.erb :
<% if #question.user.avatar.blank? %>
<img src="http://www.adtechnology.co.uk/images/UGM-default-user.png" style="width: 75px;">
<% elsif #question.user.avatar %>
<%= image_tag #question.user.avatar, :style => "width:75px;" %>
<% end %>
def show
#user = User.find(params[:id])
respond_with(#question)
end
Since the show action's called in QuestionsController, params[:id] will be #question's id. You should use #question.user to refer to the author of #question:
def show
#user = #question.user
respond_with(#question)
end

How to show user comments in rails

How can I show all comments in the post#show?
comments_controller
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
#comment = Comment.new(comment_params)
#post = Post.find(params[:post_id])
#comment.user_id = current_user.id
#comment.username = current_user.username
#comment.post_id=#post.id
#comment.save
redirect_to post_path(#post)
end
def show
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:text, :username)
end
end
Models:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :posts
has_many :comments
end
#app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
end
#app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
the views/posts/show.html.erb
<ul class="img-list-single">
<li>
<a>
<img src=<%= #post.url %>/>
<span class="text-content"><span><%=#post.title%></span></span>
</a>
<%= #comment.username%>
<%if current_user%>
<%= form_for :comment, :url => post_comments_path(#post) do |f|%>
<%= f.text_field :text %>
<%= f.submit%>
<% end %>
<%if current_user.id==#post.user_id%>
<%= button_to 'Delete', #post, method: :delete, :onclick => " returconfirm('Are you sure you want to delete this post?')"%>
<%end%>
<%end%>
First of all fix your posts controller. The show action should look like this:
class PostsController < ApplicationController
def show
#post = Post.find(params[:id])
#comments = #post.comments.includes(:user)
end
end
Now in app/views/posts/show.html.erb, I would render a partial:
<ul>
<%= render #comments %>
</ul>
Rails will look for a partial in app/views/comments/_comment.html.erb. You can just put all your comment view logic in there and will display all the comments:
# app/views/comments/_comment.html.erb
<li>
<%= comment.text %>
<br>
<%= comment.user.try(:username) %>
</li>
Finally, I would fix your create action in the comments controller:
class CommentsController < ApplicationController
def create
# First get the parent post:
#post = Post.find(params[:post_id])
# Then build the associated model through the parent (this will give it the correct post_id)
#comment = #post.comments.build(comment_params)
# Assign the user directly
#comment.user = current_user
if #comment.save
redirect_to post_path(#post)
else
render :new
end
end
end
It seems to me that you don't need to store the username attribute on the comment model, since that should be available through the comment.user association.
in your post#show action simply do:
#post = Post.find(params[:id])
#comments = #post.comments
then in your view add:
<% #comments.each do |comment| %>
<%= comment.text %>
<br />
<% end %>

'nil' is not an ActiveModel-compatible object. It must implement :to_partial_path while creating comments Rails

Alright guys, as one of my projects at Bloc I am creating a reddit clone. For this particular assignment, I am to create a feature where users can comment on each post (witch is already nested within each topic). However, I am coming across this error when I try to view a post that is associated with a topic.
ArgumentError in Posts#show
'nil' is not an ActiveModel-compatible object. It must implement :to_partial_path.
So far I have created comments controller, made the foreign key connection between comments and users, made the comments routes nested inside of the posts routes, created both a form partial for comment submission and a comment partial which is in post/show, and created a CommentPolicy in order to authorize users to create new comments.
I have checked my database, and comments do exist because I added them to my seed file. I suspect my error lies in my forms and my references to my partials, but I am a bit stumped. Any help here would be greatly appreciated. Thanks!
My code:
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_many :posts
has_many :comments
mount_uploader :avatar, AvatarUploader
def admin?
role == 'admin'
end
def moderator?
role == 'moderator'
end
end
comment.rb
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
respective routes within routes.rb
resources :topics do
resources :posts, except: [:index] do
resources :comments, only: [:create]
end
end
comments_controller:
class CommentsController < ApplicationController
def index
end
def create
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:post_id])
#comments = #post.comments
#comment = current_user.comments.build(params[:comment])
#comment.post = #post
#new_comment = Comment.new
authorize #comment
if #comment.save
flash[:notice] = "Comment was saved"
else
flash[:error] = "There was an error saving this comment. Please try again."
end
end
end
posts_controller:
class PostsController < ApplicationController
def show
#post = Post.find(params[:id])
#topic = Topic.find(params[:topic_id])
#comment = Comment.find(params[:id])
authorize #comment
end
def new
#topic = Topic.find(params[:topic_id])
#post = Post.new
authorize #post
end
def create
#topic = Topic.find(params[:topic_id])
#post = Post.new(post_params)
#post.user = current_user
#post.topic = #topic
authorize #post
if #post.save
flash[:notice] = "Post was saved."
redirect_to [#topic, #post]
else
flash[:error] = "There was an error saving this post. Please try again."
render :new
end
end
def edit
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
authorize #post
end
def update
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
authorize #post
if #post.update_attributes(post_params)
flash[:notice] = "Post was updated."
redirect_to [#topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :edit
end
end
private
def post_params
params.require(:post).permit(:title, :body, :image)
end
end
comments/_form.html.erb
<%= form for [topic, post, comment] do |f| %>
<div class="form-group">
<%= f.label :body %>
<%= f.text_area :body, rows: 8, class: 'form-control', placeholder: "Enter comment here" %>
</div>
<div class="form-group">
<%= f.submit "Add comment", class: "btn btn-success" %>
</div>
<% end %>
comments/_comment.html.rb
<%= comment.body %>
posts/show.html.erb
<h1><%= #post.markdown_title %></h1>
<div class="row">
<div class="col-md-8">
<small>
<%= image_tag(#post.user.avatar.tiny.url) if #post.user.avatar? %>
submitted <%= time_ago_in_words(#post.created_at) %> ago by
<%= #post.user.name %>
</small>
<p><%= #post.markdown_body %></p>
<small>
<%= image_tag #post.image_url%>
</small>
</div>
<div class="col-md-4">
<% if policy(#post).edit? %>
<%= link_to "Edit", edit_topic_post_path(#topic, #post), class: 'btn btn-success' %>
<% end %>
</div>
<%= render #comments %>
<% if policy(#comment).create? %>
<h4>New Comment</h4>
<%= render partial: 'comments/form', locals: { topic: #topic, post: #post, comment: #comment } %>
<% end %>
comment_policy
class CommentPolicy < ApplicationPolicy
def new
user.present?
end
def create
user.present?
end
end
comments within seed file
#Create Comments
100.times do
Comment.create!(
user: users.sample, # we have not yet associated Users with Comments
post: posts.sample,
body: Faker:: Lorem.paragraph
)
end
comments = Comment.all
The believe the error is in this line
<%= render #comments %>
in your posts/show.html.erb
You don't have #comments defined in show method of posts_controller. Try putting #comments = #post.comments in show method.
def show
#post = Post.find(params[:id])
#topic = Topic.find(params[:topic_id])
#comment = Comment.find(params[:id])
authorize #comment
#comments = #post.comments
end

Undefined method 'id' for nil:NilClass

I am having trouble solving this problem. I keep getting the same error:
ActionView::Template::Error (undefined method `id' for nil:NilClass):
Here is my likes controller:
class LikesController < ApplicationController
def new
#bookmark = Bookmark.find(params[:bookmark_id])
#like = Like.new
end
def create
#bookmark = Bookmark.find(params[:bookmark_id])
# #like = Like.new
# #like.user = current_user
# #like.bookmark = #bookmark
#like = current_user.likes.build(bookmark: #bookmark)
if #like.save
flash[:notice] = "Bookmark was Liked!"
redirect_to #bookmark
else
flash[:error] = "Unable to Like Bookmark"
redirect_to #bookmark
end
end
def destroy
##bookmark = Bookmark.find(params[:bookmark_id])
#like = #bookmark.likes.find(params[:id])
if #like.destroy
flash[:notice] = "Bookmark was Un-liked."
redirect_to #bookmark
else
flash[:error] = "Error Un-liking bookmark."
redirect_to #bookmark
end
end
end
My User model:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_many :topics
has_many :bookmarks
has_many :likes, dependent: :destroy
def liked(bookmark)
likes.where(bookmark: bookmark.id).first
end
end
My likes partial:
<div>
<% if like = current_user.liked(bookmark) %>
<%= link_to [#topic, bookmark, like], class: 'btn btn-danger', method: :delete do %>
<i class="glyphicon glyphicon-star-empty"> </i> Unlike
<% end %>
<% else %>
<%= link_to [#topic, bookmark, Like.new], class: 'btn btn-primary', method: :post do %>
<i class="glyphicon glyphicon-star"> </i> Like
<% end %>
<% end %>
</div>
Let me know if I need to show anything else, I appreciate any help
From where you are calling the partial try this :
<% #bookmarks.each do |bookmark| %>
<%= render partial: 'likes/like', locals: {bookmark: bookmark} %>
<% end %>
In your likes partial, you have:
<% if like = current_user.liked(bookmark) %>
That = should be a ==. With a single equals, you're checking whether the like variable is assigned a truthy value, based on current_user.liked(bookmark). You want a double equals to test equality.
UPDATE
If you really mean to both assign and compare, split it into two lines so it looks like it's intentional. It's a microexample of the "Command / Query Separation Principle."
<% like = current_user.liked(bookmark) %>
<% if like %>
(Sorry this probably doesn't relate directly to your question, but it was very distracting to see.)

Resources