Ruby on rails ActiveRecord关联-将功能放在何处?

Ruby on rails ActiveRecord关联-将功能放在何处?,ruby-on-rails,ruby,activerecord,sinatra,Ruby On Rails,Ruby,Activerecord,Sinatra,我正在为以下情况寻找一些最佳实践建议 我有以下骨架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: t

我正在为以下情况寻找一些最佳实践建议

我有以下骨架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
-或-

因此,API应该是:
@current\u user.country\u code
-或-
CountryEntry.code\u for\u user(@current\u user)




似乎将代码放在
country\u entry.rb
中会使一切更加解耦,但会使API更加丑陋。在这个问题上有任何一般或个人经验的最佳做法吗?

我认为
@当前用户。在这种情况下,国家/地区代码是一个更好的选择,因为它将更容易在您的代码中使用

  • 实例方法VS类方法:如果方法是针对实例的,当然最好是实例方法

  • 在用户模型与在国家模型中:用户模型获胜。德米特定律表明红宝石中只有一个点。如果你有机会做到这一点,当然最好跟着做

  • 结论:你的第一种方法获胜

    # user.rb
    def country_codes
      self.country_entries.map(&:code)
    end
    
    加:德米特法参考


    现在这真是一个有趣的问题。它有很多答案;-)

    根据您最初的问题,我建议您将代码放入关联本身

    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
    
    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
    
    class用户
    显然,世界上没有人关心得墨忒尔定律,所以对此持怀疑态度

    至于将代码放入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
    
    class用户
    就开发人员从这两个方案中获得的API而言,添加到用户模型似乎非常简单。鉴于这个问题:

    现在假设我需要为特定用户获取一个逗号分隔的CountryEntry代码列表

    上下文是由一个用户组成的,我们希望获得该用户的代码列表。自然的“入口点”似乎是一个用户对象

    另一种看待问题的方式是责任(因此链接到Demeter的@robkuz条目)。一个
    CountryEntry
    实例负责提供它的代码(可能还有其他一些东西)。一个
    CountryEntry
    类基本上负责提供所有实例所共有的属性和方法,而不仅仅是(好的)。获取逗号分隔代码列表是
    CountryEntry
    实例的一种特殊用法,只有
    User
    对象才关心这些实例。在这种情况下,责任属于当前用户对象。旁观者眼中的价值

    这与线程上的大多数答案是内联的,尽管在目前的解决方案中,您没有得到逗号分隔的代码列表,而是一个代码数组



    在性能方面,请注意,由于延迟评估,可能也存在差异。只是一个便条——更熟悉ActiveRecord的人可以对此发表评论

    我正要发布完全相同的东西,这时我看到你添加了你的答案+谢谢@iain,我只是追随伟大的思想,但并不拥有它:)为共同的观点干杯。比利,你能补充一点你的原则吗?我不确定你到底指的是什么。@EricPlaton,实际上这个原则是“得墨忒尔定律”,尽管基本原则类似于单一责任原则。查看我的更新以供参考。对于这个小例子,我同意你的看法。我唯一的问题是,如果这变得更复杂一点,用户模型将“了解”更多关于国家/地区进入模型的信息。
    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
    
    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