엔진 시작하기

이 가이드에서는 엔진에 대해 알아보고 어떻게 호스트 애플리케이션에 추가 기능을 제공할 수 있는지 배울 것입니다.

이 가이드를 읽고 나면 다음을 알 수 있습니다:

  • 엔진이란 무엇인지.
  • 엔진을 생성하는 방법.
  • 엔진에 기능을 추가하는 방법.
  • 애플리케이션에 엔진을 연결하는 방법.
  • 애플리케이션에서 엔진 기능을 재정의하는 방법.
  • 로드 및 구성 훅을 사용하여 Rails 프레임워크를 로드하지 않는 방법.

엔진이란?

엔진은 호스트 애플리케이션에 기능을 제공하는 “미니 애플리케이션"으로 간주될 수 있습니다. Rails 애플리케이션은 실제로 Rails::Application 클래스가 Rails::Engine의 많은 동작을 상속받는 "강화된” 엔진에 불과합니다.

따라서 엔진과 애플리케이션은 미묘한 차이점을 제외하고는 거의 동일한 것으로 간주될 수 있습니다. 엔진과 애플리케이션은 공통 구조를 공유합니다.

엔진은 플러그인과도 밀접한 관련이 있습니다. 두 가지 모두 공통 lib 디렉토리 구조를 가지고 있으며 rails plugin new 생성기를 사용하여 생성됩니다. 차이점은 엔진이 Rails에 의해 “완전한 플러그인"으로 간주된다는 것입니다(생성기 명령에 전달되는 --full 옵션에 의해 표시됨). 여기서는 --mountable 옵션을 사용할 것이며, 이 옵션에는 --full의 모든 기능이 포함되어 있습니다. 이 가이드에서는 이러한 "완전한 플러그인"을 일반적으로 "엔진"이라고 합니다. 엔진은 플러그인이 될 수 있고, 플러그인은 엔진이 될 수 있습니다.

이 가이드에서 생성할 엔진의 이름은 "blorgh"입니다. 이 엔진은 호스트 애플리케이션에 블로깅 기능을 제공하여 새 기사와 댓글을 작성할 수 있게 합니다. 이 가이드의 시작 부분에서는 엔진 자체 내에서만 작업할 것이지만, 나중 섹션에서는 애플리케이션에 연결하는 방법을 살펴볼 것입니다.

엔진은 또한 호스트 애플리케이션에서 격리될 수 있습니다. 이는 애플리케이션이 articles_path와 같은 라우팅 헬퍼 경로를 가질 수 있고 엔진도 articles_path라는 경로를 제공할 수 있지만, 두 경로가 충돌하지 않는다는 것을 의미합니다. 이와 함께 컨트롤러, 모델 및 테이블 이름도 네임스페이스화됩니다. 이에 대해서는 이 가이드의 라우팅 섹션에서 자세히 설명합니다.

항상 애플리케이션이 엔진에 우선한다는 것을 명심해야 합니다. 애플리케이션은 자신의 환경에서 최종 결정권을 가집니다. 엔진은 애플리케이션을 크게 변경하는 것이 아니라 향상시키는 역할을 해야 합니다.

다른 엔진의 데모를 보려면 Devise, Thredded, Spree, Refinery CMS를 확인하세요.

마지막으로, 엔진은 James Adam, Piotr Sarnacki, Rails Core Team 및 기타 많은 사람들의 노력 없이는 불가능했을 것입니다. 이들을 만나면 감사의 말을 잊지 마세요!

엔진 생성하기

엔진을 생성하려면 플러그인 생성기를 실행하고 필요에 따라 적절한 옵션을 전달해야 합니다. "blorgh” 예제의 경우 “마운트 가능한” 엔진을 만들어야 하므로 다음 명령을 터미널에서 실행합니다:

$ rails plugin new blorgh --mountable

플러그인 생성기의 전체 옵션 목록은 다음 명령을 입력하여 확인할 수 있습니다:

$ rails plugin --help

--mountable 옵션은 “마운트 가능"하고 네임스페이스로 격리된 엔진을 만들고 싶다는 것을 생성기에 알려줍니다. 이 생성기는 --full 옵션을 사용하는 것과 동일한 골격 구조를 제공합니다. --full 옵션은 다음과 같은 엔진을 생성하도록 지시합니다:

  • app 디렉토리 트리
  • config/routes.rb 파일:

    Rails.application.routes.draw do
    end
    
  • lib/blorgh/engine.rb에 있는 파일로, 표준 Rails 애플리케이션의 config/application.rb 파일과 기능이 동일합니다:

    module Blorgh
      class Engine < ::Rails::Engine
      end
    end
    

--mountable 옵션은 --full 옵션에 다음을 추가합니다:

  • 자산 매니페스트 파일(blorgh_manifest.jsapplication.css)
  • 네임스페이스화된 ApplicationController 스텁
  • 네임스페이스화된 ApplicationHelper 스텁
  • 엔진의 레이아웃 뷰 템플릿
  • config/routes.rb의 네임스페이스 격리:

    Blorgh::Engine.routes.draw do
    end
    
  • lib/blorgh/engine.rb의 네임스페이스 격리:

    module Blorgh
      class Engine < ::Rails::Engine
        isolate_namespace Blorgh
      end
    end
    

또한 --mountable 옵션은 생성기에게 test/dummy 위치의 더미 테스트 애플리케이션 내에 엔진을 마운트하도록 지시합니다. 이는 test/dummy/config/routes.rb 파일에 다음 내용을 추가합니다:

mount Blorgh::Engine => "/blorgh"

엔진 내부

중요한 파일

이 새로운 엔진의 루트 디렉토리에는 blorgh.gemspec 파일이 있습니다. 나중에 애플리케이션에 엔진을 포함할 때 다음 줄을 Rails 애플리케이션의 Gemfile에 추가할 것입니다:

gem "blorgh", path: "engines/blorgh"

bundle install을 실행하는 것을 잊지 마세요. Gemfile에 gem을 지정하면 Bundler가 이를 gem으로 로드하고 blorgh.gemspec 파일을 구문 분석하며 lib 디렉토리의 lib/blorgh.rb 파일을 요구합니다. 이 파일은 lib/blorgh/engine.rb 파일(위치: lib/blorgh/engine.rb)을 요구하고 Blorgh라는 기본 모듈을 정의합니다.

require "blorgh/engine"

module Blorgh
end

팁: 일부 엔진은 이 파일을 사용하여 엔진의 전역 구성 옵션을 설정합니다. 이는 상당히 좋은 아이디어이므로 구성 옵션을 제공하려면 엔진의 module이 정의된 파일이 완벽한 장소입니다. 모듈 내에 메서드를 배치하면 됩니다.

lib/blorgh/engine.rb 내에는 엔진의 기본 클래스가 있습니다:

