我正在尝试在 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
那么,让我们在这里构建一个示例:
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