acts_as_votable NoMethodError (undefined method `comments' for nil:NilClass): - ruby-on-rails

I'm trying to implement voting on comments within pits in my app and I keep getting a no method error. I've tried rearranging my code a number of different ways to get it to work but its not cooperating. My error in terminal shows this
Parameters: {"pit_id"=>"1", "comment_id"=>"2"}
Pit Load (0.2ms) SELECT "pits".* FROM "pits" WHERE "pits"."id" = ? LIMIT 1 [["id", 1]]
Completed 500 Internal Server Error in 2ms
NoMethodError (undefined method `comments' for nil:NilClass):
app/controllers/comments_controller.rb:22:in `upvote'
Its finding the "pit id" and the "comment id" but something is clearly a bit off. Would somebody with a better understanding of whats going on to point out what that it is. Thanks.
As it is now my code
_comment.html.erb
<div class = "well">
<p>
<strong>Comment:</strong>
<%= comment.body %>
<p>posted by: <%= comment.user.name %></p>
<%= link_to "Upvote", pit_comment_like_path(#pit, comment), method: :put, :remote => true %>
<%= link_to "Downvote", pit_comment_dislike_path(#pit, comment), method: :put, :remote => true %>
</p>
<p>
<%if comment.user == current_user %>
<%= link_to 'Destroy Comment', [#pit, comment],
method: :delete,
data: { confirm: 'Are you sure?' } %>
<% end %>
</p>
</div>
Comments Controller
class CommentsController < ApplicationController
def create
#pit= Pit.find(params[:pit_id])
#comment = #pit.comments.build(comments_params)
#comment.user = current_user
#comment.save
redirect_to pit_path(#pit)
end
def destroy
#pit = Pit.find(params[:pit_id])
#comment = #pit.comments.find(params[:id])
#comment.destroy
redirect_to pit_path(#pit)
end
def upvote
#comment = Pit.find(params[:pit_id])
#comment = #pit.comments.find(params[:id])
#comment.upvote_by current_user
redirect_to pit_path(#pit)
end
def downvote
#comment = Pit.find(params[:pit_id])
#comment = #pit.comments.find(params[:id])
#comment.downvote_by current_user
redirect_to pit_path(#pit)
end
Routes
Rails.application.routes.draw do
devise_for :users, :controllers => { registrations: 'registrations' }
devise_scope :user do
get 'users/sign_in' => 'devise/sessions#new'
get 'users/sign_out' => 'devise/sessions#destroy'
match 'users/:id', to: 'users#show', as: 'user', via: 'get'
end
resources :pits do
resources :comments do
put "like", to: "comments#upvote"
put "dislike", to: "comments#downvote"
end
end
root to: 'pages#home'
get '/about' => 'pages#about'
end
User Class
class User < ActiveRecord::Base
acts_as_voter
has_many :pits
has_many :comments
enum role: [:user, :vip, :admin]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :user
end
def name
name = first_name + ' ' + last_name
end
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Comment Class
class Comment < ActiveRecord::Base
acts_as_votable
belongs_to :pit
belongs_to :user
end

Related

Rails: User can't accept friend request

I'm making my first solo rails project. It's a facebook clone, and at the moment I can't get a user to accept a friend request. Please let me know if the information posted isn't sufficient enough to help work towards an answer.
friend_request_controller.rb
class FriendRequestsController < ApplicationController
before_action :set_friend_request, except: [:index, :create]
def index
#incoming = FriendRequest.where(friend: current_user)
#outgoing = current_user.friend_requests
end
def create
#user = User.find(current_user)
friend = User.find(params[:id])
#friend_request = current_user.friend_requests.new(friend_id: friend)
if #friend_request.save
redirect_to user_path(current_user)
end
end
def update
friend = User.find(params[:id])
#friend_request = current_user.friend_requests.find(friend_id: friend)
#friend_request.accept
end
show.html.erb
Hello my my email is <%= #user.email %>
<% if user_signed_in? %>
<li>
<%= link_to 'Logout', destroy_user_session_path, :method => :delete %></li>
<li><%= link_to 'All Users', users_path %>
</li>
<% else %>
<li>
<%= link_to('Login', new_user_session_path) %>
</li>
<% end %>
<ul>
<% current_user.friend_requests.each do |request| %>
<h4>You have new friend requests from:</h4>
<li>
<%= User.find(request.friend_id).email %>
<%= link_to "Accept", friend_request_path(friend_id: #friend),method:"put" %>
<%= link_to "Decline", "#" %>
</li>
<% end %>
</ul>
I know something is wrong with my link_to helper here
user.rb
class User < ApplicationRecord
has_many :friend_requests, dependent: :destroy
has_many :pending_friends, through: :friend_requests, source: :friend
has_many :friendships, dependent: :destroy
has_many :friends, through: :friendships
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
friend_request.rb
class FriendRequest < ApplicationRecord
belongs_to :user
belongs_to :friend, class_name: 'User'
def accept
user.friends << friend
destroy
end
def destroy
end
end
Do what #araratan has mentioned + in your frined_request controller, replace params[:id] with params[:friend_id].
Instead of:
<%= link_to "Accept", friend_request_path(friend_id: #friend),method:"put" %>
Try to change #friend to request.friend_id:
<%= link_to "Accept", friend_request_path(friend_id: request.friend_id),method:"put" %>

Rails: NoMethodError on creating has_one association with devise model

I am a complete beginner in Rails as such and I am trying to build a page to add extra profile data once the user logs in.
I am using Devise for authentication purposes and that works fine. I get this error and I have been stuck here.
undefined method `profiles'
Can you please help?
Codes
profiles_controller.rb
class ProfilesController < ApplicationController
before_action :authenticate_user!, only: [:new, :create, :show]
def new
#profile = current_user.profiles.build
end
def create
#profile = current_user.profiles.build(profile_params)
if #profile.save
format.html {redirect_to #profile, notice: 'Post was successfully created.'}
else
format.html {render 'new'}
end
end
def show
#profile = current_user.profiles
end
private
def profile_params
params.require(:profile).permit(:content)
end
end
The error seems to be coming from these lines in particular
def new
#profile = current_user.profiles.build
end
Other codes for reference:
/views/profiles/new.html.erb
<h1>Profiles#new</h1>
<p>Find me in app/views/profiles/new.html.erb</p>
<h3>Welcome <%= current_user.email %></h3>
<%= form_for(#profile) do |f| %>
<div class="field">
<%= f.label :content %><br />
<%= f.text_field :text, autofocus: true %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<%end%>
routes.rb
Rails.application.routes.draw do
get 'profiles/new'
get 'profiles/create'
get 'profiles/show'
get 'profiles/update'
get 'pages/home'
get 'pages/dashboard'
devise_for :users, controllers: { registrations: "registrations" }
resources :profiles
root 'pages#home'
devise_scope :user do
get "user_root", to: "page#dashboard"
end
end
models/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
has_one :profile, dependent: :destroy
end
models/profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
end
I just figured it out!
As the relationship is has_one, we should be using
def new
#profile = current_user.build_profile
end
instead of
def new
#profile = current_user.profiles.build
end
according to the documentation -
http://guides.rubyonrails.org/association_basics.html#has-one-association-reference
1) If your user must have many profiles. Set in your app/models/user.rb has_many :profiles
2) In your ProfilesController in new method instead of #profile = current_user.profiles use #profile = Profile.new
3) In your routes.rb delete
get 'profiles/new'
get 'profiles/create'
get 'profiles/show'
get 'profiles/update'
because you have already used resources :profiles
4) To stay with rules of DRY you can render form from a partial. Just add in views/profiles/_form.html.erb with the same content in your new.html.erb and after this you can delete everything im new.htm.erb and paste <%= render "form" %>. In future it will help you to render edit form if you want.
5) In your ProfilesController you can add method index with all profiles
def index
#profiles = Profile.all
end
You are trying to call an undefined relationship:
def new
#profile = current_user.profiles.build
end
has_one :profile
You should be calling:
def new
#profile = current_user.build_profile
end