module Blorgh
  class Engine < ::Rails::Engine
    isolate_namespace Blorgh
  end
end

Rails::Engine 클래스를 상속함으로써 이 gem은 지정된 경로에 엔진이 있음을 Rails에 알리고 엔진을 애플리케이션 내에 올바르게 마운트하며 모델, 메일러, 컨트롤러 및 뷰의 로드 경로에 엔진의 app 디렉토리를 추가하는 등의 작업을 수행합니다.

여기서 isolate_namespace 메서드에 특별한 주의를 기울일 필요가 있습니다. 이 호출은 컨트롤러, 모델, 라우팅 및 기타 항목을 자체 네임스페이스로 격리하여 애플리케이션 내부와 분리하는 역할을 합니다. 그렇지 않으면 엔진의 구성 요소가 애플리케이션으로 "누출"되어 원치 않는 혼란을 일으키거나 중요한 엔진 구성 요소가 애플리케이션 내의 유사한 이름의 항목에 의해 재정의될 수 있습니다. 이러한 충돌의 한 예는 헬퍼입니다. isolate_namespace를 호출하지 않으면 엔진의 헬퍼가 애플리케이션의 컨트롤러에 포함될 수 있습니다.

참고: isolate_namespace 줄을 엔진 클래스 정의 내에 두는 것이 매우 권장됩니다. 그렇지 않으면 엔진에서 생성된 클래스가 애플리케이션과 충돌할 수 있습니다.

이 네임스페이스 격리가 의미하는 바는 bin/rails generate model과 같은 호출로 생성된 모델이 Article이 아닌 Blorgh::Article로 불리게 된다는 것입니다. 또한 모델의 테이블 이름도 articles가 아닌 blorgh_articles가 됩니다. 모델 네임스페이싱과 유사하게 ArticlesController라는 컨트롤러는 Blorgh::ArticlesController가 되며, 해당 컨트롤러의 뷰는 app/views/articles가 아닌 app/views/blorgh/articles에 있습니다. 메일러, 작업 및 헬퍼도 네임스페이스화됩니다.

마지막으로, 라우팅도 엔진 내에서 격리됩니다. 이는 네임스페이싱의 가장 중요한 부분 중 하나이며 이 가이드의 라우팅 섹션에서 자세히 설명됩니다.

app 디렉토리

app 디렉토리에는 assets, controllers, helpers, jobs, mailers, modelsviews 디렉토리가 있으며, 이는 애플리케이션에서 익숙한 것과 유사합니다. 모델에 대해서는 향후 섹션에서 자세히 살펴볼 것입니다.

app/assets 디렉토리에는 imagesstylesheets 디렉토리가 있으며, 이 또한 애플리케이션과 유사합니다. 그러나 여기의 차이점은 각 디렉토리에 엔진 이름의 하위 디렉토리가 포함되어 있다는 것입니다. 이 엔진이 네임스페이스화될 것이므로 자산도 네임스페이스화해야 합니다.

app/controllers 디렉토리에는 blorgh 디렉토리가 있으며 이 디렉토리에는 application_controller.rb라는 파일이 포함되어 있습니다. 이 파일은 엔진의 컨트롤러에 대한 공통 기능을 제공할 것입니다. blorgh 디렉토리는 엔진의 다른 네, 계속해서 번역하겠습니다.

app/controllers 디렉토리에는 blorgh 디렉토리가 있으며 이 디렉토리에는 application_controller.rb라는 파일이 포함되어 있습니다. 이 파일은 엔진의 컨트롤러에 대한 공통 기능을 제공할 것입니다. blorgh 디렉토리는 엔진의 다른 컨트롤러가 위치할 곳입니다. 이 네임스페이스화된 디렉토리에 파일을 배치하면 다른 엔진이나 애플리케이션 내의 동일한 이름의 컨트롤러와 충돌할 가능성을 방지할 수 있습니다.

참고: 엔진 내의 ApplicationController 클래스는 애플리케이션의 ApplicationController와 동일한 이름을 가지고 있어 애플리케이션을 엔진으로 변환하기 쉽습니다.

app/controllers와 마찬가지로 app/helpers, app/jobs, app/mailersapp/models 디렉토리에도 공통 기능을 모으는 관련 application_*.rb 파일이 포함된 blorgh 하위 디렉토리가 있습니다. 파일을 이 하위 디렉토리에 배치하고 객체를 네임스페이스화하면 다른 엔진이나 애플리케이션 내의 동일한 이름의 요소와 충돌할 가능성을 방지할 수 있습니다.

마지막으로 app/views 디렉토리에는 layouts 폴더가 있으며 여기에는 blorgh/application.html.erb라는 파일이 포함되어 있습니다. 이 파일을 사용하여 엔진의 레이아웃을 지정할 수 있습니다. 이 엔진을 독립형 엔진으로 사용하려는 경우 이 파일에 레이아웃에 대한 사용자 지정을 추가하면 됩니다. 애플리케이션의 app/views/layouts/application.html.erb 파일이 아닌 이 파일을 사용하면 됩니다.

엔진 사용자에게 레이아웃을 강요하고 싶지 않다면 이 파일을 삭제하고 엔진의 컨트롤러에서 다른 레이아웃을 참조할 수 있습니다.

bin 디렉토리

이 디렉토리에는 bin/rails 파일 하나가 포함되어 있으며, 이를 통해 애플리케이션 내에서와 마찬가지로 rails 하위 명령 및 생성기를 사용할 수 있습니다. 즉, 다음과 같은 명령을 실행하여 엔진에 새 컨트롤러와 모델을 쉽게 생성할 수 있습니다:

$ bin/rails generate model

물론 isolate_namespaceEngine 클래스에 있는 엔진 내에서 생성된 모든 것은 네임스페이스화된다는 점을 명심해야 합니다.

test 디렉토리

test 디렉토리는 엔진에 대한 테스트가 포함될 곳입니다. 엔진을 테스트하기 위해 test/dummy에 축소된 버전의 Rails 애플리케이션이 포함되어 있습니다. 이 애플리케이션은 test/dummy/config/routes.rb 파일에서 엔진을 마운트합니다:

Rails.application.routes.draw do
  mount Blorgh::Engine => "/blorgh"
end

이 줄은 엔진을 /blorgh 경로에 마운트하여 애플리케이션을 통해서만 해당 경로에서 엔진에 액세스할 수 있게 합니다.

테스트 디렉토리 내에는 test/integration 디렉토리가 있으며, 여기에 엔진에 대한 통합 테스트를 배치해야 합니다. 또한 test 디렉토리에 다른 디렉토리를 만들 수 있습니다. 예를 들어 test/models 디렉토리를 만들어 모델 테스트를 배치할 수 있습니다.

엔진 기능 제공하기

이 가이드에서 다루는 엔진은 기사 제출 및 댓글 기능을 제공하며 시작하기 가이드와 유사한 흐름을 따릅니다.

