我正在为以下情况寻找一些最佳实践建议。
我有以下骨架ActiveRecord模型:
# user.rb
class User < ActiveRecord::Base
has_many :country_entries, dependent: destroy
end
# country_entry.rb
class CountryEntry < ActiveRecord::Base
belongs_to :user
validates :code, presence: true
end
现在假设我需要为特定用户获取以逗号分隔的CountryEntry
代码列表。问题是,我在哪里放这个方法?有两种选择:
# user.rb
#...
def country_codes
self.country_entries.map(&:code)
end
#...
-OR -
# country_entry.rb
#...
def self.codes_for_user(user)
where(user_id: user.id).map(&:code)
end
#...
因此API将是:@current_user.country_codes
- 或 - CountryEntry.codes_for_user(@current_user)
似乎将代码放在country_entry.rb
中将所有内容分离一点,但它使API变得更加丑陋。关于这个问题的任何一般或个人经验最佳实践?
答案 0 :(得分:4)
实例方法VS类方法:如果方法是针对实例的,那么当然最好是实例方法。
在Coutry模型中的用户模型VS中:用户模型获胜。 Demeter法则仅在Ruby中提出一个点。如果你有机会这样做,当然最好遵循。
结论:你的第一种方法获胜。
# user.rb
def country_codes
self.country_entries.map(&:code)
end
http://en.wikipedia.org/wiki/Law_of_Demeter
http://rails-bestpractices.com/posts/15-the-law-of-demeter
http://devblog.avdi.org/2011/07/05/demeter-its-not-just-a-good-idea-its-the-law/
答案 1 :(得分:3)
现在这真是一个有趣的问题。它有很多答案; - )
从你最初的问题我建议你把代码放在协会本身
class User < ActiveRecord::Base
has_many :country_entries do
def codes
proxy_association.owner.country_entries.map(&:code)
end
end
end
所以你可以做这样的事情
list_of_codes = a_user.country_entries.codes
现在很明显这违反了Law of Demeter。 因此,建议您最好在User对象上提供一个方法,如此
class User < ActiveRecord::Base
has_many :country_entries do
def codes
proxy_association.owner.country_entries.map(&:code)
end
end
def country_codes
self.country_entries.codes
end
end
显然,Rails世界中没有人关心得墨忒耳定律,所以请耐心等待。
至于将代码放入CountryEntry类中,我不知道为什么要这样做。如果您只能向用户查找国家/地区代码,我认为无需创建类方法。无论如何,如果你手边有一个用户,你只能查看该列表。
如果有许多不同的对象可以拥有country_entries关联,那么将它作为类方法放入CountryEntry是有意义的。
我最喜欢的是LOD和类方法的组合,以便重复使用。
class User < ActiveRecord::Base
has_many :country_entries
def country_codes
CountryEntry.codes_for_user(self)
end
end
class CountryEntry < ActiveRecord::Base
belongs_to :user
validates :code, presence: true
def self.codes_for_user(some_id)
where(ref_id: some_id).map(&:code)
end
end
答案 2 :(得分:2)
就API开发人员而言,从两个提案中获得,添加到用户模型似乎非常简单。鉴于问题:
现在假设我需要为特定用户获取以逗号分隔的CountryEntry代码列表。
上下文由用户组成,我们想要获取代码列表。自然的“入口点”似乎是一个用户对象。
另一种看待问题的方法是在责任方面(因此链接到Demeter的@robkuz条目)。 CountryEntry
实例负责提供其代码(可能还有一些其他内容)。 CountryEntry
类基本上负责提供其所有实例共有的属性和方法,而不是(好)。获取逗号分隔代码列表是CountryEntry
个实例的专用用法,只有User
个对象显然需要关注。在这种情况下,责任属于当前用户对象。旁观者眼中的价值......
这与线程上的大多数答案都是内联的,虽然在目前为止的解决方案中,您没有得到以逗号分隔的代码列表,而是一组代码。
就性能而言,请注意,由于懒惰评估,可能存在差异。只是一个注意事项---对ActiveRecord更熟悉的人可以对此发表评论!
答案 3 :(得分:0)
我认为@current_user.country_codes
在这种情况下是更好的选择,因为它会更容易在您的代码中使用。