我正在尝试找出一种基于父类动态生成子类的方法。在我的特定情况下,我希望每个实例变量都有 attr_accessor,在我的父类中初始化并在子类上继承。 我的类是代表数据库中三个不同表的三个不同模型。
“Record”是我的父类,我想在其中存储和编写我的所有代码。 “Post”和“User”是继承的子类。
我的代码
class Record
attr_reader :id
# attr_accessor
def initialize(**params)
@id = params[:id]
instance_variable_set("@#{params.keys[0]}", params.values[0])
instance_variable_set("@#{params.keys[1]}", params.values[1])
instance_variable_set(:@votes, params["votes"] || 0) if instance_of?(Post)
# p self.title
end
我想要实现的是将 attr_accessor 设置为例如在我想调用的子类“Post”中
post = Post.new(title: "New post", url: "some url")
puts post.title
我可以在不引发 NoMethodError 的情况下访问 title 实例变量
有人可以指导我,或者给我一些提示吗? 谢谢
答案 0 :(得分:0)
你正在倒退。父类不应该知道或实现其子类的特定逻辑。
class Record
attr_reader :id
def initialize(**attributes)
attributes.each do |key, value|
send("#{key}=", value)
end
end
end
class Post < Record
attr_accessor :title
attr_accessor :votes
end
irb(main):066:0> Post.new(id: 1, votes: 10, title: "Hello World").title
=> "Hello World"
attr_accessor
只是用于定义方法的元编程便利,因此无论如何都可以继承访问器方法。但是,如果您正在编写诸如对象关系管理器之类的东西,您将需要定义自己的宏方法来定义属性,以便跟踪类的属性:
module Attributes
def self.included(base)
base.extend(ClassMethods)
base.class_eval do
@attributes ||= {}
end
end
# assigns the passed attributes to the instance
def initialize(**attributes)
attributes.each do |key, value|
send "#{key}=", value
end
end
# gets all the attributes of an instance
def attributes
self.class.attributes.keys.each_with_object(Hash.new) do |key, hash|
hash[key] = send(key)
end
end
module ClassMethods
# Inherits the attributes of the parent class
def inherited(subclass)
attributes.tap do |parent_attributes|
subclass.class_eval do
@attributes ||= {}.merge(parent_attributes)
end
end
end
# defines an attribute that is inherited
def attribute(name, type = nil, **kwargs)
@attributes[name] = { type: type }.merge(kwargs)
attr_accessor name
end
def attributes
@attributes
end
end
end
class Record
include Attributes
attribute :id, Integer
end
class Post < Record
attribute :title, String
attribute :votes, Integer
end
irb(main):101:0> Post.new(votes: 10, title: "Hello World").attributes
=> {:id=>nil, :title=>"Hello World", :votes=>10}
这将属性定义存储在 class instance variable 中,让您可以附加“元数据”,从而为您稍后需要的功能打开,例如类型转换、序列化和脏跟踪。