참고: 이 섹션에 대해서는 blorgh 엔진의 루트 디렉토리에서 명령을 실행하세요.

기사 리소스 생성하기

블로그 엔진에 필요한 첫 번째 것은 Article 모델과 관련 컨트롤러입니다. 이를 빠르게 생성하려면 Rails 스캐폴드 생성기를 사용할 수 있습니다.

$ bin/rails generate scaffold article title:string text:text

이 명령은 다음과 같은 출력을 생성합니다:

invoke  active_record
create    db/migrate/[timestamp]_create_blorgh_articles.rb
create    app/models/blorgh/article.rb
invoke    test_unit
create      test/models/blorgh/article_test.rb
create      test/fixtures/blorgh/articles.yml
invoke  resource_route
 route    resources :articles
invoke  scaffold_controller
create    app/controllers/blorgh/articles_controller.rb
invoke    erb
create      app/views/blorgh/articles
create      app/views/blorgh/articles/index.html.erb
create      app/views/blorgh/articles/edit.html.erb
create      app/views/blorgh/articles/show.html.erb
create      app/views/blorgh/articles/new.html.erb
create      app/views/blorgh/articles/_form.html.erb
create      app/views/blorgh/articles/_article.html.erb
invoke    resource_route
invoke    test_unit
create      test/controllers/blorgh/articles_controller_test.rb
create      test/system/blorgh/articles_test.rb
invoke    helper
create      app/helpers/blorgh/articles_helper.rb
invoke      test_unit

스캐폴드 생성기가 수행하는 첫 번째 작업은 active_record 생성기를 호출하는 것입니다. 이는 리소스에 대한 마이그레이션과 모델을 생성합니다. 그러나 여기서 주목할 점은 마이그레이션의 이름이 일반적인 create_articles가 아닌 create_blorgh_articles라는 것입니다. 이는 Engine 클래스 정의에 있는 isolate_namespace 메서드 때문입니다. 모델 또한 app/models/article.rb가 아닌 app/models/blorgh/article.rb에 배치되어 네임스페이스화됩니다.

다음으로 test_unit 생성기가 이 모델에 대해 호출되어 test/models/blorgh/article_test.rb(일반적인 test/models/article_test.rb가 아님)에 모델 테스트를 생성하고 test/fixtures/blorgh/articles.yml(일반적인 test/fixtures/articles.yml가 아님)에 fixture를 생성합니다.

그 다음에는 config/routes.rb 파일에 리소스에 대한 라인이 삽입됩니다. 이 라인은 단순히 resources :articles이며, 엔진의 config/routes.rb 파일을 다음과 같이 만듭니다:

Blorgh::Engine.routes.draw do
  resources :articles
end

여기서 주목할 점은 라우팅이 YourApp::Application 클래스가 아닌 Blorgh::Engine 객체에 그려진다는 것입니다. 이는 엔진 라우팅이 엔진 자체에 국한되고 테스트 디렉토리 섹션에 표시된 대로 특정 지점에 마운트될 수 있도록 하기 위함입니다. 또한 애플리케이션의 라우팅과 엔진의 라우팅이 격리되도록 합니다. 이에 대한 자세한 내용은 이 가이드의 라우팅 섹션에서 설명합니다.

다음으로 scaffold_controller 생성기가 호출되어 Blorgh::ArticlesController(위치: app/controllers/blorgh/articles_controller.rb)라는 컨트롤러와 app/views/blorgh/articles의 관련 뷰를 생성합니다. 이 생성기는 또한 컨트롤러 테스트(test/controllers/blorgh/articles_controller_test.rbtest/system/blorgh/articles_test.rb)와 헬퍼(app/helpers/blorgh/articles_helper.rb)를 생성합니다.

이 생성기가 만든 모든 것은 깔끔하게 네임스페이스화되어 있습니다. 컨트롤러의 클래스는 Blorgh 모듈 내에 정의됩니다:

module Blorgh
  class ArticlesController < ApplicationController
    # ...
  end
end

참고: ArticlesController 클래스는 애플리케이션의 ApplicationController가 아닌 Blorgh::ApplicationController를 상속합니다.

app/helpers/blorgh/articles_helper.rb의 헬퍼도 네임스페이스화되어 있습니다:

module Blorgh
  module ArticlesHelper
    # ...
  end
end

이를 통해 다른 엔진이나 애플리케이션에 기사 리소스가 있는 경우에도 충돌을 방지할 수 있습니다.

엔진 루트에서 bin/rails db:migrate를 실행하여 스캐폴드 생성기가 생성한 마이그레이션을 실행하고 bin/rails servertest/dummy에서 실행하면 생성된 기본 스캐폴드를 볼 수 있습니다. 둘러보세요! 첫 번째 엔진의 첫 번째 기능을 생성했습니다.

콘솔에서 놀아보고 싶다면 bin/rails console도 작동할 것입니다. 기억하세요: Article 모델은 네임스페이스화되어 있으므로 참조하려면 Blorgh::Article로 호출해야 합니다.

irb> Blorgh::Article.find(1)
=> #<Blorgh::Article id: 1 ...>

마지막으로 이 엔진의 articles 리소스는 엔진의 루트가 되어야 합니다. 누군가가 엔진이 마운트된 루트 경로로 이동하면 기사 목록이 표시되어야 합니다. 이를 위해 엔진의 config/routes.rb 파일에 다음 줄을 삽입하면 됩니다:

root to: "articles#index"

이제 사람들은 기사를 보려면 /articles가 아닌 엔진의 루트로 이동하면 됩니다. 즉, http://localhost:3000/blorgh/articles 대신 http://localhost:3000/blorgh로 이동하면 됩니다.

댓글 리소스 생성하기

이제 엔진에서 새 기사를 생성할 수 있으므로 댓글 기능을 추가하는 것도 합리적입니다. 이를 위해 Comment 모델, 댓글 컨트롤러를 생성하고 기사 스캐폴드를 수정하여 댓글을 표시하고 새 댓글을 작성할 수 있게 해야 합니다.

엔진 루트에서 모델 생성기를 실행합니다. Comment 모델을 생성하고 관련 테이블에 article_id 정수와 text 텍스트 열을 만들도록 지시합니다.

$ bin/rails generate model Comment article_id:integer text:text

이 명령은 다음과 같은 출력을 생성합니다:

invoke  active_record
create    db/migrate/[timestamp]_create_blorgh_comments.rb
create    app/models/blorgh/comment.rb
invoke    test_unit
create      test/models/blorgh/comment_test.rb
create      test/fixtures/blorgh/comments.yml

이 생성기 호출은 필요한 모델 파일만 생성하며 파일을 blorgh 디렉토리 아래에 네임스페이스화하고 Blorgh::Comment라는 모델 클래스를 만듭니다. 이제 blorgh_comments 테이블을 만들기 위해네, 계속해서 번역하겠습니다.

