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.)
Related
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
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
After following Michael Hartl's Rails Tutorial I moved the 'micropost feed' from / to /members, and now when I submit a post that doesn't validate properly (too many characters, missing content etc.) rails returns an error saying:
ArgumentError in MicropostsController#create
First argument in form cannot contain nil or be empty
The related interface test error returns:
FAIL["test_micropost_interface", MicropostsInterfaceTest, 2015-06-22 11:13:28 +0800]
test_micropost_interface#MicropostsInterfaceTest (1434942808.57s)
Expected at least 1 element matching "div#error_explanation", found 0..
Expected 0 to be >= 1.
test/integration/microposts_interface_test.rb:19:in `block in <class:MicropostsInterfaceTest>'
How can I fix these errors so user friendly error messages (div#error_explanation) will display correctly?
Supporting info
MembersController:
class MembersController < ApplicationController
before_filter :logged_in_user
def index
#micropost = current_user.microposts.build
#feed_items = current_user.feed.paginate(page: params[:page])
end
end
MicropostsController:
class MicropostsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def create
#micropost = current_user.microposts.build(micropost_params)
if #micropost.save
flash[:success] = "Micropost created!"
# redirect_to root_url
redirect_to members_path
else
#feed_items = []
#micropost = []
render 'members/index'
end
end
def destroy
#micropost.destroy
flash[:success] = "Micropost deleted"
# redirect_to request.referrer || root_url
redirect_to request.referrer || members_path
end
private
def micropost_params
params.require(:micropost).permit(:content, :picture)
end
def correct_user
#micropost = current_user.microposts.find_by(id: params[:id])
# redirect_to root_url if #micropost.nil?
redirect_to members_path if #micropost.nil?
end
end
_micropost_form.html.erb
<%= form_for(#micropost, html: { multipart: true }) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new micropost (420 chars max)..." %>
</div>
<%= f.submit "Post", class: "btn btn-primary" %>
<span class="picture">
<%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %>
</span>
<% end %>
<script type="text/javascript">
$('#micropost_picture').bind('change', function() {
size_in_megabytes = this.files[0].size/1024/1024;
if (size_in_megabytes > 5) {
alert('Maximum file size is 5MB. Please choose a smaller file.');
}
});
</script>
app/models/micropost.rb
class Micropost < ActiveRecord::Base
belongs_to :user
default_scope -> { order(created_at: :desc) }
mount_uploader :picture, PictureUploader
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 420 }
validate :picture_size
private
# Validates the size of an uploaded picture.
def picture_size
if picture.size > 5.megabytes
errors.add(:picture, "should be less than 5MB")
end
end
end
Update
_error_messages.html.erb
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
If you look at the error
First argument in form cannot contain nil or be empty
You can clearly make out from it that the first argument that's #micropost variable is nil. Now move to the controller and see if you have set that variable or not.
In else part of create action, inside microposts you have #micoposts = [], an empty array which is then passed on to your template and causing error.
Fix:
Change create method to this:
def create
#micropost = current_user.microposts.build(micropost_params)
if #micropost.save
flash[:success] = "Micropost created!"
# redirect_to root_url
redirect_to members_path
else
#feed_items = current_user.feed.paginate(page: params[:page])
render 'members/index'
end
end
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.
undefined method avatar?' for nil:NilClass
undefined methodname' for nil:NilClass
Hi, I'm receiving the following errors in my partial. The reason I listed both is because after commenting out the line causing the first error message, I get the second error which leads me to believe the problem isn't with "avatar" or "name" specifically, but with something else,though I don't know what. In rails console, I'm able to call user and name on a comment. I also seeded the database using Faker if that matters. Here's the partial.
<%= content_tag :div, class: 'media', id: "comment-#{comment.id}" do %>
<%= link_to '#', class: 'pull-left' do %>
<%= image_tag(comment.user.avatar.small.url) if comment.user.avatar? %>
<% end %>
<div class="media-body">
<small>
<%= comment.user.name %> commented <%= time_ago_in_words(comment.created_at) %> ago
<% if policy(comment).destroy? %>
| <%= link_to "Delete", [#topic, #post, comment], method: :delete %>
<% end %>
</small>
<p><%= comment.body %></p>
</div>
<% end %>
Also, please see the render.
<div class="col-md-4">
<% if policy(Comment.new).create? %>
<h4>Leave a comment</h4>
<br/>
<%= render partial: 'comments/comment', locals: { topic: #topic, post: #post, comment: #comment } %>
<% end %>
</div>
The below are my user model and comments_controller
class UsersController < ApplicationController
before_filter :authenticate_user!
def update
if current_user.update_attributes(user_params)
flash[:notice] = "User information updated"
redirect_to edit_user_registration_path(current_user)
else
render "devise/registrations/edit"
end
end
private
def user_params
params.require(:user).permit(:name, :avatar)
end
end
Comments_controller
def create
#topic = Topic.find(params[:topic_id])
#post = #topic.posts.find(params[:post_id])
#comments = #post.comments
#comment = current_user.comments.build(comment_params)
#comment.post = #post
#new_comment = Comment.new
authorize #comment
if #comment.save
redirect_to [#topic, #post], notice: "Comment was submitted successfully."
else
flash[:error] = "There was an error submitting the comment. Please try again."
end
end
I've already reset the database, but to no avail. Stuck as to what the issue is. Thanks for your help.
Please see below for my User and Comment models.
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
default_scope { order('created_at DESC') }
validates :body, length: { minimum: 5 }, presence: true
after_create :send_favorite_emails
private
def send_favorite_emails
self.post.favorites.each do |favorite|
if favorite.user_id != self.user_id && favorite.user.email_favorites?
FavoriteMailer.new_comment(favorite.user, self.post, self).deliver
end
end
end
end
User model
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
has_many :votes, dependent: :destroy
has_many :favorites, dependent: :destroy
mount_uploader :avatar, AvatarUploader
def role?(base_role)
role == base_role.to_s
end
def favorited(post)
self.favorites.where(post_id: post.id).first
end
def voted(post)
self.votes.where(post_id: post.id).first
end
private
end
If you're getting
undefined method foo for nil:NilClass
it's that the thing you're calling your method on is nil.
So in your case, you're calling avatar? and name on something nil.
Looking at your code, it's clear comment.user is (a) what those methods are called on, and hence (b) what is nil.
Result: your comment has no user. Either enforce all comments (including new/empty/stub ones) to have an user (blank user?), or make your view so that a user is not necessary.
The issue was discovered. In the partial render
comment: #comment
should be
comment: comment