Rails 5属于奇怪的行为

时间:2017-10-28 16:59:35

标签: ruby-on-rails

客户等级

class Client < ApplicationRecord
 validates_presence_of :name, :email
 validates_email_format_of :email, :message => 'is not looking good'
 validates_uniqueness_of :email

 has_many :projects
end

项目类

class Project < ApplicationRecord
   belongs_to :client, optional: false

   validates_presence_of :name 

end

我的表的架构

create_table "clients", force: :cascade do |t|
    t.string "name"
    t.string "email"
    t.string "phone"
    t.string "address"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "projects", force: :cascade do |t|
    t.string "name"
    t.integer "client_id"
    t.string "description"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

有时我想在没有指定客户端的情况下创建Project。所以我添加了选项:选项false。所以现在我可以在不指定任何客户端ID的情况下创建项目。但是,当我尝试使用client_id创建项目时,它接受client_id的任何值,即如果输入8并且如果此id在客户端中不存在,那么它也被接受。我希望在这种情况下它不应该保存这个项目。

我该如何实现这种行为?

我有rails版本5.1.4

2 个答案:

答案 0 :(得分:1)

我会编写您自己的自定义验证,以确保在持久化项目记录之前,客户端的ID实际存在于您的数据库中:

class Project < ApplicationRecord
   belongs_to :client, optional: false

   validates_presence_of :name

   validate :validate_client_id, if: :client_id?

  private

  def validate_client_id
    errors.add(:client_id, "is invalid") unless Client.exists?(self.client_id)
  end 
end

仅当字段不为空时才会运行验证。这很方便,因为client_id在您的情况下是可选的。

答案 1 :(得分:1)

首先是一些更改,是可选的:true,可选:false是默认行为,并且希望每次都获得一个关联的记录,据说,你可以这样做:

class Project < ApplicationRecord
    belongs_to :client, optional: true

    # Sorry, small bug, client_id? with value zero would return always false and it becomes zero when you input strings or false
    # validates_presence_of :client, if: client_id?
    validates_presence_of :client, unless: Proc.new{ |d| d.client_id.blank? }
end

这将在client_id存在时验证客户端记录

p = Project.new                 # => #<Project id: nil, client_id: nil, ...
p.valid?                        # => true
p.client = Client.first         # => #Client id: 1, ...
p.valid?                        # => true
p.client = nil                  # => nil
p.valid?                        # => true
#Non-existent id 10
p.client_id = 10                # => 10
p.valid?                        # => false
p.errors.full_messages          # => ["Client can't be blank"]
p.client_id = 1                 # => 1
p.client                        # => #Client id: 1, ...
p.valid?                        # => true

您甚至可以使用自定义消息

validates_presence_of :client, message: 'invalid client', if: :client_id?

最后,只是一个建议,使用t.references进行迁移,以便能够使用外键并将此字段编入索引

t.references :client, foreign_key: true