이제 blorgh_comments 테이블을 만들기 위해 마이그레이션을 실행합니다:

$ bin/rails db:migrate

기사에 댓글을 표시하려면 app/views/blorgh/articles/show.html.erb를 편집하고 "Edit” 링크 앞에 다음 줄을 추가합니다:

<h3>Comments</h3>
<%= render @article.comments %>

이 줄은 Blorgh::Article 모델에 has_many 댓글 연결이 정의되어 있어야 한다는 것을 의미합니다. 현재는 그렇지 않습니다. 이를 정의하려면 app/models/blorgh/article.rb를 열고 모델에 다음 줄을 추가합니다:

has_many :comments

이렇게 하면 모델이 다음과 같이 됩니다:

module Blorgh
  class Article < ApplicationRecord
    has_many :comments
  end
end

참고: has_manyBlorgh 모듈 내부의 클래스 내에 정의되어 있기 때문에 Rails는 Blorgh::Comment 모델을 사용하려는 것을 알 수 있으므로 :class_name 옵션을 지정할 필요가 없습니다.

다음으로 기사에 댓글을 작성할 수 있는 폼이 필요합니다. 이를 추가하려면 app/views/blorgh/articles/show.html.erb에서 render @article.comments 호출 아래에 다음 줄을 넣습니다:

<%= render "blorgh/comments/form" %>

그런 다음 이 줄이 렌더링할 partial이 존재해야 합니다. app/views/blorgh/comments 디렉토리를 새로 만들고 거기에 _form.html.erb라는 새 파일을 만들어 필요한 partial을 만듭니다:

<h3>New comment</h3>
<%= form_with model: [@article, @article.comments.build] do |form| %>
  <p>
    <%= form.label :text %><br>
    <%= form.text_area :text %>
  </p>
  <%= form.submit %>
<% end %>

이 폼이 제출되면 엔진 내의 /articles/:article_id/commentsPOST 요청을 시도할 것입니다. 이 경로는 아직 존재하지 않지만 config/routes.rbresources :articles 줄을 다음과 같이 변경하여 만들 수 있습니다:

resources :articles do
  resources :comments
end

이렇게 하면 댓글에 대한 중첩 경로가 생성됩니다. 이것이 폼에서 요구하는 바입니다.

경로는 존재하지만 이 경로로 가는 컨트롤러는 아직 없습니다. 이를 생성하려면 엔진 루트에서 다음 명령을 실행합니다:

$ bin/rails generate controller comments

이 명령은 다음과 같은 것을 생성합니다:

create  app/controllers/blorgh/comments_controller.rb
invoke  erb
 exist    app/views/blorgh/comments
invoke  test_unit
create    test/controllers/blorgh/comments_controller_test.rb
invoke  helper
create    app/helpers/blorgh/comments_helper.rb
invoke    test_unit

폼은 /articles/:article_id/commentsPOST 요청을 보낼 것이며, 이는 Blorgh::CommentsControllercreate 액션에 해당합니다. 이 액션을 생성해야 합니다. app/controllers/blorgh/comments_controller.rb의 클래스 정의 내에 다음 줄을 추가하면 됩니다:

def create
  @article = Article.find(params[:article_id])
  @comment = @article.comments.create(comment_params)
  flash[:notice] = "Comment has been created!"
  redirect_to articles_path
end

private
  def comment_params
    params.require(:comment).permit(:text)
  end

새 댓글 폼을 작동시키는 데 필요한 마지막 단계입니다. 그러나 댓글 표시는 아직 제대로 작동하지 않습니다. 지금 댓글을 작성하면 다음과 같은 오류가 발생할 것입니다:

Missing partial blorgh/comments/_comment with {:handlers=>[:erb, :builder],
:formats=>[:html], :locale=>[:en, :en]}. Searched in:   *
"/Users/ryan/Sites/side_projects/blorgh/test/dummy/app/views"   *
"/Users/ryan/Sites/side_projects/blorgh/app/views"

엔진은 댓글 렌더링에 필요한 partial을 찾을 수 없습니다. Rails는 먼저 애플리케이션의(test/dummy) app/views 디렉토리를 찾고 그 다음에 엔진의 app/views 디렉토리를 찾습니다. 찾을 수 없으면 이 오류가 발생합니다. 엔진은 Blorgh::Comment 클래스의 모델 객체를 받기 때문에 blorgh/comments/_comment를 찾아야 합니다.

이 partial은 현재 댓글 텍스트만 렌더링할 것입니다. app/views/blorgh/comments/_comment.html.erb에 새 파일을 만들고 다음 줄을 넣습니다:

<%= comment_counter + 1 %>. <%= comment.text %>

comment_counter 지역 변수는 <%= render @article.comments %>가 제공하는 것이며, 반복할 때마다 자동으로 정의되고 증가합니다. 이 예에서는 각 댓글 옆에 작은 번호를 표시하는 데 사용됩니다.

이로써 블로그 엔진의 댓글 기능이 완성되었습니다. 이제 애플리케이션에서 이를 사용할 차례입니다.

애플리케이션에 연결하기

애플리케이션 내에서 엔진을 사용하는 것은 매우 쉽습니다. 이 섹션에서는 애플리케이션에 엔진을 마운트하고 필요한 초기 설정을 수행하는 방법, 그리고 엔진에 기사와 댓글의 소유권을 제공하도록 애플리케이션의 User 클래스에 연결하는 방법을 다룹니다.

엔진 마운트하기

먼저 Gemfile에 엔진을 지정해야 합니다. 테스트할 애플리케이션이 없다면 엔진 디렉토리 외부에서 rails new 명령을 사용하여 하나를 생성할 수 있습니다:

$ rails new unicorn

일반적으로 Gemfile에 엔진을 지정하는 것은 일반적인 일상적인 gem과 같은 방식으로 수행됩니다.

gem "devise"

그러나 blorgh 엔진을 로컬 머신에서 개발하고 있기 때문에 Gemfile:path 옵션을 사용해야 합니다:

gem "blorgh", path: "engines/blorgh"

그런 다음 bundle을 실행하여 gem을 설치합니다.

앞서 설명한 대로 Gemfile에 gem을 배치하면 Rails가 로드될 때 로드됩니다. 먼저 엔진의 lib/blorgh.rb를 요구한 다음 엔진의 주요 기능을 정의하는 lib/blorgh/engine.rb를 요구합니다.

엔진의 기능을 애플리케이션 내에서 사용할 수 있게 하려면 애플리케이션의 config/routes.rb 파일에 마운트해야 합니다:

mount Blorgh::Engine, at: "/blog"

이 줄은 엔진을 /blog에 마운트합니다. 이렇게 하면 bin/rails server로 애플리케이션을 실행할 때 http://localhost:3000/blog에서 엔진에 액세스할 수 있습니다.

