Home > Articles

Creating a Component-Based Application with Rails

This chapter excerpt tells the story of creating a full Rails application within a component. From the first steps to migrations and dependency management, it covers the common pitfalls of the unavoidable aspects of component-based Rails.

Save 35% off the list price* of the related book or multi-format eBook (EPUB + MOBI + PDF) with discount code ARTICLE.
* See informit.com/terms

This chapter is from the book

Photo: mattiaath/123RF

In preparation for creating your first CBRA app, you should ensure that your system is up to date with regard to Ruby and Rails. I suggest using the latest published versions of both Ruby and the Rails gems. The way I have my system set up, using the Ruby Version Manager (RVM) (http://rvm.io/), is something like the following:

Install rvm, bundler, and rails. Execute anywhere

$ rvm get stable
$ rvm install 2.4.2
$ gem install bundler -v '1.15.4'
$ gem install rails -v '5.1.4'

2.1 The Entire App Inside a Component

In this section, we will be creating a Rails application that contains no handwritten code directly in the app folder and instead has all code inside an engine mounted into the application.

The first step in creating a CBRA app is the same as creating any new Rails app: rails new!

Generate Sportsball app. Execute where you like to store your Rails projects

$ rails new sportsball
$ cd sportsball

I often refer to this Rails app as the main app or container app. However, we are not going to bother writing any code of our application into the newly created folder structure. Instead, we are going to write all of it inside a component. That component will be implemented through a Rails engine. In fact, let us force ourselves to stick to this and delete the app folder.

Delete the app folder. Execute in ./

$ rm -rf app

There is no obvious candidate as to where the components of our application should be added in the created folder structure. All folders have their specific purpose and our components don’t really fit in any of them. Consequently, I believe components should not go into the created folder structure and instead should find their place in a new directory under the root. I like to use components as the folder name.

Create the components folder. Execute in ./

$ mkdir components

To create our first component, we will use the rails plugin new command to create a Rails engine. For lack of a better name, we will call this first component app_component.

Initially, I will use app_component as a component name. This is despite what I said before about the naming of components. Read the following for a defense. But first, we generate this component using the following command:

Generate the app_component gem. Execute in ./

$ rails plugin new components/app_component --full --mountable

The command line parameters --full and --mountable make the plugin generator create a gem that loads a Rails::Engine that isolates itself from the Rails application. It comes with a test harness application and blueprints for tests based on Test::Unit. See Appendix A for a full explanation of these creation parameters and to learn how to switch the tests to RSpec.

We can now cd into the component folder in ./components/app_component and execute bundle. Depending on our version of bundler, there will be a warning (in older versions) or error about our gemspec not being valid:

app_component gem error during bundle. Execute in ./components/app_component

$ bundle
The latest bundler is 1.16.0.pre.3, but you are currently running
    1.15.4.
To update, run `gem install bundler --pre`
You have one or more invalid gemspecs that need to be fixed.
The gemspec at ./components/app_component/app_component.gemspec is
    not valid.
Please fix this gemspec.
The validation error was '"FIXME" or "TODO" is not a description'

This warning is because there are a bunch of “TODO” entries in the gemspec that are picked up on by bundler and that we need to remove. If you fill out all the fields with “TODO” in the Gem::Specification block of the gemspec, this warning/error will go away. However, email, homepage, description, and license are not required, and if you delete those you only need to fill in authors and summary to get rid of the warning.

Removing all TODOs from the generated gemspec leads to the following file, which will not throw an error:

./components/app_component/app_component.gemspec

 1 $:.push File.expand_path("../lib",    ____FILE____   )
 2 
 3 # Maintain your gems version:
 4 require "app_component/version"
 5
 6 # Describe your gem and declare its dependencies:
 7 Gem::Specification.new do |s|
 8   s.name        = "app_component"
 9   s.version     = AppComponent::VERSION
10   s.authors     = ["Stephan Hagemann"]
11   s.summary     = "Summary of AppComponent."
12   s.license     = "MIT"
13
14   s.files = Dir["{app,config,db,lib}/**/*",
                   "MIT-LICENSE", "Rakefile", "README.md"]
15
16   s.add_dependency "rails", "~> 5.1.0"
17
18   s.add_development_dependency "sqlite3"
19 end

If we now go back up into the root folder of Sportsball and call bundle there, we notice that among the many gems that are being used, we also see our new component app_component.

Seeing AppComponent being used in the app (some results omitted). Execute in ./

$ bundle
The latest bundler is 1.16.0.pre.3, but you are currently running
    1.15.4.
To update, run `gem install bundler --pre`
Resolving dependencies...
Using rake 12.2.1
 
 . . .
 
Using rails 5.1.4
Using sass-rails 5.0.6
Using app_component 0.1.0 from source at `components/app_component`
Bundle complete! 17 Gemfile dependencies, 73 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

This is because rails plugin new not only creates a new gem, it also automatically adds a reference to this gem into the Gemfile of an app in the context of which it was created. That is, because we executed rails plugin new from the root of the Sportsball app, we got also got a new entry in our Gemfile.

./Gemfile showing reference to AppComponent gem (some lines omitted)

1 source 'https://rubygems.org'
2 
3  . . .
4 
5 gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
6 gem 'app_component', path: 'components/app_component'

In earlier versions of Rails, this does not happen automatically. If you are in this situation, add the last line from the previous snippet to your Gemfile to get the same result when bundling the app. Notice that the gem reference uses the path option to specify where this gem can be found (namely, our local filesystem). Commonly, path is used only for gems under development, but as we will see, it works just fine for use in CBRA applications.

Back to AppComponent. While it is now hooked up within the Sportsball application, it does not actually do anything yet. Let us fix that next. We will create a landing page and route the root of the engine to it.

Generate a controller for the component. Execute in ./

$ cd components/app_component
$ rails g controller welcome index

By moving into the folder of the gem, we are using the engine’s Rails setup. Because of that and because we made this a mountable engine, our welcome controller is created inside the AppComponent namespace. See Appendix B for an in-depth discussion of the folder structure and the namespace created by the engine.

We change the component’s routes as follows to hook the new controller up to the root of the engine’s routes:

./components/app_component/config/routes.rb

1 AppComponent::Engine.routes.draw do
2   root to: "welcome#index"
3 end

Last, we make the main app aware of the routes of the engine by mounting them into the routes of the application. Here, we are mounting the engine to the root of the app as there are no other engines and the main app will never have any routes of its own. See Appendix B for a discussion of how routing works and what options you have.

./config/routes.rb

1 Rails.application.routes.draw do
2   mount AppComponent::Engine, at: "/"
3 end

That’s all. Let’s start up our server!

Start up the Rails server. Execute in ./

$ rails s
=> Booting Puma
=> Rails 5.1.4 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.10.0 (ruby 2.4.2-p198), codename: Russell's Teapot
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop

Now, when you open http://localhost:3000 with a browser, you should see (as in Figure 2.1) your new welcome controller’s index page. That wasn’t too bad, was it?

Figure 2.1

Figure 2.1. Your first CBRA-run web page

Having the component separated from the container application also allows us to draw a component diagram (see Figure 2.2). This diagram shows our component in the middle using its gem name. The surrounding box with the application name indicates the Rails application of which our code is a part. The arrow indicates that the container app is dependent directly on app_component (as we just saw, AppComponent was added directly to the Gemfile of Sportsball). In subsequent sections of the book we will see how we create a web of components with dependencies among them.

Figure 2.2

Figure 2.2. Our first component diagram

Generating this graph yourself at this stage of the app is a bit tricky. It is the way we are referencing the component in Gemfile currently. If you still want to do it, there are a couple of steps involved.

First, you will need to install the cobradeps gem (https://github.com/shageman/cobradeps), a gem I wrote to allow for the generation of Rails component diagrams. This gem depends on graphviz (http://www.graphviz.org/), an open-source graph visualization software. You install these two applications as follows (assuming that you are on OSX and are homebrew, which I recommend you do: https://brew.sh/).

Install graphviz and cobradeps. Execute anywhere

$ brew install graphviz
$ gem install cobradeps

To alleviate the gem reference problem we mentioned, change the AppComponent line in your Gemfile to this:

Reference to app_component in ./Gemfile allowing for graph generation

1 gem 'app_component',
2     path: 'components/app_component',
3     group: [:default, :direct]

The group: [:default, :direct] will behave normally with bundler and is used by cobradeps to determine that the gem is indeed a direct dependency (we will see in Section 2.3 why this is necessary). Now you can generate the component graph by executing the following statement. The result will be output into ./component_diagram.png.

Generate a component graph for Sportsball. Execute in ./

$ cobradeps -g component_diagram .

That’s it! Your first CBRA app is ready to get serious. You can now continue all feature development inside of components/app_component.

Some aspects of what we glossed over in this section are covered in more depth in the Appendixes. Refer to Appendix A for an in-depth look at the various kinds of engines that Rails features, and Appendix B for an introduction to engine routing and mounting.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020