2009-07-01 2 views
234

저는 레일스를 정말 좋아해요. (일반적으로 무방하지만) 루비는 매우 좋아해요. 그래도 거대한 ActiveRecord 서브 클래스와 거대한 컨트롤러를 만드는 경향은 매우 당연합니다 (리소스 당 컨트롤러를 사용하더라도). 더 깊은 객체 세계를 만들려면 클래스 (및 모듈)를 어디에 두겠습니까? 나는 헬퍼에 대한 견해, 컨트롤러 및 모델에 대해 묻고있다.레일에서 객체 지향 설계 : 물건을 넣을 곳

리브 (Lib)는 괜찮습니다. some solutions to get it to reload in a dev environment을 찾았지만이 방법을 사용하는 것이 더 좋은지 알고 싶습니다. 저는 수업이 너무 커지는 것에 정말로 관심이 있습니다. 또한 엔진은 어떻습니까? 그리고 엔진은 어떻게 들어 맞습니까?

답변

371

레일스는 MVC 관점에서 구조를 제공하기 때문에, 모델, 뷰 및 컨트롤러 컨테이너 만 제공되는 것이 당연합니다. 초보자 (심지어 중간 프로그래머까지도)의 전형적인 관용구는 앱의 모든 로직을 모델 (데이터베이스 클래스), 컨트롤러 또는 뷰로 밀어 넣는 것입니다.

누군가가 "뚱뚱한 모델, 스키니 컨트롤러"패러다임을 지적하고 중간 개발자는 컨트롤러의 모든 것을 급히 소비하고 모델에 던져 응용 로직을위한 새로운 쓰레기통이되기 시작합니다 .

스키니 컨트롤러는 실제로 좋은 생각이지만, 모델에 모든 것을 넣는 것은 실제로 가장 좋은 계획은 아닙니다.

루비에서는 모듈 식으로 만들기위한 몇 가지 좋은 옵션이 있습니다. 상당히 대중적인 대답은 메소드 그룹을 포함하는 모듈 (일반적으로 lib에 있음)을 사용하고 해당 모듈을 적절한 클래스에 포함시키는 것입니다. 이 기능은 여러 클래스에서 재사용하려는 기능의 범주가 있지만 기능이 여전히 클래스에 개념적으로 연결된 경우에 유용합니다.

모듈을 클래스에 포함하면 메서드가 클래스의 인스턴스 메서드가되므로 여전히 개의 메서드가 포함 된 클래스로 끝납니다.이 코드는 여러 파일로 잘 구성되어 있습니다.

이 솔루션은 경우에 따라 제대로 작동 할 수 있습니다. 다른 경우에는 코드에서 이 아닌 모델, 뷰 또는 컨트롤러 인 클래스를 사용하는 것이 좋습니다.

그것에 대해 생각하는 좋은 방법은 하나의 (또는 소수의) 사물에 대해 책임을 져야한다고 말하는 "단일 책임 원칙"입니다. 모델은 응용 프로그램의 데이터를 데이터베이스에 지속시키는 역할을합니다. 귀하의 컨트롤러는 요청을 받고 실행 가능한 응답을 반환 할 책임이 있습니다.

이러한 상자에 일관성이없는 개념 (지속성, 요청/응답 관리)이 있다면 이 해당 아이디어를 어떻게 모델화하는지 생각하고 싶을 것입니다. , 당신은 아마 또한 당신을 추가 할

config.load_paths << File.join(Rails.root, "app", "classes") 

당신이 승객 또는 JRuby를를 사용하는 경우 : 당신은 응용 프로그램/클래스에서 비 모델 클래스를 저장하거나 다른 곳과 수행하여 하중 경로에 디렉토리를 추가 할 수 있습니다 열망로드 경로 경로 :

config.eager_load_paths << File.join(Rails.root, "app", "classes") 

