Rails:如果没有找到关联,则创建关联以避免零错误

发布于 2024-09-24 22:02:30 字数 947 浏览 7 评论 0原文

我有一个应用程序,我的用户可以在其中拥有一组首选项。两者都存储为 ActiveRecord-models,如下所示:

class User < AR::Base
   has_one :preference_set
end

class PreferenceSet < AR::Base
   belongs_to :user
end

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

@u = User.first
@u.preference_set => #<PreferenceSet...>
@u.preference_set.play_sounds => true

但是如果尚未创建首选项集,则会失败,因为 @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

这导致“堆栈级别太深”,因为它递归地调用自身。

我的问题是:

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

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

谢谢!

I have an application where my users can have a set of preferences. Both are stored as ActiveRecord-models as follows:

class User < AR::Base
   has_one :preference_set
end

class PreferenceSet < AR::Base
   belongs_to :user
end

I can now access the preferences of a user:

@u = User.first
@u.preference_set => #<PreferenceSet...>
@u.preference_set.play_sounds => true

But this fails if a preference set is not already created, since @u.preference_set will be returning nil, and I'll be calling play_sounds on nil.

What I want to archive is that User.preference_set always returns a PreferenceSet instance. I've tried defining it like this:

class User < ..
   has_one :preference_set

   def preference_set
     preference_set || build_preference_set
   end
end

This is causing a 'Stack level too deep', since it is calling itself recursively.

My question is this:

How can I ensure that @user.preference_set returns either the corresponding preference_set-record or, if none exists, builds a new one?

I know I could just rename my association (eg. preference_set_real) and avoid recursive calls this way, but for the sake of simplicity in my app, I'd like to keep the naming.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

因为看清所以看轻 2024-10-01 22:02:30

有一个优雅简单的形式:

class User < ApplicationRecord
  has_one :preference_set
  
  def preference_set
    super || build_preference_set
  end
end

ActiveRecord 有意启用这种 super 的使用来覆盖关联方法的行为。

There's an elegantly simple form:

class User < ApplicationRecord
  has_one :preference_set
  
  def preference_set
    super || build_preference_set
  end
end

ActiveRecord intentionally enables such use of super to override the behaviour of association methods.

灯角 2024-10-01 22:02:30

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

class User < ActiveRecord::Base
   has_one       :preference_set, :autosave => true
   before_create :build_preference_set
end

这将对其进行设置,以便每当创建 User 时,PreferenceSet 也会创建。如果您需要使用参数初始化关联记录,请在 before_create 中调用不同的方法,该方法调用 build_preference_set(:my_options => "here") 然后返回 <代码> true。

然后,您可以通过迭代任何没有 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

Well the best way to do this is to create the associated record when you create the primary one:

class User < ActiveRecord::Base
   has_one       :preference_set, :autosave => true
   before_create :build_preference_set
end

That will set it up so whenever a User is created, so is a PreferenceSet. If you need to initialise the the associated record with arguments, then call a different method in before_create which calls build_preference_set(:my_options => "here") and then returns true.

You can then just normalise all existing records by iterating over any that don't have a PreferenceSet and building one by calling #create_preference_set.

If you want to only create the PreferenceSet when it is absolutely needed, then you can do something like:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文