在我的Rails应用中,我users
可以拥有多个projects
,而invoices
可以有多个class Invoice < ActiveRecord::Base
attr_accessible :number, :date, :project_id
validates :project_id, :presence => true,
:inclusion => { :in => ????????? }
end
。
如何确保用户只能为他的项目之一而不是为其他用户的项目创建发票?
class InvoicesController < ApplicationController
def new
@invoice = current_user.invoices.build(:project_id => params[:project_id])
end
def create
@invoice = current_user.invoices.build(params[:invoice])
if @invoice.save
flash[:success] = "Invoice saved."
redirect_to edit_invoice_path(@invoice)
else
render :new
end
end
end
感谢您的帮助。
{{1}}
答案 0 :(得分:1)
我认为不应该进行验证。您应该确保用户选择的项目是他的项目之一。
您可以在控制器上执行以下操作:
project = current_user.projects.find params[:project_id]
@invoice = Invoice.new(project: project)
# ...
您的创建操作可能看起来像这样。
def create
@invoice = current_user.invoices.build(params[:invoice])
@invoice.project = current_user.projects.find params[:invoice][:project_id]
if @invoice.save
flash[:success] = "Invoice saved."
redirect_to edit_invoice_path(@invoice)
else
render :new
end
end
答案 1 :(得分:1)
project_id
是敏感的&#34;属性 - 所以从attr_accessible中删除它。你是对的,你不应该相信表格中的参数,你必须检查它。
def create
@invoice = current_user.invoices.build(params[:invoice])
# @invoice.project_id is nil now because this attr not in attr_accessible list
@invoice.project_id = params[:invoice][:project_id] if current_user.project_ids.include?(params[:invoice][:project_id])
if @invoice.save
flash[:success] = "Invoice saved."
redirect_to edit_invoice_path(@invoice)
else
render :new
end
end
如果用户试图破解您的应用并将project_id
更改为非拥有值,则方法create
会使部分new
无效@invoice
。 不要忘记将project_id
验证留在。
如果您遇到异常Can't mass-assign protected attributes...
,有几种方法可以做。最简单的方法是:
1.从环境配置中删除线(开发,测试,生产)
# Raise exception on mass assignment protection for Active Record models
config.active_record.mass_assignment_sanitizer = :strict
2。在分配之前拒绝来自参数的敏感参数。
# changes in method create
def create
project_id = params[:invoice].delete(:project_id)
@invoice = current_user.invoices.build(params[:invoice])
@invoice.project_id = project_id if current_user.project_ids.include?(project_id)
...
end
答案 2 :(得分:0)
好的,幸运的是,这次我设法找到了我自己的解决方案。
我没有对我的控制器进行任何更改(“让我们保持'瘦”),但是我的模型添加了验证方法:
class Invoice < ActiveRecord::Base
attr_accessible :number, :date, :project_id
validates :project_id, :presence => true,
:numericality => { :only_integer => true },
:inclusion => { :in => proc { |record| record.available_project_ids } }
def available_project_ids
user.project_ids
end
end
我不确定这是好的还是坏的编码习惯。也许有人可以对此有所了解。但目前对我来说似乎很安全,到目前为止我还没能以任何方式破解它。