참고: Devise와 같은 다른 엔진은 devise_for와 같은 사용자 지정 헬퍼를 지정하는 방식으로 이를 처리합니다. 이러한 헬퍼는 정확히 같은 작업을 수행하지만 미리 정의된 경로에 엔진의 기능을 마운트하며 이 경로는 사용자 지정이 가능할 수 있습니다.

엔진 설정

엔진에는 blorgh_articlesblorgh_comments 테이블에 대한 마이그레이션이 포함되어 있으며, 엔진의 모델이 이 테이블을 올바르게 쿼리할 수 있도록 애플리케이션의 데이터베이스에 이 테이블을 생성해야 합니다. 이 마이그레이션을 애플리케이션으로 복사하려면 애플리케이션의 루트에서 다음 명령을 실행합니다:

$ bin/rails blorgh:install:migrations

여러 엔진의 마이그레이션을 복사해야 하는 경우 railties:install:migrations를 대신 사용하세요:

$ bin/rails railties:install:migrations

소스 엔진에 대한 마이그레이션 경로를 지정하려면 MIGRATIONS_PATH를 사용할 수 있습니다.

$ bin/rails railties:install:migrations MIGRATIONS_PATH=db_blourgh

여러 데이터베이스가 있는 경우 DATABASE를 지정하여 대상 데이터베이스를 지정할 수도 있습니다.

$ bin/rails railties:install:migrations DATABASE=animals

이 명령을 처음 실행하면 엔진의 모든 마이그레이션이 복사됩니다. 다음에 실행하면 이미 복사된 마이그레이션만 복사됩니다. 이 명령의 첫 번째 실행은 다음과 같은 출력을 생성합니다:

Copied migration [timestamp_1]_create_blorgh_articles.blorgh.rb from blorgh
Copied migration [timestamp_2]_create_blorgh_comments.blorgh.rb from blorgh

첫 번째 타임스탬프([timestamp_1])는 현재 시간이 되고 두 번째 타임스탬프([timestamp_2])는 현재 시간에 1초를 더한 값이 됩니다. 이렇게 하는 이유는 엔진의 마이그레이션이 애플리케이션의 기존 마이그레이션 이후에 실행되도록 하기 위함입니다.

이러한 마이그레이션을 애플리케이션의 컨텍스트에서 실행하려면 단순히 bin/rails db:migrate를 실행하면 됩니다. http://localhost:3000/blog에 액세스하면 기사가 비어 있습니다. 이는 애플리케이션 내에 생성된 테이블이 엔진 내에 생성된 것과 다르기 때문입니다. 새로 마운트된 엔진을 가지고 놀아보세요. 엔진만 있을 때와 동일한 것을 발견할 수 있습니다.

특정 엔진의 마이그레이션만 실행하고 싶다면 SCOPE를 지정하면 됩니다:

$ bin/rails db:migrate SCOPE=blorgh

이는 엔진을 제거하기 전에 엔진의 마이그레이션을 되돌리고 싶은 경우 유용할 수 있습니다. blorgh 엔진의 모든 마이그레이션을 되돌리려면 다음과 같이 실행할 수 있습니다:

$ bin/rails db:migrate SCOPE=blorgh VERSION=0

애플리케이션이 제공하는 클래스 사용하기

애플리케이션이 제공하는 모델 사용하기

엔진이 생성되면 엔진의 구성 요소와 애플리케이션의 구성 요소 간 링크를 제공하기 위해 애플리케이션의 특정 클래스를 사용하고 싶을 수 있습니다. blorgh 엔진의 경우 기사와 댓글에 작성자가 있으면 좋을 것 같습니다.

일반적인 애플리케이션에는 사용자를 나타내는 User 클래스가 있을 수 있습니다. 그러나 애플리케이션에서 이 클네, 계속해서 번역하겠습니다.

일반적인 애플리케이션에는 사용자를 나타내는 User 클래스가 있을 수 있습니다. 그러나 애플리케이션에서 이 클래스를 Person과 같은 다른 이름으로 호출할 수도 있습니다. 이러한 이유로 엔진은 특정 User 클래스에 대한 연결을 하드코딩해서는 안 됩니다.

이 경우 간단하게 유지하기 위해 애플리케이션에 애플리케이션 사용자를 나타내는 User 클래스가 있다고 가정하겠습니다(이를 구성 가능하게 만드는 방법에 대해서는 나중에 다룰 것입니다). 애플리케이션에서 다음 명령을 사용하여 이 클래스를 생성할 수 있습니다:

$ bin/rails generate model user name:string

bin/rails db:migrate 명령을 실행하여 향후 사용을 위해 users 테이블을 만들어야 합니다.

또한 간단하게 유지하기 위해 기사 폼에 author_name이라는 새 텍스트 필드를 추가할 것입니다. 사용자는 이 이름을 입력할 수 있습니다. 엔진은 그런 다음 이 이름을 사용하여 새 User 객체를 만들거나 이미 존재하는 객체를 찾을 것입니다. 엔진은 그런 다음 찾거나 생성된 User 객체와 기사를 연결할 것입니다.

먼저 app/views/blorgh/articles/_form.html.erb 엔진 내의 partial에 author_name 텍스트 필드를 추가해야 합니다. 이를 title 필드 위에 추가할 수 있습니다:

<div class="field">
  <%= form.label :author_name %><br>
  <%= form.text_field :author_name %>
</div>

다음으로 Blorgh::ArticlesController#article_params 메서드를 업데이트하여 새 폼 매개변수를 허용해야 합니다:

def article_params
  params.require(:article).permit(:title, :text, :author_name)
end

그런 다음 Blorgh::Article 모델에서 author_name 필드를 실제 User 객체로 변환하고 기사가 저장되기 전에 해당 객체를 연결해야 합니다. 또한 이 필드에 대한 setter와 getter 메서드를 정의하는 attr_accessor가 필요합니다.

이 모든 것을 수행하려면 app/models/blorgh/article.rbattr_accessorfor author_name, author 연결 및 before_validation 호출을 추가해야 합니다. author 연결은 현재 User 클래스로 하드코딩됩니다.

attr_accessor :author_name
belongs_to :author, class_name: "User"

before_validation :set_author

private
  def set_author
    self.author = User.find_or_create_by(name: author_name)
  end

author 연결의 객체를 User 클래스로 나타냄으로써 엔진과 애플리케이션 간에 링크가 설정됩니다. blorgh_articles 테이블의 레코드와 users 테이블의 레코드를 연결할 방법이 필요합니다. author라는 연결 이름 때문에 blorgh_articles 테이블에 author_id 열이 추가되어야 합니다.

이 새 열을 생성하려면 엔진 내에서 다음 명령을 실행합니다:

$ bin/rails generate migration add_author_id_to_blorgh_articles author_id:integer

