Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
686 views
in Technique[技术] by (71.8m points)

ruby-on-rails - 防止对特定操作进行ActiveRecord关联验证的最佳方法(Best way to prevent ActiveRecord association validations on specific actions)

I have 2 models: User and Purchase .

(我有2个模型: UserPurchase 。)

Purchases belong to Users.

(购买属于用户。)

class User < ApplicationRecord
  has_many :purchases
end

class Purchase < ApplicationRecord
  belongs_to :user
  enum status: %i[succeeded pending failed refunded]
end

In Rails 5.2, a validation error is raised when any modifications are made to a Purchase with no associated User .

(在Rails 5.2中,当对没有关联UserPurchase进行任何修改时,都会引发验证错误。)

This works great for new purchases, but it also throws errors when simply trying to save data on an existing purchase with a user that no longer exists in the database.

(这对于新购买的产品非常有用,但是当仅尝试使用数据库中不再存在的用户来保存现有购买的数据时,也会引发错误。)

For example:

(例如:)

user = User.find(1)

# Fails because no user is passed
purchase = Purchase.create(status: 'succeeded') 

# Succeeds
purchase = Purchase.create(user: user, status: 'succeeded') 
purchase.status = 'failed'
purchase.save

user.destroy

# Fails because user doesn't exist
purchase.status = 'refunded'
purchase.save

I know I can prevent the second update from failing by making the association optional with belongs_to :user, optional: true in the purchase model, but that cancels out the first validation for purchase creation as well.

(我知道我可以通过将购买模型中的belongs_to :user, optional: true为可选,从而防止第二次更新失败,但这也取消了对购买创建的第一次验证。)

I could also just build my own custom validations for the user association, but I'm looking for a more conventional Rails way to do this.

(我也可以为用户关联建立自己的自定义验证,但是我正在寻找一种更常规的Rails方法来实现。)

  ask by Doug translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can use the if: and unless: options to make validations conditional:

(您可以使用if:unless:选项使验证成为条件:)

class Purchase < ApplicationRecord
  belongs_to :user, optional: true # suppress generation of the default validation
  validates_presence_of :user, unless: :refunded?
  enum status: %i[succeeded pending failed refunded]
end

You can pass the name of a method or a lambda.

(您可以传递方法或lambda的名称。)

These shouldn't be confused with the if and unless keywords - they are just keyword arguments.

(这些不应与ifunless关键字混淆-它们只是关键字参数。)

The optional: option for belongs_to really just adds a validates_presence_of validation with no options.

(实际上, belongs_tooptional:选项仅添加了validates_presence_of验证,而没有任何选项。)

Which is nice as a shorthand but not really that flexible.

(简写是不错的选择,但是却没有那么灵活。)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...