I am using devise and devise_ldap for my rails authentication. I am trying to use the built in helper, current user to display the users email on the welcome page of my application.
This is the code that I have tried to use to:
<% if user_signed_in? %>
<div>Signed in as... <%= current_user.email %></div>
<% end %>
when I sign in to the application, I get the error;
undefined method `email' for nil:NilClass
Here is my routes.rb
Rails.application.routes.draw do
devise_for :users
resources :users
resources :systems do
member do
get :targets, :sources
end
root 'systems#index'
end
and my users controller:
class UsersController < ApplicationController
authorize_resource
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
def index
#users = User.all.order("display_name asc")
end
# GET /users/1
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /stories/1/edit
def edit
respond_to do |format|
format.html
format.js
end
end
# POST /stories
def create
#user = User.new(user_params)
respond_to do |format|
puts 'user controller'
if #user.save!
format.html { redirect_to user_path(#user), notice: 'User was successfully created.' }
else
format.html { render :new }
end
end
end
# PATCH/PUT /stories/1
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to user_path(#user), notice: 'User was successfully updated.' }
else
format.html { render :edit }
end
end
end
# DELETE /stories/1
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_path notice: 'User was successfully destroyed.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:display_name, :email, :username)
end
end
my users model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
before_create :rememberable_value
before_save :get_ldap_values
devise :ldap_authenticatable, :rememberable, :trackable, :validatable
def get_ldap_values
if self.username
self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first if Devise::LDAP::Adapter.get_ldap_param(self.username,"mail")
self.display_name = Devise::LDAP::Adapter.get_ldap_param(self.username,"displayName").first if Devise::LDAP::Adapter.get_ldap_param(self.username,"displayName")
end
end
# def role?(role)
# return !!self.roles.find_by_name(role.to_s.camelize)
# end
def email_required?
false
end
def email_changed?
false
end
def rememberable_value
self.remember_token ||= Devise.friendly_token
end
def name_to_display
if self.display_name
self.display_name
else
self.username
end
end
def password_required?
false
end
def password_match?
self.errors[:password] << "can't be blank" if password.blank?
self.errors[:password_confirmation] << "can't be blank" if password_confirmation.blank?
self.errors[:password_confirmation] << "does not match password" if password != password_confirmation
password == password_confirmation && !password.blank?
end
end
I am not sure what I am missing to be able to access the current users information after a successful sign in.
Update
Here is the new routes file:
Rails.application.routes.draw do
devise_scope :user do
get '/users/sign_out' => 'devise/sessions#destroy'
get "/users/sign_in" => "devise/sessions#new"
# delete "/logout" => "devise/sessions#destroy"
end
devise_for :users
authenticate(:user) do
resources :users
resources :reports
resources :change_logs, only: [:index, :show]
resources :systems do
member do
get :targets, :sources
end
resources :change_logs, module: :systems
resources :components do
resources :change_logs, module: :components
end
resources :c_relations
end
resources :integrations
get '/static_pages/home' # => 'static_pages#home', as: 'home'
root 'systems#index'
end
In routes.rb you should enclose the rows following
devise_for :users
in a block
authenticate(:user) do
resources :users
[...]
end
The problem was that I had overridden the devise mapping and current_user. I removed them and was able to access current user in my views.
Do you have before_action :authenticate_user! in your controller chain at all?
Current_user could be nil after signin is if you aren't asking devise to authenticate the action.
Related
I am new in Ruby on Rails.
I want to run http://localhost:3000/admin/users to see users index page.
But when I run this link, it guide me to http://localhost:3000/admin/login.
Is there something wrongs with my route setting?
Rails.application.routes.draw do
get 'users/new'
get 'users/show'
if Rails.env.development?
mount LetterOpenerWeb::Engine, at: '/letter_opener'
end
root to: 'helps#top'
# admin login
get 'admin/login', to: 'admin/login#index', as: 'admin/login'
get 'admin/logout', to: 'admin/login#logout'
post 'admin/login/login'
get 'admin', to: 'admin/projects#index', as: 'admin_top'
namespace :admin do
resources :users, only: %i(index new create)
resources :projects do
resources :project_users
resources :project_comments
end
resources :images
resources :categories
resources :campanies
end
end
users_controller.rb
class Admin::UsersController < AdminController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
#users = User.all
end
def show
end
def new
#user = User.new
end
def edit
end
#Post /admin/projects
def create
#user = User.new(user_params)
if #user.save
flash[:notice] = 'User saved successfully'
redirect_to :back
else
flash[:alert] = #user.errors
binding.pry
render :new
end
end
def update
end
def destroy
end
private
def set_user
#user = User.find(params [:id])
end
def user_params
params.require(:user).permit(:campany_id, :name, :email, :password_digest, :profile, :prefecture_id, :address)
end
end
Thank you!
Your UsersControllers is under the admin namespace, that's to say you must be logged in order to access to this.
If you want to have access without validating the user is currently logged in, then you'll have to remove the constraint or verification to the controller or to make a new controller and index method which point to /admin/users but this time without the user verification.
That's:
# app/controllers/users_controller.rb
class UsersController < ApplicationController
...
def index
#users = User.all
end
...
end
# config/routes.rb
get '/users', to: 'users#index'
'/users' or '/admin/users' as you want to do it, but if you use the last one then any person must infer that's a restricted resource .
I'm trying to create a way for users to review other users.
When I try going on www.site.com/users/1/reviews/new , i get redirected to my homepage with 'resource not found'. I'm guessing it has to do with my routes?
routes.rb
Rails.application.routes.draw do
devise_for :users,
:controllers => { registrations: 'registrations',
omniauth_callbacks: 'omniauth_callbacks'} #<-- that thing is for STRIPE!
#STRIPE
resources :charges
#MAILBOXER
resources :conversations, only: [:index, :show, :destroy] do
member do
post :reply
post :restore
post :mark_as_read
end
collection do
delete :empty_trash
end
end
resources :messages, only: [:new, :create]
#user reviews (THE PROBLEM)
resources :users do
resources :reviews
end
#categories associatoin
resources :categories, except: [:destroy]
root 'home#index'
get 'profile', to: 'users#show'
end
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,
:omniauthable
#Categories association stuff
has_many :user_categories
has_many :categories, through: :user_categories
#user review association stuff
has_many :reviews
acts_as_messageable
def mailboxer_email(object)
email
end
end
review.rb
class Review < ActiveRecord::Base
belongs_to :user
end
reviews_controller.rb
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :edit, :update, :destroy]
before_action :set_user
before_action :authenticate_user!
# GET /reviews
# GET /reviews.json
def index
#reviews = Review.all
end
# GET /reviews/1
# GET /reviews/1.json
def show
end
# GET /reviews/new
def new
#review = Review.new
end
# GET /reviews/1/edit
def edit
end
# POST /reviews
# POST /reviews.json
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
#review.user_id = #user.id
end
# PATCH/PUT /reviews/1
# PATCH/PUT /reviews/1.json
def update
respond_to do |format|
if #review.update(review_params)
format.html { redirect_to #review, notice: 'Review was successfully updated.' }
format.json { render :show, status: :ok, location: #review }
else
format.html { render :edit }
format.json { render json: #review.errors, status: :unprocessable_entity }
end
end
end
# DELETE /reviews/1
# DELETE /reviews/1.json
def destroy
#review.destroy
respond_to do |format|
format.html { redirect_to reviews_url, notice: 'Review was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_review
#review = Review.find(params[:id])
end
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def review_params
params.require(:review).permit(:rating, :comment)
end
end
def set_user
#user = User.find(params[:id])
end
should be:
def set_user
#user = User.find(params[:user_id])
end
I have set up users with devise and each user can select a role. What I am trying to do is allow admins to be able to edit any user on the site if they have role admin. I currently have a UsersController setup like this:
class UsersController < ApplicationController
before_filter :authenticate_user!, only: [:index, :new, :edit, :update, :destroy]
skip_before_filter
def index
#users = User.order('created_at DESC').all
end
def show
#user = User.friendly.find(params[:id])
#users_authors = User.all_authors
end
# get authors index in here
def authors
end
def create
#user = User.create(user_params)
end
def edit
#user = User.find(params[:id])
end
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
if #user.destroy
redirect_to users_url, notice: "User deleted."
end
end
private
def user_params
params.require(:user).permit(:avatar, :email, :name, :biography, :role_id, :book_id, :username, :password, :password_confirmation)
end
end
This is trying to create a CRUD to edit users which works but I need to be able to populate the forms in the users/edit view wityh the correct selected users details. I my devise controller I have this setup:
class Admin::UsersController < Admin::BaseController
helper_method :sort_column, :sort_direction
before_filter :find_user, :only => [:edit, :update, :show, :destroy]
def index
#q = User.search(params[:q])
#users = find_users
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to admin_users_path, :notice => "Successfully created user."
else
render :new
end
end
def show
end
def edit
#user = User.find(params[:id])
end
def update
if #user.update_attributes(user_params)
redirect_to admin_users_path, :notice => "Successfully updated user."
else
render :edit
end
end
def destroy
#user.destroy
redirect_to admin_users_path, :notice => "User deleted."
end
protected
def find_user
#user = User.find(params[:id])
end
def find_users
search_relation = #q.result
#users = search_relation.order(sort_column + " " + sort_direction).references(:user).page params[:page]
end
def sort_column
User.column_names.include?(params[:sort]) ? params[:sort] : "created_at"
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : "desc"
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:email,:username,:name,:biography,:role_id,:book_id,:role_name,:password,:password_confirmation,:encrypted_password,:reset_password_token,:reset_password_sent_at,:remember_created_at,:sign_in_count,:current_sign_in_at,:last_sign_in_at,:current_sign_in_ip,:last_sign_in_ip)
end
end
For clarity here is the user model:
class User < ActiveRecord::Base
belongs_to :role
has_many :books, dependent: :destroy
has_many :ideas, dependent: :destroy
accepts_nested_attributes_for :books
accepts_nested_attributes_for :ideas
def confirmation_required?
false
end
extend FriendlyId
friendly_id :username, use: [:slugged, :finders]
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_attached_file :avatar, styles: {
large: "600x450#",
medium: "250x250#",
small: "100x100#"
}, :default_url => "/images/:style/filler.png"
#validates_attachment_content_type :avatar, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
validates :avatar, :email, :username, :password, presence: true
def self.all_authors
User.select('users.id, users.username, users.role_id AS USER_ROLE')
.joins(:role).where(users: {role_id: '2'})
end
before_create :set_default_role
private
def set_default_role
self.role ||= Role.find_by_name('Admin')
end
end
In my routes I added a new route for users below the devise users resource as suggested on devise wiki like so:
devise_for :users, :path_prefix => 'my', :path_names => { :sign_up => "register" }
namespace :admin do
resources :users
end
Can anyone help with adding the ability of admins being able to edit all users here, I think its right but I cannot get the correct data into the forms in edit, it uses the current logged users details only.
A first draft for your ability.rb would be:
class Ability
include CanCan::Ability
def initialize(user)
# ...
if user.admin?
can :manage, User
end
# ...
end
end
And then in your user's controller remove the before_filter :find_user, :only => [:edit, :update, :show, :destroy] and related method, and use
load_and_authorize_resource :user
That would load the user from the URL and authorize! it using CanCan. You'll also need to handle the CanCan::AccessDenied exception for non-admin users visiting those pages, but that is another question that you can check in the CanCan docs.
When you visit admin_users_path routes you'll be able to CRUD them if you have the views ready and working.
I am using Ruby on Rails and utilized devise for my log in and registration. After signing up, I get this error message:
NoMethodError in Devise::SessionsController#create undefined method profile_path' for #<Devise::SessionsController:0x007f9425b1f9c0>
I used rails generate scaffold profile and have the following code:
profiles_controller.rb
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
def profile
end
# GET /profiles
# GET /profiles.json
def index
#profiles = Profile.all
end
# GET /profiles/1
# GET /profiles/1.json
def show
end
# GET /profiles/new
def new
#profile = Profile.new
end
# GET /profiles/1/edit
def edit
#profile = Profile.find_by user_id: current_user.id
#attributes = Profile.attribute_names - %w(id user_id created_at updated_at)
end
# POST /profiles
# POST /profiles.json
def create
#profile = Profile.new(profile_params)
respond_to do |format|
if #profile.save
format.html { redirect_to #profile, notice: 'Profile was successfully created.' }
format.json { render :show, status: :created, location: #profile }
else
format.html { render :new }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /profiles/1
# PATCH/PUT /profiles/1.json
def update
respond_to do |format|
if #profile.update(profile_params)
format.html { redirect_to #profile, notice: 'Profile was successfully updated.' }
format.json { render :show, status: :ok, location: #profile }
else
format.html { render :edit }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
# DELETE /profiles/1
# DELETE /profiles/1.json
def destroy
#profile.destroy
respond_to do |format|
format.html { redirect_to profiles_url, notice: 'Profile was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_profile
#profile = Profile.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def profile_params
params[:profile]
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
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :name
devise_parameter_sanitizer.for(:account_update) << :name
end
def after_sign_in_path_for(resource)
profile_path(resource)
end
def after_sign_up_path_for(resource)
profile_path(resource)
end
end
profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
end
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_many :pins, dependent: :destroy
validates :name, presence: true
has_one :profile
before_create :build_profile #creates profile at user registration
end
routes.rb
Rails.application.routes.draw do
resources :profiles, only: [:edit]
resources :pins
devise_for :users
#devise_for :installs
root "pins#index"
get "about" => "pages#about"
Thanks.
You need to use the plural: profiles_path rather than profile_path, in application_controller.rb.
I'm having some trouble implementing one last step in my pundit authorizations...I have a projects model as well as a project_policy that authorizes which users in the app can view and interact w/ the project. However, my projects have several components - one of which is an index of project versions that is accessed within the project (a project has_many versions)...so I need to be able to restrict users access to this list of versions as well... along with the default project profile (I restrict if a users is not an owner/admin or collaborator). I currently have these 'versions', however, setup in their own model.
Details: Currently if I am not an admin/owner or collaborator, the restrictions work when I try to access the url projects/20 (it will redirect me and say "you're not authorized"), but if i navigate to 'projects/20/versions' or 'projects/20/versions/1' or 'projects/20/versions/new' it does not restrict me. Do I need to create a new version_policy for this or can i just restrict this within the project_policy since technically the versions are a part of the project? & what would the code look like that I need to add?
My code is as follows - thanks in advance for any and all help...
PROJECT_POLICY.RB
class Scope < Struct.new(:user, :scope)
end
def update?
user.project_admin? or user.project_collaborator?
end
# method used in projects controller, (study pundit docs)
def visit?
if project.is_private?
user.project_admin?(project) || user.project_owner?(project) || user.project_collaborator?(project)
else
true
end
end
def main_profile?
true
end
def projectversions?
user.project_admin?(project) || user.project_owner?(project)
end
def settings?
user.project_admin?(project) || user.project_owner?(project)
end
def collaboration?
user.project_admin?(project) || user.project_owner?(project)
end
def invite_admin?
user.project_admin?(project) || user.project_owner?(project)
end
def invite_collaborator?
user.project_admin?(project) || user.project_owner?(project)
end
end
PROJECT.RB (PROJECTS MODEL)
class Project < ActiveRecord::Base
...
...
has_many :versions, dependent: :destroy
validates :title, presence: true, length: { maximum: 100 }
validates :background, presence: true
validates :user_id, presence: true
default_scope -> { order('created_at DESC') }
def user_name
owner.try(:name)
end
def user_name=(name)
self.user = User.find_by_name(name) if name.present?
end
def private?
self.is_private == true
end
def public?
self.is_private == false
end
end
PROJECTS_CONTROLLER.RB
class ProjectsController < ApplicationController
before_filter :signed_in_user, only: [:create, :new, :edit, :update]
# Creates redirect and alert when pundit sees someone is not authorized (via :not_authorized_in_project below)
rescue_from Pundit::NotAuthorizedError, :with=>:not_authorized_in_project
def new
#project = Project.new
end
def show
#project = Project.find(params[:id])
authorize #project, :visit?
#user = User.where(:id => #project.user_id).first
rescue Pundit::NotAuthorizedError
flash[:danger] = "You are not authorized to access this page."
redirect_to projects_path || root_path
end
def create
#project = current_user.own_projects.build(project_params)
if #project.save
flash[:success] = "Welcome to your new project."
redirect_to #project
else
render 'new'
end
end
def update
#project = Project.find(params[:id])
if #project.update_attributes(project_params)
flash[:success] = "Project Created"
redirect_to #project
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "Project destroyed"
redirect_to users_path
end
def projectadmins
#title = "Project Admins"
#project = Project.find(params[:id])
authorize #project, :visit?
#projects = #project.projectadmins.paginate(page: params[:page])
render 'show_projectadmin_project'
rescue Pundit::NotAuthorizedError
flash[:danger] = "You are not authorized to access this page."
redirect_to projects_path || root_path
end
def projectversions
*# If I should place the authorizations in this controller...What code should go here? And how would I also restrict the new/show actions for projects/versions i.e, 'projects/20/versions/new', etc?*
end
def settings
#project = Project.find(params[:project_id])
authorize #project
render 'settings'
end
private
def project_params
params.require(:project).permit(:title, :background, :is_private)
end
# USED FOR PUNDIT REDIRECT & ALERT FLASH WHEN SOMEONE IS NOT AUTHORIZED TO ACCESS SOMETHING
def not_authorized_in_project
flash[:danger] = "You are not authorized to access this page."
redirect_to project_path(#project) || root_path
end
end
ROUTES.RB
ProductionApp::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :projects do
resources :versions
match '/settings'=>'projects#settings', :via=>:get, :as=>:settings
match '/collaboration'=>'projects#collaboration', :via=>:get, :as=>:collaboration
match '/invite_admin'=>'projects#invite_admin', :via=>:patch, :as=>:invite_admin
match '/invite_collaborator'=>'projects#invite_collaborator', :via=>:patch, :as=>:invite_collaborator
get :autocomplete_user_name, :on=>:collection
end
resources :versions do
resources :users
end
resources :projects do
member do
get :projectadmins
end
end
resources :admin_relationships, only: [:create, :destroy]
resources :collaborator_relationships, only: [:create, :destroy]
# get "static_pages/home"
# get "static_pages/help"
# get "static_pages/about"
end
much appreciated...let me know if anything else I missed would be helpful to see.