天天看点

如何在Rails 4中使用问题

本文翻译自:How to use concerns in Rails 4

The default Rails 4 project generator now creates the directory "concerns" under controllers and models.

默认的Rails 4项目生成器现在在控制器和模型下创建目录“Concer”。

I have found some explanations about how to use routing concerns, but nothing about controllers or models.

我找到了一些关于如何使用路由问题的解释,但没有关于控制器或模型的解释。

I am pretty sure it has to do with the current "DCI trend" in the community and would like to give it a try.

我很确定它与社区当前的“DCI趋势”有关,并且想尝试一下。

The question is, how am I supposed to use this feature, is there a convention on how to define the naming / class hierarchy in order to make it work?

问题是,我应该如何使用此功能,是否有关于如何定义命名/类层次结构以使其工作的约定?

How can I include a concern in a model or controller?

如何在模型或控制器中包含问题?

#1楼

参考:https://stackoom.com/question/z0zX/如何在Rails-中使用问题

#2楼

So I found it out by myself.

所以我自己发现了它。

It is actually a pretty simple but powerful concept.

它实际上是一个非常简单但功能强大的概念。

It has to do with code reuse as in the example below.

它与代码重用有关,如下例所示。

Basically, the idea is to extract common and / or context specific chunks of code in order to clean up the models and avoid them getting too fat and messy.

基本上,这个想法是提取常见的和/或特定于上下文的代码块,以便清理模型并避免它们变得太胖和混乱。

As an example, I'll put one well known pattern, the taggable pattern:

作为一个例子,我将放置一个众所周知的模式,可标记的模式:
# 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
           

So following the Product sample, you can add Taggable to any class you desire and share its functionality.

因此,按照Product示例,您可以将Taggable添加到您想要的任何类并共享其功能。

This is pretty well explained by DHH :

DHH很好地解释了这一点:
In Rails 4, we're going to invite programmers to use concerns with the default app/models/concerns and app/controllers/concerns directories that are automatically part of the load path. 在Rails 4中,我们将邀请程序员使用默认app / models / concerns和app / controllers / concerns目录中的问题,这些目录自动成为加载路径的一部分。 Together with the ActiveSupport::Concern wrapper, it's just enough support to make this light-weight factoring mechanism shine. 与ActiveSupport :: Concern包装一起,它足以支持这种轻量级因子机制。

#3楼

This post helped me understand concerns.

这篇文章帮助我理解了问题。
# app/models/trader.rb
class Trader
  include Shared::Schedule
end

# app/models/concerns/shared/schedule.rb
module Shared::Schedule
  extend ActiveSupport::Concern
  ...
end
           

#4楼

I have been reading about using model concerns to skin-nize fat models as well as DRY up your model codes.

我一直在阅读有关使用模型问题来修饰脂肪模型以及干掉模型代码的问题。

Here is an explanation with examples:

以下是对示例的解释:

1) DRYing up model codes 1)干掉型号代码

Consider a Article model, a Event model and a Comment model.

考虑文章模型,事件模型和评论模型。

An article or an event has many comments.

文章或事件有很多评论。

A comment belongs to either Article or Event.

评论属于文章或事件。

Traditionally, the models may look like this:

传统上,模型可能如下所示:

Comment Model:

评论模型:
class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end
           

Article Model:

文章模型:
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
           

Event Model

事件模型
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
           

As we can notice, there is a significant piece of code common to both Event and Article.

我们可以注意到,事件和文章都有一个共同的重要代码。

Using concerns we can extract this common code in a separate module Commentable.

使用关注点,我们可以在单独的模块中提取此公共代码。

For this create a commentable.rb file in app/models/concerns.

为此,在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
           

And now your models look like this :

现在您的模型看起来像这样:

Comment Model:

评论模型:
class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end
           

Article Model:

文章模型:
class Article < ActiveRecord::Base
  include Commentable
end
           

Event Model:

活动模型:
class Event < ActiveRecord::Base
  include Commentable
end
           

2) Skin-nizing Fat Models. 2)皮肤肥胖模型。

Consider a Event model.

考虑事件模型。

A event has many attenders and comments.

一个活动有很多参与者和评论。

Typically, the event model might look like this

通常,事件模型可能如下所示
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
           

Models with many associations and otherwise have tendency to accumulate more and more code and become unmanageable.

具有许多关联的模型,否则倾向于积累越来越多的代码并变得难以管理。

Concerns provide a way to skin-nize fat modules making them more modularized and easy to understand.

关注点提供了一种皮肤化脂肪模块的方法,使它们更加模块化和易于理解。

The above model can be refactored using concerns as below: Create a

attendable.rb

and

commentable.rb

file in app/models/concerns/event folder

可以使用以下关注点重构上述模型:在app / models / concerns / event文件夹中创建

attendable.rb

commentable.rb

文件

attendable.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

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
           

And now using Concerns, your Event model reduces to

现在使用Concerns,您的事件模型减少到
class Event < ActiveRecord::Base
  include Commentable
  include Attendable
end
           

* While using concerns its advisable to go for 'domain' based grouping rather than 'technical' grouping.

*在使用问题时,建议采用“域名”分组而不是“技术”分组。

Domain Based grouping is like 'Commentable', 'Photoable', 'Attendable'.

基于域的分组就像“可评论”,“可照片”,“可以参加”。

Technical grouping will mean 'ValidationMethods', 'FinderMethods' etc

技术分组将意味着'ValidationMethods','FinderMethods'等

#5楼

In concerns make file filename.rb

关注make文件filename.rb

For example I want in my application where attribute create_by exist update there value by 1, and 0 for updated_by

例如,我想在我的应用程序中,属性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
           

If you want to pass arguments in action

如果你想传递参数
included do
   before_action only: [:create] do
     blaablaa(options)
   end
end
           

after that include in your model like this:

之后,在您的模型中包含如下:
class Role < ActiveRecord::Base
  include TestConcern
end
           

#6楼

It's worth to mention that using concerns is considered bad idea by many.

值得一提的是,使用顾虑被很多人认为是坏主意。
  1. like this guy 喜欢这个家伙
  2. and this one 还有这个

Some reasons:

一些原因:
  1. There is some dark magic happening behind the scenes - Concern is patching

    include

    method, there is a whole dependency handling system - way too much complexity for something that's trivial good old Ruby mixin pattern. 幕后发生了一些黑暗魔法 - 关注是修补

    include

    方法,有一个完整的依赖处理系统 - 对于一些琐碎的好旧Ruby混合模式的东西太复杂了。
  2. Your classes are no less dry. 你的课程也不干。 If you stuff 50 public methods in various modules and include them, your class still has 50 public methods, it's just that you hide that code smell, sort of put your garbage in the drawers. 如果你在各种模块中填充50个公共方法并包含它们,你的类仍然有50个公共方法,只是你隐藏了代码味道,有点把你的垃圾放在抽屉里。
  3. Codebase is actually harder to navigate with all those concerns around. 代码库实际上更难以解决所有这些问题。
  4. Are you sure all members of your team have same understanding what should really substitute concern? 您确定您的团队中的所有成员都有同样的理解应该真正替代关注点吗?

Concerns are easy way to shoot yourself in the leg, be careful with them.

关注是轻松拍摄腿部的方法,小心使用它们。