2016-05-31 31 views
1

我的應用程序是一個減肥應用程序。它使用Devise進行用戶認證。如何讓我只爲相同的配置文件索引?

用戶has_one :profile(配置文件表將user_id保存爲外鍵)存儲像姓,名等數據,並在用戶註冊時自動創建。配置文件has_many :weights(應用程序的用戶應定期權衡自己,並將其新權重存儲在此表中)。到現在爲止還挺好。

我有以下問題: 如果登錄的用戶轉到權重控制器的索引頁,他只能看到他自己的權重。但是,如果此用戶現在更改URL欄中的profile_id,他還可以看到其他配置文件的權重(儘管它不是「他的」配置文件)。此外,他現在可以創建一個新的權重,然後保存另一個profile_id(這顯然不是他自己的)。

我所做的一般是限制用戶編輯或銷燬不擁有自己的profile_id的權重(通過我的weights_controller.rb中的before_action :require_same_weight_profile)。

我現在的問題是:我怎樣才能防止這個用戶(有一定的配置文件)做上述的東西?

我確定答案很簡單(幾個月前我開始編碼)。

UPDATE在此期間,我找到了解決方案。不幸的是,評論中的建議解決方案並不適合我。什麼 工作如下:

我在weights_controller.rb更新

before_action :require_permission 

... 

def require_permission 
    if current_user != Profile.find(params[:profile_id]).user 
    redirect_to root_path 
    end 
end 

的routes.rb

Rails.application.routes.draw do 

    devise_for :users 
    resources :profiles, only: [:index, :show, :edit, :update] do 
    resources :weights 

    end 

profile.rb

class Profile < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :pal 
    has_many :weights, dependent: :destroy 
    belongs_to :goal 
end 

weight.rb

class Weight < ActiveRecord::Base 
    belongs_to :profile 
end 

weights_controller.rb

class WeightsController < ApplicationController 
    before_action :set_profile 
    before_action :load_profile 
    before_action :set_weight, only: [:show, :edit, :update, :destroy] 
    before_action :require_same_weight_profile, only: [:show, :edit, :update, :destroy] 


    # GET /weights 
    # GET /weights.json 
    def index 
    @weights = Profile.find(params[:profile_id]).weights 
    end 

    # GET /weights/1 
    # GET /weights/1.json 
    def show 
    end 

    # GET /weights/new 
    def new 
    @weight = Weight.new(:profile_id => params[:profile_id]) 
    end 

    # GET /weights/1/edit 
    def edit 
    end 

    # POST /weights 
    # POST /weights.json 
    def create 
    @weight = Weight.new(weight_params) 

    respond_to do |format| 
     if @weight.save 
     format.html { redirect_to profile_weights_path, notice: 'Weight was successfully created.' } 
     format.json { render :show, status: :created, location: @weight } 
     else 
     format.html { render :new } 
     format.json { render json: @weight.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # PATCH/PUT /weights/1 
    # PATCH/PUT /weights/1.json 
    def update 
    respond_to do |format| 
     if @weight.update(weight_params) 
     format.html { redirect_to profile_weights_path, notice: 'Weight was successfully updated.' } 
     format.json { render :show, status: :ok, location: @weight } 
     else 
     format.html { render :edit } 
     format.json { render json: @weight.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /weights/1 
    # DELETE /weights/1.json 
    def destroy 
    @weight.destroy 
    respond_to do |format| 
     format.html { redirect_to profile_weights_path, notice: 'Weight was successfully destroyed.' } 
     format.json { head :no_content } 
    end 
    end 

    private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_weight 
     @weight = Weight.find(params[:id]) 
    end 

    def set_profile 
     @profile = Profile.find_by(user_id: params[:id]) 
    end 

    def load_profile 
     @profile = current_user.profile #|| current_user.build_profile 
    end 

    # Never trust parameters from the scary internet, only allow the white list through. 
    def weight_params 
     params.require(:weight).permit(:profile_id, :weight, :weight_day) 
    end 

    # This checks if the current user wants to deal with weights other than his own 
    def require_same_weight_profile 
     if @weight.profile_id != current_user.profile.id 
     flash[:danger] = "You can only edit or delete your own weights" 
     redirect_to profile_weights_path(current_user.profile) 
     end 
    end 
end 

profiles_controller.rb

class ProfilesController < ApplicationController 
    before_action :set_profile, only: [:show, :edit, :update, :destroy] 
    before_action :load_profile 


    # 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 
    end 

    # POST /profiles 
    # POST /profiles.json 
    def create 
    @profile = Profile.new(profile_params) 
    @profile.user = current_user 

    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_by(user_id: params[:id]) 
    end 

    def load_profile 
     @profile = current_user.profile #|| current_user.build_profile 
    end 

    # Never trust parameters from the scary internet, only allow the white list through. 
    def profile_params 
     params.fetch(:profile, {}).permit(:prename, :surname, :birthdate, :gender, :size, :pal_id) 
    end 

end 
+0

你已經完成了應該完成的任務 – emaillenin

+0

@Oliver是否有任何理由權重是配置文件下的嵌套資源?你可以刪除嵌套,只是獲取當前用戶的權重 –

回答

0

您只需確保用戶是他正在觀看的網頁的所有者。這是一個常見的安全問題,你必須知道在每一個應用程序,你讓

def show 
unless @weight.profile_id == current_user.id 
redirect_to '/root' 

end 

如果您的個人資料是私人(配置文件/ 1)僅僅是用戶1,看你需要添加代碼,以及到配置文件控制器。

+0

你在開玩笑嗎?它是一個自我解釋的代碼,我告訴他爲什麼他應該這樣做......我還應該說些什麼? – Boltz0r

+0

@ Boltz0r查看OP的代碼用戶和個人資料並不是一回事,因此您需要根據當前用戶個人資料的ID來檢查體重的個人資料ID。 –

+0

是真的,我的錯誤 – Boltz0r

0

在顯示配置文件之前,您可以添加回調來驗證所有權;如果配置文件不屬於當前用戶,則返回403 Forbidden。

回調可能是這個樣子:

def verify_ownership 
    if @weight.profile.user != current_user 
    render :status => 403 and return 
    end 
end 

使用它添加到您的回調鏈:

before_action :set_weight 
before_action :verify_ownership 

確保調用set_weight在此之前的回調,從而使@weight變量不是nil

您可以爲配置文件本身做一些非常類似的操作:只需將回調更改爲以下內容,並以相同的方式將其添加到回調鏈。

def verify_ownership 
    if @profile.user != current_user 
    render :status => 403 and return 
    end 
end 
+0

Thx很多。不幸的是沒有爲我工作。但發現了一個不同的解決方案(文章中的更新)。 – Oliver

+0

FWIW,這不是一個回調,它是一個過濾器。 –

+0

Thx。我將它改爲before_action。 – Oliver

相關問題