Rails 5 API - 使用来自 belongs_to 关联模型的值在 has_one 的一侧设置默认值

Rails 5 API - setting default values on the one side of a has_one using values from the belongs_to associated model

This question 似乎是 Stack Overflow 上关于设置模型默认值的最多 voted/relevant 问题。尽管探索了多种方法,但其中 none 涵盖了这个问题。

请注意,这是一个 API - 因此提醒的默认文本必须由 api 提供,因此我将其存储在数据库中。有些用户希望使用该默认值,有些用户会更新它。

这是我的代码,但感觉不对,因为我必须在 'parent'(User 模型中设置默认值之一(:body) ).

class User < ActiveRecord::Base    
  # Relationships
  belongs_to :account
  has_one :reminder

  before_create :build_default_reminder

  private
  def build_default_reminder
    build_reminder(body: get_default_body)
  end

  def get_default_body
    <<~HEREDOC
      This is a quick reminder about the outstanding items still on your checklist.
      Thank you,
      #{self.name}
    HEREDOC
  end
end

class Reminder < ApplicationRecord
  # Relationships
  belongs_to :user

  # Default attributes
  attribute :is_follow_up, :boolean, default: true
  attribute :subject, :string, default: "your checklist reminder!"
  attribute :greeting, :string, default: "Hi"
end

我更愿意做的是这样,以便所有默认值都在同一模型中(child):

class User < ActiveRecord::Base    
  # Relationships
  belongs_to :account
  has_one :reminder    
end

class Reminder < ApplicationRecord
  # Relationships
  belongs_to :user

  # Default attributes
  attribute :is_follow_up, :boolean, default: true
  attribute :subject, :string, default: "your checklist reminder!"
  attribute :greeting, :string, default: "Hi"
  attribute :body, :string, default:
    <<~HEREDOC
      This is a quick reminder about the outstanding items still on your checklist.
      Thank you,
      #{self.user.name}
    HEREDOC
end

但这当然会引发错误:

undefined method `user' for #<Class:0x007fa59d4d0f90>

问题的出现是因为默认的:body字符串必须包含用户名。有没有办法实现这一点 - 即。在 reminder 模型中拥有所有默认值,但不知何故引用了创建它的用户?

我认为这很棘手这一事实可能表明您可能想要稍微重新设计一下。特别是,您似乎将模型逻辑与视图逻辑混合在一起。

您可以通过将实际创建字符串的逻辑移动到更靠近它要呈现的位置(ERB 文件、电子邮件模板等)来解决此问题。然后,当您传入要为其生成字符串的 Reminder 实例时,调用 @reminder.user.name 的代码将起作用,因为 @reminder.user 关联不起作用空白。

I think the fact that this is tricky may be an indication that you might want to redesign this a little bit. In particular, it looks like you're mixing model logic with view logic.

这是@Adam Berman 的中肯观察。所以它已经重新设计 - 在@MrYoshiji 的评论的帮助下,谢谢大家!

我认为以下是更好且更易于维护的解决方案,尤其是当应用程序确实需要能够提供这些默认英文文本的实际翻译时 - 因此我还将创建 custom_greetingcustom_subject 这两个属性。

class User < ActiveRecord::Base    
  # Relationships
  belongs_to :account
  has_one :reminder    
end

class Reminder < ApplicationRecord
  # Relationships
  belongs_to :user

  # Default attributes
  attribute :subject, :string, default: "your checklist reminder!"
  attribute :greeting, :string, default: "Hi"

  def body=(value)
    self.custom_body = value
  end

  def body
    custom_body.presence || I18n.t('reminder.default_body', name: self.user.name)
  end
end

en.yml 文件:

  reminder:
    default_body: "\nThis is a quick reminder about the outstanding items still on your checklist.\
      \nPlease click the button below to review the items we're still waiting on.\
      \nThank you,\
      \n%{name}"

(this question 对 yml 中的 multi-line 文本帮助很大)

(this question 有助于理解 getter/setter - 请参阅@pascal betz 中有关存储价格的答案)