Rails:保存后validation关联?
我有一个User
模型,它有很多roles
。 角色包含user_id
字段,我想validate_presence_of
问题是:如果我在创建时为用户分配了一个角色,则validation失败,因为没有设置user_id。 现在,我确实想validationuser_id是否存在,但我需要在检查之前保存用户。
代码目前看起来像这样:
@user = User.new(params[:user]) @user.roles < 'Peon') unless @user.has_roles? if @user.save # ...
我能想到解决问题的唯一方法是禁用validation,我不想做,或者双重保存到DB,这不是完全有效的。
处理此问题的标准方法是什么?
如果您将代码更改为如下所示,我认为您可以解决validation问题:
@user = User.new(params[:user]) @user.roles.new(:name => 'Peon') unless @user.has_roles? if @user.save # ...
如果这不起作用,您可以尝试将validation更改为:
class Role < ActiveRecord::Base belongs_to :user validates :user_id, :presence => true, :unless => Proc.new() {|r| r.user} end
经过一番研究,这个解决方案似乎最简单。 首先,在您的Role
模型中,validationuser
,而不是validationuser_id
。
validates :user, :presence => true
然后,在您的User
模型中,将:inverse_of => :user
到您的has_many
调用中:
has_many :roles, :inverse_of => :user
然后它按预期工作:
irb(main):001:0> @user = User.new => # irb(main):002:0> @user.roles << Role.new(:name => "blah") => [#] irb(main):003:0> @user.roles[0].user => # irb(main):004:0> @user.save (0.1ms) begin transaction SQL (3.3ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", Fri, 04 Jan 2013 02:29:33 UTC +00:00], ["updated_at", Fri, 04 Jan 2013 02:29:33 UTC +00:00]] User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1 SQL (0.2ms) INSERT INTO "roles" ("created_at", "name", "updated_at", "user_id") VALUES (?, ?, ?, ?) [["created_at", Fri, 04 Jan 2013 02:29:34 UTC +00:00], ["name", "blah"], ["updated_at", Fri, 04 Jan 2013 02:29:34 UTC +00:00], ["user_id", 3]] (1.9ms) commit transaction => true irb(main):005:0> @user.roles.first => #
但请注意,这仍会产生两个SQL事务,一个用于保存用户,另一个用于保存角色。 我不知道你怎么能避免这种情况。
另请参阅: 如何validationRails属于关联的存在?
你必须看看ActiveRecord的Callbacks 。 可能你会使用before_validation
来做到这一点。
对于任何人谷歌搜索has_many :through
的解决方案has_many :through
关联,截至2013年12月5日:inverse_of
选项不能与:through
( source )一起使用。 相反,您可以使用@ waldyr.ar建议的方法。 例如,如果我们的模型设置如下:
class User < ActiveRecord::Base has_many :roles has_many :tasks, through: roles end class Role < ActiveRecord::Base belongs_to :user belongs_to :task end class Task < ActiveRecord::Base has_many :roles has_many :users, through: roles end
我们可以按如下方式修改我们的Role
类,以便在保存之前validationtask
和user
的存在
class Role < ActiveRecord::Base belongs_to :user belongs_to :task before_save { validates_presence_of :user, :task } end
现在,如果我们创建一个新User
并添加如下几个tasks
:
>> u = User.new >> 2.times { u.tasks << Task.new }
运行u.save
将保存User
和Task
,以及透明地构建和保存task_id
键user_id
和task_id
被适当设置的新Role
。 validation将针对所有型号运行,我们可以继续我们的快乐方式!