Whenever I try to delete a user I get the error: Couldn't find User with 'id'=8. The error points to a line from application_controller.rb in the "current_user" method: ActiveRecord::RecordNotFound at /users. "/users" is where I'm trying to redirect_to.
I don't know where I'm going wrong. I wonder if it's a <%= javascript_include_tag ... %> that I'm missing in the application.html.erb file.
application_controller.rb
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
users_controller.rb
def delete
#user = User.find(params[:id])
end
def destroy
#user = User.find(params[:id]).destroy
flash[:warning] = '#{#user.name} has been deleted.'
redirect_to users_path
end
sessions_controller.rb
class SessionsController < ApplicationController
def create
user = User.find_by(email: params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
if request.referrer == login_url
redirect_to root_path
else
redirect_to :back
end
else
flash.now[:danger] = "Email and password did not match. Please try again."
render :new
end
end
def destroy
session[:user_id] = nil
flash[:success] = "Logged out."
redirect_to :back
end
end
views/users/show.html.erb
<p id="notice"><%= notice %></p>
<h2 id="page-title"><%= #user.name %> <small>#<%= #user.username %></small>
<div class="small pull-right"></div>
</h2>
<hr/>
<% #user.types.each do |type| %>
<h4><small><%= type.name %></small></h4>
<% end %>
<% if current_user == #user %> # visible to current_user
<div class="float-right">
<%= link_to 'Edit', edit_user_path(#user), class: 'btn btn-default' %>
<%= link_to 'Delete Account', user_path,
data: { confirm: 'Are you sure you want to delete your account forever?' },
method: :delete, class: 'btn btn-danger' %>
</div>
<% end %>
If you need anymore files let me know.
I feel like this is a simple fix. Please help. And thank you in advance!
When you use find with a non existing record id, ActiveRecord throws ActiveRecord::RecordNotFound exception. You can get around this by usingfind_by, which will return nil. so try this in your application_controller.rb
def current_user
#current_user ||= User.find_by(id: session[:user_id])
end
Or you can just use your check more correctly by doing this
def current_user
#current_user ||= (session[:user_id].present? && User.find(session[:user_id]))
end
The second will still raise exception if the user_id in the session is not an invalid user.
Hope that helps
I guess if bug is in application controller add the following code in the destroy method of user controller:
session[:user_id] = nil if current_user == #user
This way if you delete the current connected user, it'll be logged out.
Related
Can anyone help me figure out why I am getting the following error?
When assigning attributes, you must pass a hash as an argument.
The form:
<%= form_for([current_user, current_user.suggestions.build]) do |f| %>
<%= f.label :category %>:
<%= f.select :category, ['Startup', 'Cars', 'Kids', 'Food', 'Other'] %> <br>
<%= f.text_area :suggestion %><br>
<%= f.submit 'Submit Suggestion' %>
<% end %>
SuggestionController:
def create
#suggestion = current_user.suggestions.create(suggestion_params)
end
private
def suggestion_params
params.require(:suggestion).permit(:suggestion, :category)
redirect_to shirts_path
end
ApplicationController:
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
suggestion_params is returning the last line of the method redirect_to shirts_path, which current_user.suggestions.create can't accept because it isn't acceptable data.
The redirect should be in create method:
def create
#suggestion = current_user.suggestions.create(suggestion_params)
redirect_to shirts_path
end
private
def suggestion_params
params.require(:suggestion).permit(:suggestion, :category)
end
I am following along with Michael Hartls tutorial and I am trying to add the destroy action in order to delete users as admin. However, the link is not displaying under users name. I am also using Devise, not sure if that matters. Any help is greatly appreciated. Thanks
Controller/users
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted."
redirect_to users_path
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
_users.html
<li>
<class= "round-image-50"><%= image_tag(current_user.avatar.url(:thumb)) %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
<%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %>
<% end %>
</li>
Routes
devise_for :admins
devise_for :users
resources :posts
resources :users
get "users/show"
get 'feed', to: 'posts#index', as: :feed
get "about" => "pages#about"
root "pages#home"
match 'users/:id' => 'users#show', via: :get
Migration
class AddAdminToUsers < ActiveRecord::Migration
def self.up
add_column :users, :admin, :boolean, :default => false
end
def self.down
remove_column :users, :admin
end
end
I was able to figure it out. The below code needed to go on my user index page instead not the _user.html page. Thank you for your help #Pavan
<% if current_user.admin? && !current_user?(user) %>
<%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %>
<% end %>
I have two failing rpec tests that state that there are two links that are not present. the exact messages are:
Failure/Error: it {should have_link("Sign Out", href: signout_path)}
expected #has_link?("Sign Out", {:href=>"/signout"}) to return true, got false
Failure/Error: it {should have_link("Profile", href: user_path(user))}
expected #has_link?("Profile", {:href=>"/users/1"}) to return true, got false
when I visit the site locally I notice that when I type in the url to a specific user the page comes up but the menu changes do not appear as they should for a signed in user. So I tried signing in as another user and I notice that it does not allow it telling me my user info is invalid. So that leads me to believe that my user authentication is not working properly, but truthfully what do I know since I am still learning. My Code looks like:
application_controller
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
include SessionsHelper
end
sessions_controller
class SessionsController < ApplicationController
def new
#title = "Sign In"
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email or password'
render 'new'
end
end
end
user model
class User < ActiveRecord::Base
before_save { self.email = email.downcase }
before_create :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false}
has_secure_password
validates :password, length: { minimum: 6}
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.digest(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.digest(User.new_remember_token)
end
end
and my sessions_helper
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.digest(remember_token))
self.current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
remember_token = User.digest(remember_token)
#current_user ||= User.find_by(remember_token: remember_token)
end
def signed_in?
!current_user.nil?
end
end
this is the menu change that is supposed to happen when a user is signed in
<header class="navbar navbar-fixed-top navbar-inverse">
<div class="navbar-inner">
<div class="container">
<%= link_to "Sample App", root_path, class: "navbar-brand" %>
<nav>
<ul class="nav navbar-nav navbar-right">
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<% if signed_in? %>
<li><%= link_to "Users", "#" %></li>
<li id="fat-menu" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Account
</a>
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings", "#" %></li>
<li class="divider"></li>
<li><%= link_to "Sign Out", signout_path, method: "delete" %></li>
</ul>
</li>
<% else %>
<li><%= link_to "Sign In", signin_path %></li>
<% end %>
</ul>
</nav>
</div>
</div>
</header>
It's as if my application doesn't see that anyone is signed in. I can post another files needed I will be glad to post. I am just not sure how this isn't working given that no runtime exceptions come up. As always any advice is appreciated.
here is the routes.rb
Rails.application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
root 'static_pages#home'
match '/help', to: 'static_pages#help', via: 'get'
match '/about', to: 'static_pages#about', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
match '/signup', to: 'users#new', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'sessions#destroy', via: 'delete'
the signed_in? method in sessions_helper.rb was mistyped:
!current_user.nil? should have been current_user.nil?.
Also I changed the create method in my sessions controller from:
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email or password'
render 'new'
end
end
to:
def create
user = User.find_by_email(params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email or password'
render 'new'
end
end
these changes have now allowed the application to work as expected.
Everytime I click the "Sign in with Github" button, I get a Page not found. When I try http://127.0.0.1:3000/auth/github/callback
I get an error called OmniAuth::Strategies::OAuth2::CallbackError which says "csrf_detected | CSRF detected" . Here is my code:
initializers/omniauth.rb:
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :github, ENV['GITHUB_ID'], ENV['GITHUB_SECRET'],
:scope => 'user,public_repo',
:redirect_uri => ENV['http://127.0.0.1:3000']
end
routes.rb:
root 'users#new'
get '/auth/:provider/callback' => 'sessions#create'
get '/signout' => 'sessions#destroy', as: :signout
end
views/users/new.html.erb:
<% if current_user %>
<h1> Welcome: </h1>
<h2><%= link_to 'Sign out', signout_path %></h2>
<% else %>
<h2><%= link_to 'Sign in with Github', "/auth/github" %></h2>
<% end %>
sessions_controller.rb:
class SessionsController < ApplicationController
def new
end
def create
auth = request.env["omniauth.auth"]
user = User.where(:provider => auth['provider'], :uid => auth['uid'].to_s).first || User.from_omniauth(auth)
reset_session
session[:user_id] = user.id
redirect_to root_url, :notice => "Signed in!"
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => 'Signed out!'
end
def failure
redirect_to root_url, :alert => "Authentication error: #{params[:message].humanize}"
end
end
user.rb:
class User < ActiveRecord::Base
def self.from_omniauth(auth)
# where(auth.slice(:provider, :uid)).first_or_initialize.tap
create! do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
end
application_controller.rb:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
Please help!
I managed to fix this error by adding scope: 'user:email' to the end of the provider statement in the OmniAuth initializer file.
Rails.application.config.middleware.use OmniAuth::Builder do
provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET'], scope: 'user:email'
end
Error 404 means "File or Directory not found". In other words, the server received and understood your request, and would have been quite willing to fulfil the request, but the data that you asked for doesn't exist.
I'm following the rails-tutorials from Michael Hartl, it's really fun !
but i'm having troubles from upon listing 8.20 and so on.
Cause i guessed i had made a type-o i erased the app and started from scratch again..
The best way to learn is repeat right ?
Well.. also on the second build i got the same error.
> NoMethodError in SessionsController#create
undefined method `[]' for nil:NilClass
Extracted source (around line #7):
6 def create
7 user = User.find_by(email: params[:session][:email].downcase)
8 if user && user.authenticate(params[:session][:password])
9 sign_in user
10 else
after googling for a few hours i tried resetting the db ( drop / create / migrate test:prepare)
i have tried copying pieces of code out of the example (e.g. controllers/helpers/views)
but I cant seem to find the solution.
Here is the code for
session_controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
end
end
session helper:
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def current_user?(user)
user == current_user
end
def sign_out
current_user.update_attribute(:remember_token,
User.encrypt(User.new_remember_token))
cookies.delete(:remember_token)
self.current_user = nil
end
end
User model
class User < ActiveRecord::Base
before_save {self.email = email.downcase }
before_create :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX},
uniqueness: {case_sensetive: false}
has_secure_password
validates :password, length: { minimum: 3 }
def User.new_remember_token
SecureRandom.urlsafe_base64
# SecureRandom.urlsafe_base64
end
def User.encrypt(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.encrypt(User.new_remember_token)
end
end
user controller
class UsersController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.save
flash.now[:succes] = "Welcome to the sample app"
redirect_to #user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
and the user helper
module UsersHelper
# Returns the Gravatar (http://gravatar.com/) for the given user.
def gravatar_for(user, options = { size: 50 })
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
size = options[:size]
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
how can i properly copy-paste the error log ?
Based on the error you're getting, the problem is clearly somewhere in your Users controller:
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
The error is being generated because params[:session] is, in fact, nil. Now the question is, why?
My guess is that you have a typo in your sign_in form, it should be:
<%= form_for(:session, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
Please make sure :session is typed correctly.