在 Rails 7 中实现派生属性

问题描述 投票:0回答:1

我正在尝试在 Rails 7 中实现派生字段。我有一个标签模型。标签有一个前缀、一个循环号和一个可选的后缀。 (是的,我是一名仪器工程师:-)我将这些属性单独保存在数据库中,因为需要单独对它们进行排序和搜索,但大多数时候标签被引用并显示为这些字段的组合。我定义了一个属性访问器和一个私有的 setter 函数来连接字段,并设置 after_find 帮助器来触发 setter。但它们似乎不起作用。在控制台中,

Tag.first.full_tag
结果为
nil
,并且视图中不显示任何内容。

我本以为这个要求比较常见,但在我的搜索中没有发现任何有用的东西。当然,我可能可以将派生属性持久保存到数据库中,但这会违反“单一信息源”的基本规则。如果有人能指出我哪里出错了,我将不胜感激。

# tag.rb:
class Tag < ApplicationRecord
  belongs_to :project
  belongs_to :discipline, foreign_key: :discipline, primary_key: :code

  attr_reader :full_tag
  after_find :set_full_tag

...

 private

    def set_full_tag
      full_tag = prefix + "-" + loop.to_s.rjust(4, '0')
      if !suffix.empty?
        full_tag += "." + suffix
      end
    end
end
ruby-on-rails
1个回答
0
投票

那么,让我们在这里构建一个示例:

建议代码:

class Tag < ApplicationRecord
  # attr_accessor for the derived full_tag
  attr_accessor :full_tag
  
  # Set the full_tag after finding the record
  after_find :set_full_tag

  private

  def set_full_tag
    # Set the full_tag on the instance using self.full_tag
    self.full_tag = "#{prefix}-#{self.loop.to_s.rjust(4, '0')}"
    
    # Add suffix if it's present
    self.full_tag += ".#{suffix}" if suffix.present?
  end
end

原始代码的主要问题(据我所知)是它没有正确设置

full_tag
值。为了解决这个问题,我们首先将
attr_reader
替换为
attr_accessor
。为什么?
attr_reader
只能让您读取该值,而
attr_accessor
则可以让您读取和写入它。据我了解,您想在找到记录后更改
full_tag
值。

接下来,

full_tag = ...
创建一个临时变量,它不会将组合标签存储在模型中。我们可以使用
self.full_tag = ...
,告诉Rails使用
attr_accessor
生成的setter方法,以便
full_tag
值正确更新并保存在对象中。

我希望这能为您指明正确的方向,我是 Rails 新手。

测试框架:

rails new tag_proj
cd tag_proj
rails generate model Tag prefix:string loop:integer suffix:string
rails db:migrate

echo "
class Tag < ApplicationRecord
  attr_accessor :full_tag
  after_find :set_full_tag

  private

  def set_full_tag
    self.full_tag = \"#{prefix}-#{self.loop.to_s.rjust(4, '0')}\"
    self.full_tag += \".#{suffix}\" if suffix.present?
  end
end
" > app/models/tag.rb

echo "
Tag.create(prefix: 'XX', loop: 123, suffix: 'A')
Tag.create(prefix: 'YY', loop: 45, suffix: 'B')
Tag.create(prefix: 'ZZ', loop: 67, suffix: nil)
" >> db/seeds.rb

rails db:seed

echo "
# lib/tasks/tag_full_tag.rake
namespace :tag do
  task full_tag: :environment do
    puts Tag.first.full_tag   
    puts Tag.second.full_tag
    puts Tag.third.full_tag
  end
end
" > lib/tasks/tag_full_tag.rake

rake tag:full_tag

输出

> rake tag:full_tag
XX-0123.A
YY-0045.B
ZZ-0067
© www.soinside.com 2019 - 2024. All rights reserved.