참고: 마이그레이션의 이름과 그 뒤의 열 사양 때문에 Rails는 자동으로 특정 테이블에 열을 추가하려는 것을 알고 마이그레이션에 이를 작성합니다. 더 이상 알려줄 필요가 없습니다.

이 마이그레이션은 애플리케이션에서 실행되어야 합니다. 이를 위해 먼저 다음 명령을 사용하여 복사해야 합니다:

$ bin/rails blorgh:install:migrations

여기서는 단 하나의 마이그레이션만 복사되었음에 주목하세요. 이는 처음 이 명령을 실행했을 때 처음 두 개의 마이그레이션이 이미 복사되었기 때문입니다.

NOTE Migration [timestamp]_create_blorgh_articles.blorgh.rb from blorgh has been skipped. Migration with the same name already exists.
NOTE Migration [timestamp]_create_blorgh_comments.blorgh.rb from blorgh has been skipped. Migration with the same name already exists.
Copied migration [timestamp]_add_author_id_to_blorgh_articles.blorgh.rb from blorgh

다음 명령을 사용하여 마이그레이션을 실행합니다:

$ bin/rails db:migrate

이제 모든 부분이 제자리에 있으므로 blorgh_articles 테이블의 레코드와 users 테이블의 레코드, 즉 기사의 작성자가 연결됩니다.

마지막으로 작성자 이름이 기사 페이지에 표시되어야 합니다. app/views/blorgh/articles/_article.html.erb에서 “Title” 출력 위에 다음 코드를 추가합니다:

<p>
  <strong>Author:</strong>
  <%= article.author.name %>
</p>

애플리케이션이 제공하는 컨트롤러 사용하기

일반적으로 Rails 컨트롤러는 인증 및 세션 변수 액세스와 같은 코드를 공유하므로 기본적으로 ApplicationController에서 상속됩니다. 그러나 Rails 엔진은 메인 애플리케이션과 독립적으로 실행되도록 설계되어 있으므로 각 엔진에는 범위가 지정된 ApplicationController가 있습니다. 이 네임스페이스는 코드 충돌을 방지하지만 엔진 컨트롤러는 종종 메인 애플리케이션의 ApplicationController에 있는 메서드에 액세스해야 합니다. 이에 대한 쉬운 방법은 엔진의 범위가 지정된 ApplicationController를 메인 애플리케이션의 ApplicationController에서 상속하도록 변경하는 것입니다. Blorgh 엔진의 경우 app/controllers/blorgh/application_controller.rb를 다음과 같이 변경하면 됩니다:

module Blorgh
  class ApplicationController < ::ApplicationController
  end
end

기본적으로 엔진의 컨트롤러는 Blorgh::ApplicationController에서 상속됩니다. 따라서 이 변경을 수행한 후에는 메인 애플리케이션의 ApplicationController에 액세스할 수 있습니다. 마치 메인 애플리케이션의 일부인 것처럼 동작합니다.

이 변경에는 엔진이 ApplicationController를 가진 Rails 애플리케이션에서 실행되어야 한다는 요구 사항이 있습니다.

엔진 구성하기

이 섹션에서는 사용자 클래스를 구성 가능하게 만드는 방법과 엔진에 대한 일반적인 구성 팁을 다룹니다.

애플리케이션에서 구성 설정 지정하기

다음 단계는 애플리케이션 내에서 사용자를 나타내는 클래스를 엔진에 맞춤형으로 만드는 것입니다. 이는 해당 클래스가 항상 User가 아닐 수 있기 때문입니다(앞서 설명한 바와 같이). 이 구성 설정을 사용자 지정 가능하게 만들기 위해 엔진에 author_class라는 구성 설정이 있습니다.

이 구성 설정을 정의하려면 Blorgh 모듈 내에 mattr_accessor를 사용해야 합니다. lib/blorgh.rb에 다음 줄을 추가합니다:

mattr_accessor :author_class

이 메서드는 attr_accessorcattr_accessor의 형제와 같이 작동하지만 지정된 이름의 setter와 getter 메서드를 모듈에 제공합니다. 이를 사용하려면 Blorgh.author_class로 참조해야 합니다.

다음 단계는 Blorgh::Article 모델을 이 새 설정으로 전환하는 것입니다. app/models/blorgh/article.rbbelongs_to 연결을 다음과 같이 변경합니다:

belongs_to :author, class_name: Blorgh.author_class

Blorgh::Article 모델의 set_author 메서드도 이 클래스를 사용해야 합니다:

self.author = Blorgh.author_class.constantize.find_or_create_by(name: author_name)

author_class 결과를 계속 constantize하지 않도록 하려면 lib/blorgh.rb 파일의 Blorgh 모듈 내에서 author_class getter 메서드를 재정의하여 항상 저장된 값을 constantize하도록 할 수 있습니다:

def self.author_class
  @@author_class.constantize
end

이렇게 하면 set_author의 위 코드가 다음과 같이 약간 더 짧고 암시적인 동작이 됩니다:

self.author = Blorgh.author_class.find_or_create_by(name: author_name)

author_class 메서드가 이제 Class 객체를 반환하므로 Blorgh::Article 모델의 belongs_to 정의도 수정해야 합니다:

belongs_to :author, class_name: Blorgh.author_class.to_s

이 구성 설정을 애플리케이션 내에서 설정하려면 초기화기를 사용해야 합니다. 초기화기를 사용하면 애플리케이션이 시작되고 엔진의 모델이 이 구성 설정에 의존할 수 있기 전에 구성이 설정됩니다.

blorgh 엔진이 설치된 애플리케이션의 config/initializers/blorgh.rb에 새 초기화기를 만들고 다음 내용을 넣습니다:

Blorgh.author_class = "User"

경고: 여기서는 클래스의 String 버전을 사용해야 합니다. 클래스 자체를 사용하면 Rails가 해당 클래스를 로드하려 하고 관련 테이블을 참조하려 할 수 있습니다. 이로 인해 테이블이 아직 존재하지 않는 경우 문제가 발생할 수 있습니다. 따라서 String을 사용하고 나중에 엔진에서 constantize를 사용하여 클래스로 변환해야 합니다.

새 기사를 만들어 보세요. 이전과 동일하게 작동하지만 이번에는 config/initializers/blorgh.rb의 구성 설정을 사용하여 클래스를 알아냅니다.

이제 클래스가 무엇인지에 대한 엄격한 종속성이 없습니다. 엔진에서는 해당 클래스가 find_or_create_by 메서드를 정의하고 기사와 연결될 수 있는 객체를 반환하기만 하면 됩니다. 물론 이 객체에는 참조할 수 있는 식별자가 있어야 합니다.

일반적인 엔진 구성

