如何在Rails 4中使用concerns
如何在Rails 4中使用concerns
默认的Rails 4项目生成器现在会在控制器和模型下创建\"concerns\"目录。我找到了一些关于如何使用路由关心的解释,但没有关于控制器或模型的。
我非常确定这与社区中当前的\"DCI潮流\"有关,并希望尝试一下。
问题是,我应该如何使用这个功能,是否有规定的命名/类层次结构定义方式才能使其正常工作?我如何在模型或控制器中包含关心?
我一直在研究如何使用模型关注将臃肿的模型精简化,并使您的模型代码保持DRY。以下是一些带有示例的解释:
1) 精简化模型代码
考虑一个文章(Article)模型,一个活动(Event)模型和一个评论(Comment)模型。一篇文章或一个活动可能有多个评论。评论属于文章或者活动。
传统上,这些模型可能看起来像:
评论模型:
class Comment < ActiveRecord::Base belongs_to :commentable, polymorphic: true end
文章模型:
class Article < ActiveRecord::Base has_many :comments, as: :commentable def find_first_comment comments.first(created_at DESC) end def self.least_commented #return the article with least number of comments end end
活动模型:
class Event < ActiveRecord::Base has_many :comments, as: :commentable def find_first_comment comments.first(created_at DESC) end def self.least_commented #returns the event with least number of comments end end
我们可以发现,活动和文章都有一段重复的代码。使用关注(concerns),我们可以将这段共同的代码提取到一个单独的Commentable(评论相关)模块中。
为此,在app/models/concerns中创建一个commentable.rb文件。
module Commentable extend ActiveSupport::Concern included do has_many :comments, as: :commentable end # for the given article/event returns the first comment def find_first_comment comments.first(created_at DESC) end module ClassMethods def least_commented #returns the article/event which has the least number of comments end end end
现在你的模型看起来像这样:
评论模型:
class Comment < ActiveRecord::Base belongs_to :commentable, polymorphic: true end
文章模型:
class Article < ActiveRecord::Base include Commentable end
活动模型:
class Event < ActiveRecord::Base include Commentable end
2) 精简化臃肿的模型
考虑一个活动模型。一个活动有许多参与者和评论。
通常,活动模型可能会像这样:
class Event < ActiveRecord::Base has_many :comments has_many :attenders def find_first_comment # for the given article/event returns the first comment end def find_comments_with_word(word) # for the given event returns an array of comments which contain the given word end def self.least_commented # finds the event which has the least number of comments end def self.most_attended # returns the event with most number of attendes end def has_attendee(attendee_id) # returns true if the event has the mentioned attendee end end
拥有许多关联和其他方面的模型往往有积累越来越多的代码而变得难以管理。关注提供了一种精简化模块使其更模块化和易于理解的方式。
可以使用关注来重构上面的模型,如下所示:
在app/models/concerns/event文件夹中创建一个attendable.rb
和commentable.rb
文件。
attendable.rb
module Attendable extend ActiveSupport::Concern included do has_many :attenders end def has_attender(attender_id) # returns true if the event has the mentioned attendee end module ClassMethods def most_attended # returns the event with most number of attendes end end end
commentable.rb
module Commentable extend ActiveSupport::Concern included do has_many :comments end def find_first_comment # for the given article/event returns the first comment end def find_comments_with_word(word) # for the given event returns an array of comments which contain the given word end module ClassMethods def least_commented # finds the event which has the least number of comments end end end
现在使用 Concerns,你的 Event 模型可以简化为
class Event < ActiveRecord::Base include Commentable include Attendable end
* 在使用 Concerns 时,建议采用“基于领域”而不是“基于技术”的分组。基于领域的分组是如“Commentable”、“Photoable”、“Attendable”,而基于技术的分组则是“ValidationMethods”、“FinderMethods”等。
所以我自己找出了它所指的概念。它实际上是一个相当简单但功能强大的概念。它与示例中的代码重用有关。基本上,这个想法是提取公共的和/或上下文特定的代码块,以清理模型并避免它们变得过于臃肿和杂乱。
作为一个例子,我会放一个众所周知的模式,即可标记模式:
# app/models/product.rb class Product include Taggable ... end # app/models/concerns/taggable.rb # notice that the file name has to match the module name # (applying Rails conventions for autoloading) module Taggable extend ActiveSupport::Concern included do has_many :taggings, as: :taggable has_many :tags, through: :taggings class_attribute :tag_limit end def tags_string tags.map(&:name).join(', ') end def tags_string=(tag_string) tag_names = tag_string.to_s.split(', ') tag_names.each do |tag_name| tags.build(name: tag_name) end end # methods defined here are going to extend the class, not the instance of it module ClassMethods def tag_limit(value) self.tag_limit_value = value end end end
所以,按照产品示例,您可以将可标记性添加到任何您想要的类中并共享其功能。
这是由DHH相当好地解释了:
在Rails 4中,我们要邀请程序员使用与之自动成为加载路径的默认app/models/concerns和app/controllers/concerns目录。连同ActiveSupport::Concern包装器一起,这足以使这种轻量级的因素机制发挥作用。