Rails:如果找不到任何错误,则创建关联

Mat*_*ias 13 activerecord ruby-on-rails has-one

我有一个应用程序,我的用户可以拥有一组首选项.两者都存储为ActiveRecord模型,如下所示:

class User < AR::Base
   has_one :preference_set
end

class PreferenceSet < AR::Base
   belongs_to :user
end
Run Code Online (Sandbox Code Playgroud)

我现在可以访问用户的首选项:

@u = User.first
@u.preference_set => #<PreferenceSet...>
@u.preference_set.play_sounds => true
Run Code Online (Sandbox Code Playgroud)

但是,这是否偏好设置尚未创建,因为@ u.preference_set将返回nil我将调用失败,play_soundsnil.

我想归档的是User.preference_set总是返回一个PreferenceSet实例.我试过像这样定义它:

class User < ..
   has_one :preference_set

   def preference_set
     preference_set || build_preference_set
   end
end
Run Code Online (Sandbox Code Playgroud)

这导致a 'Stack level too deep',因为它以递归方式调用自身.

我的问题是:

如何确保@user.preference_set返回相应的preference_set-record,如果不存在则返回构建新的记录?

我知道我可以重命名我的关联(例如preference_set_real)并以这种方式避免递归调用,但为了我的应用程序的简单性,我想保留命名.

谢谢!

ino*_*tus 44

或者干脆

class User < ApplicationRecord
   has_one :preference_set

   def preference_set
     super || build_preference_set
   end
end
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为ActiveRecord定义了mixin中的关联方法.

  • 这就是我想要的。 (2认同)

Bo *_*nes 28

那么,最好的方法是在创建主要记录时创建关联记录:

class User < ActiveRecord::Base
   has_one       :preference_set, :autosave => true
   before_create :build_preference_set
end
Run Code Online (Sandbox Code Playgroud)

这将设置它,所以无论什么时候User创建,所以是PreferenceSet.如果您需要初始化带参数的相关记录,然后调用不同的方法,before_create它调用build_preference_set(:my_options => "here"),然后返回true.

然后,您可以通过迭代任何没有a PreferenceSet并通过调用构建一个来对所有现有记录进行规范化#create_preference_set.

如果您只想创建PreferenceSet绝对需要的时间,那么您可以执行以下操作:

class User < ActiveRecord::Base
   has_one :preference_set

   def preference_set_with_initialize
     preference_set_without_initialize || build_preference_set
   end

   alias_method_chain :preference_set, :initialize
end
Run Code Online (Sandbox Code Playgroud)

  • 哇,没有碰到alias_method_chain.这很酷. (3认同)