Tana
Tana

Reputation: 31

Devise doesn't control the exact id to edit a user

I installed devise in a rails app. If a user is log in he could access to every other users edit pages.

For example, i'm user_id 2, i can edit profile of user 1/3/4/5.....when i modify params manually in the route.

Here my App Controller :

class ApplicationController < ActionController::Base
  protect_from_forgery
  before_action :authenticate_user!

  before_action :configure_permitted_parameters, if: :devise_controller?

  def configure_permitted_parameters
    # For additional fields in app/views/devise/registrations/new.html.erb
    devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, :company, :position, :office_phone, :mobile_phone, :address, :description, :radius, :photo_company_logo, :photo_presentation, photos_projet_1: [], photos_projet_2: [], photos_projet_3: [], photos_projet_4: []])

    # For additional in app/views/devise/registrations/edit.html.erb
    devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :last_name, :company, :position, :office_phone, :mobile_phone, :address, :description, :radius, :photo_company_logo, :photo_presentation, photos_projet_1: [], photos_projet_2: [], photos_projet_3: [], photos_projet_4: []])
  end
end

Here my User Controller :

class UsersController < ApplicationController

  skip_before_action :authenticate_user!, only: [:index, :show]
  before_action :set_user, only: [:show, :edit, :update]

  def index
    @client = Client.new

    @users = User.all
    @users = User.where.not(latitude: nil, longitude: nil)

    @hash = Gmaps4rails.build_markers(@users) do |user, marker|
      marker.lat user.latitude
      marker.lng user.longitude
    end

  end

  def show
    @client = Client.new
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    @user.save

    redirect_to users_path
  end


  def edit
     @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])
    @user.update(user_params)

    redirect_to user_path(@user)
  end


  private

  def user_params
    params.require(:user).permit(:company, :first_name, :last_name, :position, :mobile_phone, :office_phone, :email, :address, :description, :radius, :nettoyage_toiture, :photo_company_logo, :photo_presentation, photos_projet_1: [], photos_projet_2: [], photos_projet_3: [], photos_projet_4: [])
  end

  def set_user
    @user = User.find(params[:id])
  end

end

Here mu User model :

class User < ApplicationRecord
  has_attachment :photo_presentation
  has_attachment  :photo_company_logo
  has_many :projects, dependent: :nullify
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable
  #geocoder for google maps
  geocoded_by :address
  after_validation :geocode, if: :address_changed?
end

Here my routes :

Rails.application.routes.draw do
  ActiveAdmin.routes(self)
  devise_for :users
  root to: 'pages#home'
  resources :users do
    resources :projects
  end
  resources :clients, only: [:new, :create, :show]
  mount Attachinary::Engine => "/attachinary"
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

Thanks a lot!

Upvotes: 0

Views: 361

Answers (2)

Greg Answer
Greg Answer

Reputation: 717

The problem is this:

def edit 
  @user = User.find(params[:id])
end

def update
  @user = User.find(params[:id])
  @user.update(user_params)

  redirect_to user_path(@user)
end

If you don't want to users to be able to edit other users then you don't need these 2 methods. You can also change your route file to:

resources :users, except: [:edit, :update] do
  resources :projects
end

Update

If you make the previous edits and type rake routes in the terminal, you should see that Devise provides a controller action for editing users. It should be users/edit without the :id param. In the Devise::RegistrationsController, the edit method should just use the current_user helper method for editing the currently logged in user's account information.

If you do want admin user's to be able to edit other users then you'll want to read about one of the following Gems

  1. Can Can
  2. Pundit

With these gems you can define which user "roles" are allowed to edit other users based on their roles. You can also use these gems to give permission to create, read, update, delete other resources.

Upvotes: 1

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230296

Devise is an authentication library. You have authorization problem. So, you should use something for the authorization. I use CanCan. With it, you can define privileges like this:

 can :edit, User, id: current_user.id

If you don't want to learn another library, you can always do ghetto-authorization in your controllers.

class UsersController
  before_action :can_edit_only_self, only: [:edit, :update, :destroy]

  private

  def can_edit_only_self
    redirect_to root_path unless params[:id] == current_user.id
  end
end

* authentication - I know who you are

* authorization - I know what you are allowed to do

Upvotes: 1

Related Questions