엔진 내에서는 초기화기, 국제화 또는 기타 구성 옵션과 같은 기능을 사용하고 싶은 경우가 있을 수 있습니다. 좋은 소식은 이러한 기능이 완전히 가능하다는 것입니다. Rails 엔진은 Rails 애플리케이션과 매우 유사한 기능을 공유하기 때문입니다. 사실 Rails 애플리케이션의 기능은 엔진이 제공하는 기능의 상위 집합입니다!

초기화기(엔진이 로드되기 전네, 계속해서 번역하겠습니다.

초기화기(엔진이 로드되기 전에 실행되어야 하는 코드)를 사용하고 싶다면 config/initializers 폴더가 그 장소입니다. 이 디렉토리의 기능은 구성 가이드의 초기화기 섹션에 설명되어 있으며 애플리케이션의 config/initializers 디렉토리와 정확히 동일한 방식으로 작동합니다. 표준 초기화기를 사용하고 싶다면 동일한 방식이 적용됩니다.

로케일의 경우 config/locales 디렉토리에 로케일 파일을 배치하면 됩니다. 애플리케이션에서와 마찬가지로 작동합니다.

엔진 테스트하기

엔진이 생성되면 test/dummy 내에 더미 애플리케이션이 생성됩니다. 이 애플리케이션은 엔진을 테스트하기 위한 마운팅 지점으로 사용됩니다. 이 애플리케이션 내에서 컨트롤러, 모델 또는 뷰를 생성하여 엔진을 테스트할 수 있습니다.

test 디렉토리는 일반적인 Rails 테스트 환경처럼 취급되어야 하며, 단위, 기능 및 통합 테스트를 허용합니다.

기능 테스트

기능 테스트를 작성할 때 고려해야 할 사항은 테스트가 엔진 자체가 아닌 test/dummy 애플리케이션에서 실행된다는 것입니다. 이는 테스트 환경 설정 때문입니다. 엔진은 테스트의 주요 기능, 특히 컨트롤러를 테스트하기 위해 호스트 애플리케이션이 필요합니다. 이는 다음과 같은 일반적인 GET 요청을 컨트롤러의 기능 테스트에서 수행하면 제대로 작동하지 않을 수 있음을 의미합니다:

module Blorgh
  class FooControllerTest < ActionDispatch::IntegrationTest
    include Engine.routes.url_helpers

    def test_index
      get foos_url
      # ...
    end
  end
end

애플리케이션이 엔진의 라우팅을 명시적으로 알려주지 않는 한 이 요청이 제대로 작동하지 않습니다. 이를 위해 설정 코드에서 @routes 인스턴스 변수를 엔진의 경로 집합으로 설정해야 합니다:

module Blorgh
  class FooControllerTest < ActionDispatch::IntegrationTest
    include Engine.routes.url_helpers

    setup do
      @routes = Engine.routes
    end

    def test_index
      get foos_url
      # ...
    end
  end
end

이렇게 하면 애플리케이션에 여전히 GET 요청을 index 액션에 수행하지만 애플리케이션의 경로가 아닌 엔진의 경로를 사용하도록 지시합니다.

이렇게 하면 테스트에서 엔진의 URL 헬퍼가 예상대로 작동합니다.

엔진 기능 향상시키기

이 섹션에서는 메인 Rails 애플리케이션에서 엔진의 MVC 기능을 추가 및/또는 재정의하는 방법을 설명합니다.

모델과 컨트롤러 재정의하기

엔진의 모델과 컨트롤러는 부모 애플리케이션에 의해 재열림어 확장하거나 장식할 수 있습니다.

재정의는 app/overrides라는 전용 디렉토리에 구성될 수 있으며, 자동 로더에 의해 무시되고 to_prepare 콜백에서 사전 로드됩니다:

# config/application.rb
module MyApp
  class Application < Rails::Application
    # ...

    overrides = "#{Rails.root}/app/overrides"
    Rails.autoloaders.main.ignore(overrides)

    config.to_prepare do
      Dir.glob("#{overrides}/**/*_override.rb").sort.each do |override|
        load override
      end
    end
  end
end

class_eval을 사용하여 기존 클래스 재열기

예를 들어 엔진 모델을 재정의하려면

# Blorgh/app/models/blorgh/article.rb
module Blorgh
  class Article < ApplicationRecord
    # ...
  end
end

클래스를 재열기하는 파일을 만들면 됩니다:

# MyApp/app/overrides/models/blorgh/article_override.rb
Blorgh::Article.class_eval do
  # ...
end

클래스 또는 모듈 키워드를 사용하는 것이 매우 중요합니다. 그렇지 않으면 정의가 메모리에 이미 있기 때문에 잘못 정의될 수 있습니다. class_eval을 사용하면 클래스를 올바르게 재열 수 있습니다.

ActiveSupport::Concern을 사용하여 기존 클래스 재열기

Class#class_eval은 단순한 조정에 좋지만 더 복잡한 클래스 수정의 경우 ActiveSupport::Concern을 사용하는 것을 고려해 볼 수 있습니다. ActiveSupport::Concern은 런타임에 상호 종속적인 모듈 및 클래스의 로드 순서를 관리하여 코드를 크게 모듈화할 수 있습니다.

Article#time_since_created 추가Article#summary 재정의:

# MyApp/app/models/blorgh/article.rb

class Blorgh::Article < ApplicationRecord
  include Blorgh::Concerns::Models::Article

  def time_since_created
    Time.current - created_at
  end

  def summary
    "#{title} - #{truncate(text)}"
  end
end
# Blorgh/app/models/blorgh/article.rb
module Blorgh
  class Article < ApplicationRecord
    include Blorgh::Concerns::Models::Article
  end
end
# Blorgh/lib/concerns/models/article.rb

module Blorgh::Concerns::Models::Article
  extend ActiveSupport::Concern

  # `included do` 블록은 모듈이 포함된 컨텍스트(즉, Blorgh::Article)에서 평가되도록 합니다.
  # 모듈 자체가 아닙니다.
  included do
    attr_accessor :author_name
    belongs_to :author, class_name: "User"

    before_validation :set_author

    private
      def set_author
        self.author = User.find_or_create_by(name: author_name)
      end
  end

  def summary
    "#{title}"
  end

  module ClassMethods
    def some_class_method
      'some class method string'
    end
  end
end

자동 로드 및 엔진

자동 로드 및 상수 재로드에 대한 자세한 내용은 자동 로드 및 상수 재로드 가이드를 확인하세요.

뷰 재정의하기

Rails가 렌더링할 뷰를 찾을 때 먼저 애플리케이션의 app/views 디렉토리를 찾습니다. 여기에서 찾을 수 없는 경우 이 디렉토리를 가진 모든 엔진을 확인합니다.

Blorgh::ArticlesController의 index 액션에 대한 뷰를 렌더링하라고 요청하면 먼저 애플리케이션의 app/views/blorgh/articles/index.html.erb를 찾습니다. 찾을 수 없는 경우 엔진 내부를 확인합니다.

단순히 app/views/blorgh/articles/index.html.erb에 새 파일을 만들어 이 뷰를 재정의할 수 있습니다. 그런 다음 이 뷰가 일반적으로 출력하는 내용을 완전히 변경할 수 있습니다.

이를 시도해 보려면 app/views/blorgh/articles/index.html.erb에 새 파일을 만들고 다음 내용을 넣으세요:

<h1>Articles</h1>
<%= link_to "New Article", new_article_path %>
<% @articles.each do |article| %>
  <h2><%= article.title %></h2>
  <small>By <%= article.author %></small>
  <%= simple_format(article.text) %>
  <hr>
<% end %>

라우팅

엔진 내의 라우팅은 기본적으로 애플리케이션과 격리됩니다. 이는 Engine 클래스 내의 isolate_namespace 호출 때문입니다. 이는 애플리케이션과 엔진이 동일한 이름의 라우팅을 가질 수 있지만 충돌하지 않도록 하는 것을 의미합니다.

엔진 내의 라우팅은 Engine 클래스 내의 config/routes.rb에 그려집니다. 다음과 같이 말이죠:

Blorgh::Engine.routes.draw do
  resources :articles
end

이와 같이 격리된 라우팅을 사용하면 엔진의 라우팅 프록시 메서드를 사용하여 애플리케이션 내에서 엔진 영역에 링크해야 합니다. 일반적인 라우팅 메서드 articles_path를 사용하면 애플리케이션의 articles_path로 이동할 수 있습니다.

예를 들어 다음 예제에서는 템플릿이 애플리케이션에서 렌더링되면 애플리케이션의 articles_path로 이동하고, 엔진에서 렌더링되면 엔진의 articles_path 라우팅 헬퍼 메서드로 이동합니다:

<%= link_to "Blog articles", articles_path %>

엔진의 articles_path 라우팅 헬퍼 메서드를 항상 사용하려면 엔진과 동일한 이름의 라우팅 프록시 메서드를 호출해야 합니다.

<%= link_to "Blog articles", blorgh.articles_path %>

애플리케이션 내에서 엔진을 참조하려면 main_app 헬퍼를 사용하면 됩니다:

<%= link_to "Home", main_app.root_path %>

엔진 내에서 이를 사용하면 항상 애플리케이션의 루트로 이동합니다. main_app “라우팅 프록시” 메서드 호출을 생략하면 엔진의 루트 또는 애플리케이션의 루트로 이동할 수 있습니다.

엔진에서 렌더링된 템플릿이 애플리케이션의 라우팅 헬퍼 메서드를 사용하려고 하면 정의되지 않은 메서드 호출이 발생할 수 있습니다. 이러한 문제가 발생하면 엔진 내에서 main_app 접두사 없이 애플리케이션의 라우팅 메서드를 호출하려고 하지 않는지 확인하세요.

자산

엔진 내의 자산은 전체 애플리케이션과 동일한 방식으로 작동합니다. Rails::Engine에서 상속되기 때문에 애플리케이션은 엔진의 app/assetslib/assets 디렉토리에서 자산을 찾습니다.

엔진의 다른 모든 구성 요소와 마찬가지로 자산도 네임스페이스화해야 합니다. 즉, style.css라는 자산이 있는 경우 app/assets/stylesheets/[engine name]/style.css에 배치해야 하며, app/assets/stylesheets/style.css에 배치하면 안 됩니다. 자산이 네임스페이스화되지 않으면 호스트 애플리케이션에 동일한 이름의 자산이 있을 수 있으며, 이 경우 애플리케이션의 자산이 우선하고 엔진의 자산은 무시됩니다.

app/assets/stylesheets/blorgh/style.css에 자산이 있다고 가정해 보겠습니다. 이 자산을 애플리케이션 내에 포함하려면 stylesheet_link_tag를 사용하고 엔진 네, 계속해서 번역하겠습니다.

app/assets/stylesheets/blorgh/style.css에 자산이 있다고 가정해 보겠습니다. 이 자산을 애플리케이션 내에 포함하려면 stylesheet_link_tag를 사용하고 엔진 내부의 자산인 것처럼 참조하면 됩니다:

<%= stylesheet_link_tag "blorgh/style.css" %>

Asset Pipeline의 require 문을 사용하여 다른 자산에 대한 종속성을 지정할 수도 있습니다:

/*
 *= require blorgh/style
 */

정보. Sass나 CoffeeScript와 같은 언어를 사용하려면 엔진의 .gemspec에 관련 라이브러리를 추가해야 합니다.

별도의 자산 및 사전 컴파일

엔진의 자산이 호스트 애플리케이션에 필요하지 않은 경우도 있습니다. 예를 들어 엔진에 대한 관리 기능을 만들었다고 가정해 보겠습니다. 이 경우 호스트 애플리케이션에서 admin.css 또는 admin.js를 포함할 필요가 없습니다. 오직 gem의 관리 레이아웃만 이러한 자산을 필요로 합니다. 호스트 앱에 "blorgh/admin.css"를 포함시키는 것은 적절하지 않습니다. 이러한 상황에서는 이러한 자산을 명시적으로 사전 컴파일 대상으로 정의해야 합니다. 이렇게 하면 bin/rails assets:precompile이 실행될 때 엔진 자산이 포함됩니다.

engine.rb에서 사전 컴파일 대상 자산을 정의할 수 있습니다:

initializer "blorgh.assets.precompile" do |app|
  app.config.assets.precompile += %w( admin.js admin.css )
end

자세한 내용은 자산 파이프라인 가이드를 참조하세요.

기타 Gem 종속성

엔진 내의 gem 종속성은 엔진의 루트 디렉토리에 있는 .gemspec 파일에 지정해야 합니다. 그 이유는 엔진이 gem으로 설치될 수 있기 때문입니다. 종속성을 Gemfile 내에 지정하면 일반적인 gem install 중에는 인식되지 않아 엔진이 제대로 작동하지 않을 수 있습니다.

엔진과 함께 설치되어야 하는 종속성을 지정하려면 엔진의 .gemspec 파일 내 Gem::Specification 블록에 지정하면 됩니다:

s.add_dependency "moo"

애플리케이션의 개발 종속성으로만 설치되어야 하는 종속성을 지정하려면 다음과 같이 하면 됩니다:

s.add_development_dependency "moo"

bundle install을 실행하면 두 종류의 종속성 모두 설치됩니다. 엔진의 개발 및 테스트에 사용되는 개발 종속성만 설치됩니다.

엔진이 요구될 때 즉시 종속성을 요구하려면 엔진 초기화 전에 이를 요구해야 합니다. 예를 들어:

require "other_engine/engine"
require "yet_another_engine/engine"

module MyEngine
  class Engine < ::Rails::Engine
  end
end