我的记录/模型中充满了许多布尔标志,短字符串,misc设置等,我想将它们重构为封装类。
我通常会为父母创建一个内部类来拥有'但是Rails中最好的做法是什么?
一个例子是拥有一个表Client
,行数为10~20。每个Client
都有很长的选项列表,目前存储在Client
列下。所以有以下字段:
c = Client.find(1)
c.theme_color # "blue"
c.session_timeout_seconds # 1800
c.branding_logo # "client_a.png"
c.require_logout_confirmation # true
在没有rails的纯OOP系统中,我会重构这些"实例变量"进入嵌套的Client::Options
类。然后,所有选项都组织在一个嵌套类中,并封装在Client
内。通过这种方式,没有其他人需要知道Client::Options
和Client
密切相关(他们仍然会在不知道c.theme_color
会将呼叫委托给{{1}的情况下发送消息Client
因为没有其他类或方法调用需要改变,所以这也将成为一个松散耦合的重构。
但是,在rails中,嵌套类的东西是不可能的(据我所知),所以我正在寻找最佳实践'溶液
答案 0 :(得分:0)
这是我最终选择的解决方案:
class Client < ActiveRecord::Base
has_one :option_set, :dependent => :destroy, :autosave => true, :validate => true, :inverse_of => :client
before_create :build_option_set
# accesses all these fields through OptionSet
# :allow_nil is required or else delegation will fail - it appears delegation occurs before :build_option_set
delegate_option_set_args = [
:option_a,
:option_b,
:option_c,
# etc
].map { |f| [f, :"#{f}=", :"#{f}?" ] }.flatten << { :to => :option_set, :allow_nil => true }
delegate(*delegate_option_set_args)
end
class OptionSet < ActiveRecord::Base
validates_presence_of :client_id
validates_inclusion_of :option_c, :in => [ "foo", "bar", "buzz", "fizz" ]
belongs_to :client, :inverse_of => :option_set
end
现在,虽然仍然可以从&#34;外部&#34;访问OptionSet
。在Client
中,它仍然有效地将所有这些字段封装到它们自己的类中。访问这些字段应通过Client
的消息传递来完成,例如Client.first.option_a
,而不是修改OptionSet
。可以执行其他工作来强制执行OptionSet
不会直接修改。
我找不到在Client
创建的同时实例化选项字段的方法,但是:
client = Client.create!(client_args)
client.update_arguments!(
:option_a => 1,
:option_b => false,
:option_c => "foo"
)