Acts As Follower doesn't work on front end

I installed Acts_as_follower. I used the methods from the documentation in my console so I've determined that user 1 follows user 2(using devise) in ActiveRecord, and on my front end in the users/show.html.erb page it shows the appropriate follow/unfollow portion of the button I've implemented. Unfortunately whenever I press the follow/unfollow button nothing changes or happens.
I'm thinking it's the routing but wondering if anybody has an idea of why nothing happens. I've confirmed the lack of action from my console.
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
acts_as_followable
acts_as_follower
has_attached_file :image, :styles => { :medium => "300x300>", :thumb=> "100x100>" }
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
has_many :articles
has_many :comments
end
routes.rb
Rails.application.routes.draw do
devise_for :users
resources :articles do
member do
put "Like", to: "articles#upvote"
put "Disike", to: "articles#downvote"
end
resources :comments
end
resources :users do
get :follow
get :unfollow
end
root 'welcome#index'
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#user_articles = #user.articles
end
def create
#user = User.find(params[:user_id])
current_user.follow(#user)
end
def destroy
#user = User.find(params[:user_id])
current_user.stop_following(#user)
end
end
followers_controller.rb
class FollowsController < ApplicationController
before_action :authenticate_user!
respond_to :js
def create
#user = User.find(params[:user_id])
current_user.follow(#user)
end
def destroy
#user = User.find(params[:user_id])
current_user.stop_following(#user)
end
end
The button in users/show.html.erb
<div class="follow">
<% if #user.followed_by?(current_user) %>
<%= form_tag user_unfollow_path(user_id: #user.id), method: :post, remote: true do %>
<center><%= button_tag 'unfollow', class: 'btn btn-primary' %></center>
<% end %>
<% else %>
<%= form_tag user_follow_path(user_id: #user.id), method: :post, remote: true do %>
<center><%= button_tag 'follow', class: 'btn btn-success' %></center>
<% end %>
<% end %>
</div>
</div>
Your suspicion is correct, this is indeed a routing issue. But you get an A for effort as the documentation doesn't discuss the front end, good on you for getting this far :)
Your routes should look more like:
resources :users do
post :follow, to: "#followers#create"
delete :unfollow, to: "followers#destroy"
end
Note that unfollow is calling destroy, so by convention it's delete, also by convention create should be post.
Given that, make sure your view will look like:
<div class="follow">
<% if #user.followed_by?(current_user) %>
<%= form_tag user_unfollow_path(user_id: #user.id), method: :delete, remote: true do %>
<center><%= button_tag 'unfollow', class: 'btn btn-primary' %></center>
<% end %>
<% else %>
<%= form_tag user_follow_path(user_id: #user.id), method: :post, remote: true do %>
<center><%= button_tag 'follow', class: 'btn btn-success' %></center>
<% end %>
<% end %>
</div>

Trying to prevent non admins from signing up for admin

I have a simple blog and I only want admin access to the create admin options and view. I have installed Devise and used authenticate_admin! in my controllers but when I test it out, the page is still accessible and allows anyone to sign out for admin options. I have limited options to the admin once signed in. The problem is that anyone can sign in. If I can basically just prevent access to the admin sign up page then I'm golden. At least in this case. I'm curious if somebody can point out my error or errors. Let me know if you need anything else. Thanks
class AdminsController < ApplicationController
before_action :authenticate_admin!
def index
end
def created
end
end
Articles Controller
class ArticlesController < ApplicationController
before_action :authenticate_admin!, :except => [:index, :show]
def new
#article = Article.new
end
def index
#article = Article.all
#articles = Article.order('created_at DESC')
#articles_by_month = Article.find(:all, :order => 'created_at DESC').group_by { |article| article.created_at.strftime("%B %Y") }
end
def month_count
#articles_by_month = Article.find(:all, :order => 'created_at DESC').group_by { |article| article.created_at.strftime("%B %Y") }
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def show
#article = Article.find(params[:id])
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text, :image)
end
end
Articles Index view
<div class="bit-75">
<% #article.each do |article| %>
<h2 id="title"><%= link_to article.title, article_path(article) %></h2>
<br>
<ul id="article-links">
<div id="article-image"><%= image_tag article.image_url %></div>
<br>
<li id="article-text"><%= article.text %></li>
<p>Posted on <%= article.created_at %></p>
<br>
<% if admin_signed_in? %>
<li><%= link_to 'Edit', edit_article_path(article) %></li>
<li><%= link_to 'Destroy', article_path(article),
method: :delete, data: { confirm: 'Are you sure?'} %></li>
<li><%= link_to 'New article', new_article_path %></li>
<% else %>
<li><%= link_to 'Make a Comment', article_path(article) %><p>Comments(<%= article.comments.count %>)</p></li>
</ul>
<% end %>
<% end %>
<div id="new-article-path"></div>
</div>
<div class="bit-5">
<h2>Recent Posts</h2>
<br>
<% #article.each do |article| %>
<ul id="recent-article">
<li><%= link_to article.title, article_path(article) %></li>
</ul>
<% end %>
<br>
<br>
<h2>Archives</h2>
<% #articles_by_month.each do |monthname, articles| %>
<h4 id="month-archive"><%=link_to monthname, archives_path %></h4>
<% end %>
<!-- <h2>Tags</h2> -->
</div>
Admin model
class Admin < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Article Model
class Article < ActiveRecord::Base
has_many :comments, dependent: :destroy
validates :title, presence: true,
length: { minimum: 5 }
mount_uploader :image, ImageUploader
default_scope -> { order('created_at DESC') }
end
Routes
Blog::Application.routes.draw do
devise_for :admins
devise_scope :admin do get "/admins/sign_out", to: 'devise/sessions#destroy'
end
devise_scope :admin do
get "/admins/sign_in", to: "devise/sessions#new"
end
devise_for :users
root 'articles#index'
resources :articles do
resources :comments
end
get "welcome/index"
match '/about', to: 'static_pages#about', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
match '/archives', to: 'archives#index', via: 'get'
You can remove registerable in your Admin model to prevent people from signing up as an admin:
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable
but having devise_for :admins and then :users hints that it may be time for you to look into using a permission management gem like CanCanCan.

Getting a NoMethodError in Users#show undefined method `name' for nil:NilClass when implementing self-referential association

I've followed RyanB's railcast 163 on self-referential association to the letter, but I keep getting the following error:
NoMethodError in Users#show
Showing /Users/markwalker/welcomepie/app/views/shared/_suggested_connections.html.erb where line #6 raised:
undefined method `name' for nil:NilClass
Extracted source (around line #6):
3: <ul>
4: <% for friendship in #user.friendships %>
5: <li>
6: <%= h friendship.friend.name %>
7: (<%= link_to "remove", friendship, :method => :delete %>)
8: </li>
9: <% end %>
Here is my view (it is a partial that is rendered in the Users/show page):
<div class="span5">
<div class="MemberDisplay">
<ul>
<% for friendship in #user.friendships %>
<li>
<%= h friendship.friend.name %>
(<%= link_to "remove", friendship, :method => :delete %>)
</li>
<% end %>
</ul>
</div>
</div>
My friendship model:
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => 'User'
attr_accessible :friend_id, :user_id
end
My Friendships controller:
class FriendshipsController < ApplicationController
def create
#friendship = current_user.friendships.build(:friend_id => params[:friend_id])
if #friendship.save
flash[:notice] = "Added friend."
redirect_to root_url
else
flash[:error] = "Unable to add friend."
redirect_to root_url
end
end
def destroy
#friendship = current_user.friendships.find(params[:id])
#friendship.destroy
flash[:notice] = "Removed friendship."
redirect_to current_user
end
end
My User model:
class User < ActiveRecord::Base
has_many :friendships
has_many :friends, :through => :friendships
rolify
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :role_ids, :as => :admin
attr_accessible :name, :email, :password, :password_confirmation, :remember_me
attr_accessible :occupation_list, :gender_list, :moving_from_list, :moving_to_list, :family_type_list, :age_bracket_list, :interest_list, :about_me, :username, :avatar
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }
acts_as_taggable
acts_as_taggable_on :occupation, :gender, :moving_from, :moving_to, :family_type, :age_bracket, :interests
scope :by_join_date, order("created_at DESC")
private
def self.tag_tokens(query)
tags = User.categories.where("name like ?", "%#{query}%")
if tags.empty?
[{id: "#{query}", name: "#{query}"}]
else
tags
end
end
end
My users_controller:
class UsersController < ApplicationController
before_filter :authenticate_user!
def index
authorize! :index, #user, :message => 'Not authorized as an administrator.'
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
redirect_to users_path, :notice => "Welcome to WelcomePie!"
else
redirect_to new_users_path, :alert => "Please try signing up again"
end
end
def edit
end
def update
authorize! :update, #user, :message => 'Not authorized as an administrator.'
#user = User.find(params[:id])
if #user.update_attributes(params[:user], :as => :admin)
redirect_to user, :notice => "User updated."
else
redirect_to user, :alert => "Unable to update user."
end
end
def destroy
authorize! :destroy, #user, :message => 'Not authorized as an administrator.'
user = User.find(params[:id])
unless user == current_user
user.destroy
redirect_to users_path, :notice => "User deleted."
else
redirect_to users_path, :notice => "Can't delete yourself."
end
end
def find_tags
#tags = Video.tag_tokens(params[:q])
respond_to do |format|
format.html
format.json { render json: #tags }
end
end
end
And my routes:
Welcomepie::Application.routes.draw do
resources :friendships
authenticated :user do
root :to => 'home#index'
end
root :to => "home#index"
devise_for :users, :controllers => { :registrations => :registrations }
resources :users
end
Does anyone have ideas about why it won't recognise friendship.friend.name? I think it has something to do with Devise, but I just can't work it out.
Thanks for any help!!
You should set :foreign_key in your Friendship model
class Friendship < ActiveRecord::Base
belongs_to :user, :foreign_key => :user_id
belongs_to :friend, :class_name => 'User', :foreign_key => :friend_id
attr_accessible :friend_id, :user_id
end
The issue was actually in the index view, even though the error was occurring in the show view.
The problem was that when I added a friend, their ID wasn't being set, it was being set to zero. It may be something to do with the tutorial being older rails syntax. Anyway, for mine to work I needed to add .id to user for it to correctly set an id, as below:
<% if user_signed_in? %>
<h3>Welcome back <%= current_user.name %>!</h3>
<% else %>
<h3>Please sign up <%= link_to 'here', new_user_registration_path %></h3>
<% end %>
<% #users.each do |user| %>
<p>User: <%=link_to user.name, #user %>
<%= link_to "Add as friend", friendships_path(:friend_id => user.id), :method => :post %> </p>
<% end %>

Resources