하단 라인은 당신이 당신 자신이 질문을 찾을 레일의 지점에 도착하면, 그것은 때로 믿을 모델링 클래스를 루비 갈비를 강화하고 시작하는 시간이다 Rails가 기본적으로 제공하는 MVC 클래스 일뿐입니다.

업데이트 :이 답변은 Rails 2.x 이상에 적용됩니다.

+0

D' oh. 비 모델을위한 별도의 디렉토리를 추가하는 것은 나에게 발생하지 않았다. 나는 깔끔한 분위기가 느껴진다. –

+0

예후 다, 고마워. 좋은 대답.컨트롤러, 모델, 뷰 및 헬퍼의 모든 것이 컨트롤러 및 뷰에 자동으로 제공됩니다. 상속받은 앱에서 볼 수있는 바로 그 것입니다. 그런 다음 lib에서 mixins를 가져 오지 만 실제 OO 모델링을 시도한 적이 없습니다. 그렇습니다. "앱/수업 또는 그 밖의 모든 곳에서." 그냥 누락 된 몇 가지 표준 답변이 있는지 확인하고 싶습니다 ... –

+33

더 최신 버전에서는 config.autoload_paths가 app 아래의 모든 디렉토리로 기본 설정됩니다. 따라서 위에서 설명한대로 config.load_paths를 변경할 필요가 없습니다. 나는 eager_load_paths (아직)에 대해서는 잘 모르겠다. 그리고 그것에 대해 조사 할 필요가있다. 아무도 이미 알고 있니? –

58

업데이트 : 우려 사항은 confirmed as the new default in Rails 4입니다.

정말 모듈 자체의 특성에 따라 다릅니다. 저는 보통 컨트롤러/모델 확장을 앱 내의/concern 폴더에 넣습니다.

# concerns/authentication.rb 
module Authentication 
    ... 
end  

# controllers/application_controller.rb 
class ApplicationController 
    include Authentication 
end 



# concerns/configurable.rb 
module Configurable 
    ... 
end  

class Model 
    include Indexable 
end 

# controllers/foo_controller.rb 
class FooController < ApplicationController 
    include Indexable 
end 

# controllers/bar_controller.rb 
class BarController < ApplicationController 
    include Indexable 
end 

/lib가 일반용 라이브러리에 대한 선호하는 선택입니다. 필자는 모든 응용 프로그램 별 라이브러리를 배치하는 lib에 항상 프로젝트 네임 스페이스를 가지고 있습니다.

/lib/myapp.rb 
module MyApp 
    VERSION = ... 
end 

/lib/myapp/CacheKey.rb 
/lib/myapp/somecustomlib.rb 

Ruby/Rails 코어 확장은 일반적으로 구성 초기화 프로그램에서 발생하므로 라이브러리는 레일스 부스트랩에 한 번만로드됩니다.

/config/initializer/config.rb 
/config/initializer/core_ext/string.rb 
/config/initializer/core_ext/array.rb 

재사용 가능한 코드 조각의 경우, 다른 프로젝트에서 재사용 할 수 있도록 종종 (마이크로) 플러그인을 만듭니다.

도우미 파일은 일반적으로 도우미 메서드 (예 : 양식 작성기)에서 개체를 사용하려는 경우 도우미 메서드 및 클래스를 보유합니다.

이것은 정말 일반적인 개요입니다. 더 많은 맞춤형 추천을 얻으려면 구체적인 예에 ​​대한 자세한 정보를 제공하십시오. :)

+0

기괴한 것. 이걸 얻을 수 없어요. require_dependency RAILS_ROOT + "/ lib/my_module" lib 디렉토리에서 뭔가를 처리 할 수 ​​없습니다. 파일을 찾을 수 없지만 파일을 다시로드하지 않으면 확실히 실행되고 불만을 제기합니다. –

+0

루비의 요구 사항은 한 번만 물건을로드합니다. 무조건 무언가를로드하려면로드를 사용하십시오. – Chuck

+0

