기본 Rails 4 프로젝트 생성기는 이제 컨트롤러 및 모델 아래에 “우려”디렉토리를 만듭니다. 라우팅 문제를 사용하는 방법에 대한 설명을 찾았지만 컨트롤러 나 모델에 대해서는 설명하지 않았습니다.
커뮤니티의 현재 “DCI 트렌드”와 관련이 있으며 시도해보고 싶습니다.
문제는이 기능을 어떻게 사용해야합니까? 네이밍 / 클래스 계층 구조를 정의하여 작동하게하는 방법에 대한 규칙이 있습니까? 모델이나 컨트롤러에 관심을 어떻게 포함시킬 수 있습니까?
답변
그래서 나는 그것을 스스로 알아 냈습니다. 실제로는 매우 단순하지만 강력한 개념입니다. 아래 예제와 같이 코드 재사용과 관련이 있습니다. 기본적으로 아이디어는 모델을 정리하고 너무 뚱뚱하고 지저분 해지는 것을 피하기 위해 공통 및 / 또는 컨텍스트 특정 코드 덩어리를 추출하는 것입니다.
예를 들어, 잘 알려진 하나의 태그 가능한 패턴을 넣겠습니다.
# 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
따라서 제품 샘플에 따라 원하는 모든 클래스에 Taggable을 추가하고 기능을 공유 할 수 있습니다.
이것은 DHH에 의해 잘 설명되어 있습니다 .
Rails 4에서는 자동으로로드 경로의 일부인 기본 app / models / concerns 및 app / controllers / concerns 디렉토리에 관심을 갖도록 프로그래머를 초대합니다. ActiveSupport :: Concern 래퍼와 함께이 경량 팩토링 메커니즘을 빛나게하는 데 충분한 지원입니다.
답변
나는 모델 코드를 건조 할뿐만 아니라 뚱뚱한 모델을 피부 에 맞게 만들기 위해 모델 문제 를 사용하는 것에 대해 읽었 습니다. 다음은 예제를 사용한 설명입니다.
1) 모델 코드 건조
기사 모델, 이벤트 모델 및 설명 모델을 고려하십시오. 기사 나 이벤트에는 많은 의견이 있습니다. 의견은 기사 또는 이벤트에 속합니다.
전통적으로 모델은 다음과 같습니다.
댓글 모델 :
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
알다시피, 이벤트와 기사 모두에 공통적 인 중요한 코드가 있습니다. 우려 사항을 사용하여이 공통 코드를 별도의 모듈 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
많은 연관성이 있고 그렇지 않으면 더 많은 코드를 누적하고 관리 할 수없는 경향이있는 모델이 있습니다. 우려 사항은 지방 모듈을 피부에 맞게 처리하여보다 모듈화되고 이해하기 쉬운 방법을 제공합니다.
위의 모델은 다음과 같은 우려를 사용하여 리팩토링 할 수 있습니다 : a 작성 attendable.rb
및commentable.rb
app / models / concerns / event 폴더에 파일
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
이제 관심사를 사용하면 이벤트 모델이
class Event < ActiveRecord::Base
include Commentable
include Attendable
end
* 사용하는 동안 ‘기술적’그룹화보다는 ‘도메인’기반 그룹화를 사용하는 것이 좋습니다. 도메인 기반 그룹은 ‘Commentable’, ‘Photoable’, ‘Attendable’과 같습니다. 기술 그룹화는 ‘ValidationMethods’, ‘FinderMethods’등을 의미합니다.
답변
많은 사람들은 우려를 이용하는 것이 나쁜 생각으로 여겨진다는 것을 언급 할 가치가 있습니다.
몇 가지 이유 :
- 배후에는 약간의 어두운 마법이 있습니다. 문제는 패치
include
방법입니다. 전체 의존성 처리 시스템이 있습니다. 아주 오래된 오래된 Ruby 믹스 인 패턴에는 너무 복잡합니다. - 당신의 수업은 더 건조하지 않습니다. 다양한 모듈에 50 개의 퍼블릭 메소드를 채우고 포함 시키면 클래스에 여전히 50 개의 퍼블릭 메소드가 있습니다.이 코드 냄새를 숨기고 쓰레기를 서랍에 넣는 것입니다.
- 코드베이스는 실제로 모든 문제를 탐색하기가 더 어렵습니다.
- 팀의 모든 구성원이 실제로 대체해야 할 사항을 동일하게 이해하고 있습니까?
우려 사항은 다리에 자신을 쏠 수있는 쉬운 방법이므로 조심하십시오.
답변
이 게시물 은 관심사를 이해하는 데 도움 이되었습니다 .
# app/models/trader.rb
class Trader
include Shared::Schedule
end
# app/models/concerns/shared/schedule.rb
module Shared::Schedule
extend ActiveSupport::Concern
...
end
답변
나는 여기에있는 대부분의 예 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
와 리팩토링 후 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
인스턴스 메소드, 클래스 메소드 및 포함 된 블록이 덜 지저분하다는 것을 알 수 있습니다. 우려 사항이 귀하에게 적절하게 주입됩니다. 이것이을 사용하는 이점 중 하나입니다 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
이 예에서는 실제로 필요한 Bar
모듈입니다 Host
. 그러나 클래스 Bar
와 Foo
의 종속성이 있기 때문에Host
include Foo
(그러나 않는 이유를 대기 Host
에 대해 알고 싶은가 Foo
? 그것은 피할 수 있습니까?).
그래서 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
이제 간단 해 보입니다.
모듈 자체 에 Foo
의존성을 추가 할 수없는 이유를 생각하고 있다면 Bar
? 그렇지 않은 method_injected_by_foo_to_host_klass
클래스에 주입해야하기 때문에 작동 Bar
하지 않습니다.Bar
모듈 자체 .
답변
우려 파일 이름을 만듭니다 .rb
예를 들어 속성 create_by가 존재하는 응용 프로그램에서 1 씩 값을 업데이트하고 updated_by에 대해 0을 원합니다.
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
인수를 실제로 전달하려면
included do
before_action only: [:create] do
blaablaa(options)
end
end
그런 다음 모델에 다음과 같이 포함하십시오.
class Role < ActiveRecord::Base
include TestConcern
end