简体   繁体   English

如何在Rails验证中验证外键?

[英]How to validate foreign keys in Rails validations?

In my Rails app I have users who can have many projects which in turn can have many invoices . 在我的Rails应用程序中,我的users可以拥有许多projects ,而这些projects又可以有很多invoices

How can I make sure that a user can only create an invoice for one of his projects and not for another user's projects? 我怎样才能确保用户只能创建自己的一个项目,而不是对其他用户的项目发票吗?

class Invoice < ActiveRecord::Base

  attr_accessible :number, :date, :project_id

  validates :project_id,  :presence   => true,
                          :inclusion  => { :in => ????????? }

end

Thanks for any help. 谢谢你的帮助。


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

I think that shouldn't be on a validation. 我认为不应该进行验证。 You should ensure the project the user selected is one his projects. 您应该确保用户选择的项目是他的项目之一。

You could do something on your controller like: 您可以在控制器上执行以下操作:

project = current_user.projects.find params[:project_id]
@invoice = Invoice.new(project: project)
# ...

Your create action could look something like this. 您的创建操作可能看起来像这样。

  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

project_id is "sensitive" attribute - so remove it from attr_accessible. project_id是“敏感”属性 - 因此将其从attr_accessible中删除。 You are right that you should not believe params from the form and you must check it. 你是对的,你不应该相信表格中的参数,你必须检查它。

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

If user tries to hack your app and change project_id to not owned value then method create render partial new with invalid @invoice . 如果用户试图破解您的应用并将project_id更改为非拥有值,则方法create使用无效的@invoice呈现部分new @invoice Do not forget to leave the validation of project_id on presence . 不要忘记将project_id的验证留在存在上

If you get exception Can't mass-assign protected attributes... there are several ways what to do. 如果你得到异常Can't mass-assign protected attributes...有几种方法可以做什么。 The simplest ways are: 1. remove line from environment configs (development, test, production) 最简单的方法是:1。从环境配置中删除线(开发,测试,生产)

# Raise exception on mass assignment protection for Active Record models
config.active_record.mass_assignment_sanitizer = :strict

2. Reject sensitive parameters from params before assigning. 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

OK, luckily I managed to come up with a solution of my own this time. 好的,幸运的是我这次设法找到了我自己的解决方案。

I didn't make any changes to my controller ( "let's keep 'em skinny" ), but added a validation method to my model instead: 我没有对我的控制器进行任何更改( “让我们保持'瘦” ),但为我的模型添加了验证方法:

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

I am not sure if this is good or bad coding practice. 我不确定这是编码的好坏。 Maybe someone can shed some light on this. 也许有人可以对此有所了解。 But for the moment it seems pretty safe to me and I haven't been able to hack it in any way so far. 但目前对我来说似乎很安全,到目前为止我还无法以任何方式破解它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM