2013-09-26 28 views
0

在我的Rails應用程序中,我有users誰可以有許多projects而這又可以有許多tasks如何限制Rails關聯中的外鍵?

型號:

class Task < ActiveRecord::Base 

    attr_accessible :project_id 

end 

控制器:

class TasksController < ApplicationController 

    def create 
    @task = current_user.tasks.build(params[:task])  
    if @task.save 
     flash[:success] = "Task saved." 
     redirect_to edit_task_path(@task) 
    else 
     render :new 
    end 
    end 

    def update 
    if @task.update_attributes(params[:task]) 
     flash[:success] = "Task updated." 
     redirect_to edit_task_path(@task) 
    else 
     render :edit 
    end 
    end 

end 

什麼是對Rails標準的做法,以確保用戶一個不能爲用戶b創建任務

現在,我通過表單中的選擇框選項來限制用戶可以使用的project_ids。但是,這可以通過瀏覽器控制檯輕鬆入侵,並且不安全。

這怎麼能改進?

感謝您的任何幫助。

回答

1

我會去與一個前過濾器來檢查,如果需要的項目屬於當前用戶:

class TasksController < ApplicationController 
    before_filter :find_project, only: :create 

    def create 
    @task = @project.tasks.build(params[:task])  
    if @task.save 
     flash[:success] = "Task saved." 
     redirect_to edit_task_path(@task) 
    else 
     render :new 
    end 
    end 

    private 

    def find_project 
    @project = current_user.projects.where(id: params[ :task ][ :project_id ]).first 
    redirect_to(root_path, notice: 'No such project') unless @project 
    end 
end 

所以,如果給PROJECT_ID不匹配,屬於當前用戶的一個項目,他將被重定向了。

更軌的方式,雖然是使用嵌套的資源:

resources :projects 
    resources :tasks, shallow: true 
end 

你將不得不像這樣的路線:

GET /projects/1/tasks (index) 
GET /projects/1/tasks/new (new) 
POST /projects/1/tasks (create) 
GET /tasks/1 (show) 
GET /tasks/1/edit (edit) 
PUT /tasks/1 (update) 
DELETE /tasks/1 (destroy) 

但這不會相差太多,你仍然有以檢索帖子:

class TasksController < ApplicationController 
    before_filter :find_project, only: [ :index, :new, :create ] 
    before_filter :find_task, only: [ :show, :edit, :update, :delete ] 

    # other actions 

    def create 
    @task = @project.tasks.build(params[:task])  
    if @task.save 
     flash[:success] = "Task saved." 
     redirect_to edit_task_path(@task) 
    else 
     render :new 
    end 
    end 

    private 

    def find_project 
    @project = current_user.projects.where(id: params[ :project_id ]).first 
    redirect_to(root_path, notice: 'No such project') unless @project 
    end 

    def find_task 
    @task = current_user.tasks.where(id: params[ :id ]).first 
    redirect_to(root_path, notice: 'No such task') unless @task 
    end 
end 
+0

你好奧利弗,這很好,只是測試它。非常感謝你。 – Tintin81

+0

不幸的是,我不能在我的應用程序中使用嵌套的資源。所以我將不得不堅持你提供的第一個解決方案。因爲我是Rails的新手:你能告訴我如何調整我的'update'動作嗎?我不知道如何在那裏獲得'@ project'變量。我認爲從安全的角度來看,在'create'和'update'操作上運行過濾器就足夠了嗎? – Tintin81

1

最簡單的事情是範圍你的查找和利用事實#find可以募集RecordNotFound。 Rails將會拯救這個異常併爲你渲染404。

class TasksController < ApplicationController 
    helper_method :project 

    def create 
    @task = project.tasks.build(params[:task])  
    if @task.save 
     flash[:success] = "Task saved." 
     redirect_to edit_task_path(@task) 
    else 
     render :new 
    end 
    end 

    private 

    def project 
    @project ||= current_user.projects.find(params[:task][:project_id]) 
    end 
end 

我還想補充一點,你還應該在任務的URL範圍內,它屬於它的項目。像使用嵌套資源的/projects/:project_id/tasks/:id

+0

非常感謝。您的解決方案與Olivier所建議的非常相似。所以我想這是要走的路。我只是想知道我是否應該調整我的'更新'行動,以及這將是什麼樣子?不幸的是,我不能在我的應用程序中使用嵌套資源。 – Tintin81