如何在Rails的更新控制器操作中限制外键?

时间:2013-09-27 15:28:50

标签: ruby-on-rails ruby ruby-on-rails-3 activerecord associations

在我的Rails应用中,我有invoices,而projects可以有很多class Invoice < ActiveRecord::Base attr_accessible :project_id end

模型:

class InvoicesController < ApplicationController

  before_filter :authorized_user, :only => [ :show, :edit, :destroy ]
  before_filter :authorized_project, :only => [ :create, :update ]

  def create # safe
    @invoice = @project.invoices.build(params[:invoice])  
    if @invoice.save
      flash[:success] = "Invoice saved."
      redirect_to edit_invoice_path(@invoice)
    else
      render :new
    end
  end

  def update # not safe yet
    if @invoice.update_attributes(params[:invoice])
      flash[:success] = "Invoice updated."
      redirect_to edit_invoice_path(@invoice)
    else
      render :edit
    end
  end

  private

    def authorized_user
      @invoice = Invoice.find(params[:id])
      redirect_to root_path unless current_user?(@invoice.user)
    end

    def authorized_project
      @project = Project.find(params[:invoice][:project_id])
      redirect_to root_path unless current_user?(@project.user)
    end

end

控制器:

invoice

我最担心的是恶意用户有一天可能会创建属于另一个用户的project的{​​{1}}。

现在感谢这个董事会中一些人的帮助,我设法提出before_filter,确保项目创建时不会发生这种情况。

问题是我不明白如何将此过滤器应用于update操作。

由于更新操作未使用Rails的build函数,因此我根本不知道如何在其中获取@project

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:1)

在您的情况下,我会从current_user开始,而不是@project(提供User has_many :invoices):

current_user.invoices.build(params[:invoice])

您也可以执行以下操作,而不是明确检查current_user?(@invoice.user)

def find_invoice
  @invoice = current_user.invoices.find(params[:id])
end

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

错误的发票或项目将抛出您可能或可能不想处理的500。

如果User has_many :invoices, :through => :projectsProject因此has_many :invoices那么:

def find_invoice
  @invoice = @project.invoices.find(params[:id])
end

答案 1 :(得分:0)

@project.invoices.build方法会创建一个与该特定Invoice自动关联的新@project。您不必做任何工作,也不存在将其链接到错误项目的风险。

但是,您需要确保project_id不是可访问的属性。