yag*_*oar 619 ruby-on-rails dci ruby-on-rails-4
默认的Rails 4项目生成器现在在控制器和模型下创建目录"Concer".我找到了一些关于如何使用路由问题的解释,但没有关于控制器或模型的解释.
我很确定它与社区当前的"DCI趋势"有关,并且想尝试一下.
问题是,我应该如何使用此功能,是否有关于如何定义命名/类层次结构以使其工作的约定?如何在模型或控制器中包含问题?
yag*_*oar 607
所以我自己发现了它.它实际上是一个非常简单但功能强大的概念.它与代码重用有关,如下例所示.基本上,我们的想法是提取常见的和/或特定于上下文的代码块,以便清理模型并避免它们变得太胖和混乱.
作为一个例子,我将放置一个众所周知的模式,可标记的模式:
# 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
Run Code Online (Sandbox Code Playgroud)
因此,按照Product示例,您可以将Taggable添加到您想要的任何类并共享其功能.
DHH很好地解释了这一点:
在Rails 4中,我们将邀请程序员使用默认app/models/concerns和app/controllers/concerns目录中的问题,这些目录自动成为加载路径的一部分.与ActiveSupport :: Concern包装一起,它足以支持这种轻量级因子机制.
Aad*_*ain 372
我一直在阅读有关使用模型问题来修饰脂肪模型以及干掉模型代码的问题.以下是对示例的解释:
考虑文章模型,事件模型和评论模型.文章或事件有很多评论.评论属于文章或事件.
传统上,模型可能如下所示:
评论模型:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Run Code Online (Sandbox Code Playgroud)
文章模型:
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
Run Code Online (Sandbox Code Playgroud)
事件模型
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
Run Code Online (Sandbox Code Playgroud)
我们可以注意到,事件和文章都有一个共同的重要代码.使用关注点,我们可以在单独的模块中提取此公共代码.
为此,在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
Run Code Online (Sandbox Code Playgroud)
现在您的模型看起来像这样:
评论模型:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Run Code Online (Sandbox Code Playgroud)
文章模型:
class Article < ActiveRecord::Base
include Commentable
end
Run Code Online (Sandbox Code Playgroud)
活动模型:
class Event < ActiveRecord::Base
include Commentable
end
Run Code Online (Sandbox Code Playgroud)
考虑事件模型.一个活动有很多参与者和评论.
通常,事件模型可能如下所示
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
Run Code Online (Sandbox Code Playgroud)
具有许多关联的模型,否则倾向于积累越来越多的代码并变得难以管理.关注点提供了一种皮肤化脂肪模块的方法,使它们更加模块化和易于理解.
可以使用以下关注点重构上述模型:在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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
现在使用Concerns,您的事件模型减少到
class Event < ActiveRecord::Base
include Commentable
include Attendable
end
Run Code Online (Sandbox Code Playgroud)
*在使用问题时,建议采用"域名"分组而不是"技术"分组.基于域的分组就像"可评论","可照片","可以参加".技术分组将意味着'ValidationMethods','FinderMethods'等
Dr.*_*ove 94
值得一提的是,使用顾虑被很多人认为是坏主意.
一些原因:
include方法,有一个完整的依赖处理系统 - 对于一些琐碎的旧Ruby混合模式的东西太复杂了.关注是轻松拍摄腿部的方法,小心使用它们.
ami*_*tob 55
这篇文章帮助我理解了问题.
# app/models/trader.rb
class Trader
include Shared::Schedule
end
# app/models/concerns/shared/schedule.rb
module Shared::Schedule
extend ActiveSupport::Concern
...
end
Run Code Online (Sandbox Code Playgroud)
Siv*_*iva 39
我觉得这里的大多数例子都展示了权力,module而不是如何ActiveSupport::Concern增加价值module.
示例1:更易读的模块.
所以不用担心这是一个典型的例子module.
module M
def self.included(base)
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
def instance_method
...
end
module ClassMethods
...
end
end
Run Code Online (Sandbox Code Playgroud)
重构后ActiveSupport::Concern.
require 'active_support/concern'
module M
extend ActiveSupport::Concern
included do
scope :disabled, -> { where(disabled: true) }
end
class_methods do
...
end
def instance_method
...
end
end
Run Code Online (Sandbox Code Playgroud)
您会看到实例方法,类方法和包含的块不那么混乱.担忧会为您注入适当的注意力.这是使用的一个优点ActiveSupport::Concern.
示例2:正常处理模块依赖关系.
module Foo
def self.included(base)
base.class_eval do
def self.method_injected_by_foo_to_host_klass
...
end
end
end
end
module Bar
def self.included(base)
base.method_injected_by_foo_to_host_klass
end
end
class Host
include Foo # We need to include this dependency for Bar
include Bar # Bar is the module that Host really needs
end
Run Code Online (Sandbox Code Playgroud)
在这个例子中Bar是Host真正需要的模块.但是因为对班级的Bar依赖必须(但等待为什么要知道?可以避免吗?).FooHostinclude FooHostFoo
所以Bar它随处可见依赖性增加.并且**包含的顺序在这里也很重要.**这为巨大的代码库增加了许多复杂性/依赖性.
重构后 ActiveSupport::Concern
require 'active_support/concern'
module Foo
extend ActiveSupport::Concern
included do
def self.method_injected_by_foo_to_host_klass
...
end
end
end
module Bar
extend ActiveSupport::Concern
include Foo
included do
self.method_injected_by_foo_to_host_klass
end
end
class Host
include Bar # It works, now Bar takes care of its dependencies
end
Run Code Online (Sandbox Code Playgroud)
现在看起来很简单.
如果你在想为什么我们不能Foo在Bar模块本身中添加依赖?这不会起作用,因为method_injected_by_foo_to_host_klass必须在类中注入,Bar而不是Bar模块本身.
关注make文件filename.rb
例如,我想在我的应用程序中,属性create_by存在,将值更新为1,更新为update_by
module TestConcern
extend ActiveSupport::Concern
def checkattributes
if self.has_attribute?(:created_by)
self.update_attributes(created_by: 1)
end
if self.has_attribute?(:updated_by)
self.update_attributes(updated_by: 0)
end
end
end
Run Code Online (Sandbox Code Playgroud)
之后,在您的模型中包含如下:
included do
before_action only: [:create] do
blaablaa(options)
end
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
222769 次 |
| 最近记录: |