또한 앱 인스턴스의 수명 기간 동안 파일을 두 번로드하려는 경우가 매우 드뭅니다. 코드를 생성하는 중입니까? – Chuck

10

... 경향은 ...

는 "거대한"는 우려 단어입니다 ... 거대한 액티브 서브 클래스 거대한 컨트롤러는 매우 자연스러운 만들 ;-)

컨트롤러가 어떻게 커질까요? 그것은 당신이 살펴 봐야 할 것입니다 : 이상적으로 컨트롤러는 얇아야합니다. 얇은 공기에서 엄지 손가락을 뽑아 내면 컨트롤러 메서드 (동작) 당 5 줄 또는 6 줄 이상의 코드를 정기적으로 사용하면 컨트롤러가 너무 뚱뚱하다고 제안 할 수 있습니다. 헬퍼 함수 또는 필터로 이동할 수있는 중복이 있습니까? 모델로 밀어 넣을 수있는 비즈니스 로직이 있습니까?

모델이 어떻게 커질 수 있습니까? 각 반에서 책임 수를 줄이는 방법을 찾아야합니까? 믹스 인으로 추출 할 수있는 공통적 인 행동이 있습니까? 또는 헬퍼 클래스에 위임 할 수있는 기능 영역?

편집 : ... 잘하면 너무 심하게 아무것도 왜곡하지, 조금 확장하려고

헬퍼 : app/helpers에 살고있는 대부분의 전망을 간단하게하는 데 사용됩니다.그것들은 컨트롤러 관련 (컨트롤러에 대한 모든 뷰에서도 사용 가능)이거나 일반적으로 사용 가능합니다 (application_helper.rb에서 module ApplicationHelper).

필터 : 여러 작업 (동일한 경우 params[:id] 또는 그 유사 물을 사용하여 개체를 검색하는 경우)에서 동일한 코드 줄을 사용한다고 가정 해보십시오. 그 복제는 먼저 별도의 메소드로 추출한 다음 클래스 정의에서 필터 (예 : before_filter :get_object)를 선언하여 액션에서 완전히 추출 할 수 있습니다. ActionController Rails Guide의 섹션 6을 참조하십시오. 선언적 프로그래밍을 친구로 삼으십시오.

리팩터링 모델은 종교적인면에서 조금 더 중요합니다. 예를 들어, Uncle Bob의 제자는 당신이 SOLID의 다섯 계명을 따를 것을 제안합니다. Joel & 제프 may recommend 더 많은, 어, "실용적인"접근 방식, 이후 그들은 little more reconciled 것으로 보였습니다. 클래스에서 속성의 명확하게 정의 된 하위 집합에서 작동하는 하나 이상의 메소드를 찾는 것이 ActiveRecord 파생 모델에서 리팩토링 될 수있는 클래스를 식별하는 방법 중 하나입니다.

레일즈 모델은 ActiveRecord :: Base의 서브 클래스 일 필요는 없습니다. 또는 다른 방식으로 말하면, 모델은 테이블의 아날로그이거나 심지어 전혀 저장된 것과 관련 될 필요가 없습니다. 더 좋게도, 레일스 규약에 따라 파일 이름을 app/models (클래스 이름에 대해 #underscore라고 부름)하면, 레일스는 require이 필요없이 찾을 수 있습니다.

+0

에 관한 것입니다. Mike, 귀하의 관심에 감사 드리며 ... 저는 거대한 컨트롤러에 몇 가지 방법이있는 프로젝트를 상속 받았습니다. 나는 이것을 작은 방법으로 분해했지만 컨트롤러 자체는 여전히 "뚱뚱하다." 그래서 제가 찾고있는 것은 물건을 내릴 수있는 모든 옵션입니다. 귀하의 대답은 "도우미 기능", "필터", "모델", "믹스 인"및 "도우미 클래스"입니다. 그렇다면 어디서 이런 것들을 넣을 수 있습니까? dev env에서 자동로드되는 클래스 계층 구조를 구성 할 수 있습니까? –