Learning Angular-Rails

Getting Started with Your First Angular Rails Application

Angular Rails tutorial | first application | setup | components | data binding

Angular Rails is a powerful and versatile web development framework that combines the strengths of Angular, a popular front-end framework, and Ruby on Rails, a robust and mature back-end framework. This combination allows developers to build modern, responsive, and scalable web applications with ease. In this comprehensive guide, we'll walk you through the process of setting up your first Angular Rails application, covering everything from installation to deployment.

Prerequisites

Before we dive into the nitty-gritty of building an Angular Rails application, let's ensure you have the necessary prerequisites installed on your machine:

Setting Up the Project

With the prerequisites out of the way, let's start setting up our Angular Rails project:

1. Create a New Rails Application

Open your terminal and navigate to the directory where you want to create your project. Then, run the following command to create a new Rails application:

rails new my-angular-rails-app

This command will generate a new Rails application with the name "my-angular-rails-app" and set up the necessary directory structure and files.

2. Install Angular

Next, we need to install Angular within our Rails application. Navigate into the project directory and run the following command:

rails webpacker:install:angular

This command will install Angular and its dependencies, as well as configure Webpacker (the asset pipeline tool used by Rails) to work with Angular.

3. Generate the Angular App

With Angular installed, we can now generate the initial Angular application structure. Run the following command:

ng new client --routing --style=scss

This command will create a new Angular application called "client" inside the Rails app directory. The --routing flag enables routing in the Angular app, and --style=scss sets up SCSS as the default style format.

Integrating Angular and Rails

Now that we have both Angular and Rails set up, it's time to integrate them together:

1. Update the Rails Layout

Open the app/views/layouts/application.html.erb file and replace its contents with the following code:

<!DOCTYPE html>
<html>
  <head>
    <title>My Angular Rails App</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all' %>
    <%= javascript_pack_tag 'application' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

This code sets up the basic HTML structure for our application and includes the necessary Rails tags for rendering assets and handling CSRF protection.

2. Update the Rails Root Route

Open the config/routes.rb file and replace its contents with the following code:

Rails.application.routes.draw do
  root 'application#angular_app'
end

This code sets the root route of our Rails application to point to the angular_app action in the ApplicationController.

3. Create the Angular App Controller Action

Open the app/controllers/application_controller.rb file and add the following action:

def angular_app
  render 'layouts/application'
end

This action simply renders the application layout, which will serve as the entry point for our Angular application.

Building the Angular App

With the integration between Angular and Rails complete, we can now focus on building our Angular application:

1. Generate Components

Angular applications are built using components, which are reusable pieces of UI logic and presentation. Let's generate a new component called "home" by running the following command:

ng generate component home

This command will create a new directory called home inside the client/src/app directory, containing the component's TypeScript file, HTML template, CSS stylesheet, and test file.

2. Set Up Routing

Since we enabled routing when generating the Angular app, we can now set up our routes. Open the client/src/app/app-routing.module.ts file and update its contents with the following code:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';

const routes: Routes = [
  { path: '', component: HomeComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

This code defines a single route that maps the root path (/) to the HomeComponent we generated earlier.

3. Update the Root Component

Open the client/src/app/app.component.html file and replace its contents with the following code:

<router-outlet></router-outlet>

This code tells Angular to render the component associated with the current route inside the <router-outlet> element.

4. Build and Run the Application

With our Angular app set up, we can now build and run it. First, we need to build the Angular app by running the following command:

ng build --watch

This command will build the Angular app and watch for any changes, automatically rebuilding the app when changes are detected.

Next, open a new terminal window and navigate to the root directory of your Rails application. Start the Rails server by running the following command:

rails server

This command will start the Rails server, which will serve our Angular app.

Finally, open your web browser and navigate to http://localhost:3000. You should see the "Home" component rendered on the page.

Adding Functionality

Now that we have a basic Angular Rails application up and running, let's add some functionality to it. We'll create a simple blog application with the ability to create, read, update, and delete blog posts.

1. Generate the Post Model and Controller

First, we need to generate the Post model and controller in Rails. Run the following command:

rails generate scaffold Post title:string content:text

This command will generate the Post model, controller, views, and routes for creating, reading, updating, and deleting blog posts.

2. Set Up the Rails API

Since we're building a single-page application with Angular, we'll use Rails as an API backend. Open the config/routes.rb file and update it with the following code:

Rails.application.routes.draw do
  root 'application#angular_app'
  scope '/api' do
    resources :posts
  end
end

This code sets up a scope for the API routes, prefixing them with /api. We'll use these routes to interact with the Post model from our Angular app.

3. Generate Angular Services and Components

In Angular, we'll use services to interact with the Rails API and components to display and manage blog posts. Let's generate a new service and component by running the following commands:

ng generate service post ng generate component post-list ng generate component post-detail ng generate component post-form

These commands will generate a PostService and three components: PostListComponent, PostDetailComponent, and PostFormComponent.

4. Update the Angular Services and Components

Open the client/src/app/post.service.ts file and update it with the following code:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Post } from './post';

@Injectable({
  providedIn: 'root'
})
export class PostService {
  private apiUrl = '/api/posts';

  constructor(private http: HttpClient) { }

  getPosts(): Observable<Post[]> {
    return this.http.get<Post[]>(this.apiUrl);
  }

  getPost(id: number): Observable<Post> {
    const url = `${this.apiUrl}/${id}`;
    return this.http.get<Post>(url);
  }

  createPost(post: Post): Observable<Post> {
    return this.http.post<Post>(this.apiUrl, post);
  }

  updatePost(post: Post): Observable<Post> {
    const url = `${this.apiUrl}/${post.id}`;
    return this.http.put<Post>(url, post);
  }

  deletePost(id: number): Observable<void> {
    const url = `${this.apiUrl}/${id}`;
    return this.http.delete<void>(url);
  }
}

This code defines a service that interacts with the Rails API for creating, reading, updating, and deleting blog posts. It uses the Angular HttpClient module to make HTTP requests to the API endpoints.

Next, open the client/src/app/post-list/post-list.component.ts file and update it with the following code:

import { Component, OnInit } from '@angular/core';
import { Post } from '../post';
import { PostService } from '../post.service';

@Component({
  selector: 'app-post-list',
  templateUrl: './post-list.component.html',
  styleUrls: ['./post-list.component.scss']
})
export class PostListComponent implements OnInit {
  posts: Post[] = [];

  constructor(private postService: PostService) { }

  ngOnInit(): void {
    this.getPosts();
  }

  getPosts(): void {
    this.postService.getPosts()
      .subscribe(posts => this.posts = posts);
  }
}

This code defines the PostListComponent, which retrieves a list of blog posts from the PostService and stores them in the posts array.

Open the client/src/app/post-list/post-list.component.html file and add the following code:

<h2>Blog Posts</h2>
<ul>
  <li *ngFor="let post of posts">
    <a routerLink="/posts/{{ post.id }}">{{ post.title }}</a>
  </li>
</ul>

This code displays a list of blog post titles, with each title linking to the post detail page.

Next, open the client/src/app/post-detail/post-detail.component.ts file and update it with the following code:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Post } from '../post';
import { PostService } from '../post.service';

@Component({
  selector: 'app-post-detail',
  templateUrl: './post-detail.component.html',
  styleUrls: ['./post-detail.component.scss']
})
export class PostDetailComponent implements OnInit {
  post: Post | undefined;

  constructor(
    private route: ActivatedRoute,
    private postService: PostService
  ) { }

  ngOnInit(): void {
    this.getPost();
  }

  getPost(): void {
    const id = Number(this.route.snapshot.paramMap.get('id'));
    this.postService.getPost(id)
      .subscribe(post => this.post = post);
  }
}

This code defines the PostDetailComponent, which retrieves a single blog post from the PostService based on the post ID in the URL.

Open the client/src/app/post-detail/post-detail.component.html file and add the following code:

<div *ngIf="post">
  <h2>{{ post.title }}</h2>
  <p>{{ post.content }}</p>
</div>

This code displays the title and content of the blog post.

Finally, open the client/src/app/post-form/post-form.component.ts file and update it with the following code:

import { Component, OnInit } from '@angular/core';
import { Post } from '../post';
import { PostService } from '../post.service';

@Component({
  selector: 'app-post-form',
  templateUrl: './post-form.component.html',
  styleUrls: ['./post-form.component.scss']
})
export class PostFormComponent implements OnInit {
  post: Post = {
    id: 0,
    title: '',
    content: ''
  };

  constructor(private postService: PostService) { }

  ngOnInit(): void {
  }

  createPost(): void {
    this.postService.createPost(this.post)
      .subscribe(post => {
        // Handle successful post creation
        console.log('Post created:', post);
      });
  }
}

This code defines the PostFormComponent, which allows users to create a new blog post by submitting a form.

Open the client/src/app/post-form/post-form.component.html file and add the following code:

<h2>Create Post</h2>
<form (ngSubmit)="createPost()">
  <div>
    <label for="title">Title</label>
    <input type="text" id="title" [(ngModel)]="post.title" name="title">
  </div>
  <div>
    <label for="content">Content</label>
    <textarea id="content" [(ngModel)]="post.content" name="content"></textarea>
  </div>
  <button type="submit">Create Post</button>
</form>

This code displays a form with input fields for the post title and content, and a submit button to create the new post.

5. Update the Angular Routing

With our components and services in place, we need to update the Angular routing to include routes for the post list, detail, and form components. Open the client/src/app/app-routing.module.ts file and update it with the following code:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { PostListComponent } from './post-list/post-list.component';
import { PostDetailComponent } from './post-detail/post-detail.component';
import { PostFormComponent } from './post-form/post-form.component';

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'posts', component: PostListComponent },
  { path: 'posts/:id', component: PostDetailComponent },
  { path: 'new-post', component: PostFormComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

This code defines routes for the home page (/), post list (/posts), post detail (/posts/:id), and post form (/new-post).

6. Update the Angular Root Component

Finally, we need to update the Angular root component to include navigation links and the <router-outlet> for rendering the components based on the current route. Open the client/src/app/app.component.html file and update it with the following code:

<nav>
  <ul>
    <li><a routerLink="/">Home</a></li>
    <li><a routerLink="/posts">Posts</a></li>
    <li><a routerLink="/new-post">Create Post</a></li>
  </ul>
</nav>
<router-outlet></router-outlet>

This code adds a navigation menu with links to the home page, post list, and post form. The <router-outlet> element is where the components associated with the current route will be rendered.

Testing and Deployment

With our Angular Rails application fully functional, it's time to test it and prepare for deployment.

1. Testing

Angular provides built-in testing utilities that make it easy to write and run tests for your application. You can generate test files for your components and services using the Angular CLI.

For example, to generate a test file for the PostService, run the following command:

ng generate service post --skip-tests=false

This command will generate a test file called post.service.spec.ts in the same directory as the service file.

You can then write tests for your service methods and run them using the Angular CLI test runner:

ng test

This command will execute all the tests in your Angular application and provide a report in the terminal.

2. Deployment

To deploy your Angular Rails application, you'll need to build the Angular app for production and configure your Rails app to serve the built assets.

First, build the Angular app for production by running the following command:

ng build --prod

This command will create a production-ready build of your Angular app in the client/dist directory.

Next, configure your Rails app to serve the built Angular assets. Open the config/environments/production.rb file and add the following lines at the end:

config.public_file_server.enabled = true
config.public_file_server.headers = {
  'Cache-Control' => 'public, max-age=31536000'
}

These lines enable the Rails public file server and set the appropriate cache headers for serving static assets.

Finally, update the config/initializers/assets.rb file to include the Angular assets in the Rails asset pipeline:

Rails.application.config.assets.precompile += %w( client/dist/*.{js,css} )

This line tells Rails to precompile the JavaScript and CSS files in the client/dist directory, which is where the built Angular app is located.

With these configurations in place, you can deploy your Angular Rails application to a hosting platform like Heroku or DigitalOcean.

Conclusion

In this comprehensive guide, we've covered the entire process of setting up and building your first Angular Rails application. We started by installing the necessary prerequisites and setting up the project. Then, we integrated Angular and Rails, built the Angular app with components and services, added functionality for creating, reading, updating, and deleting blog posts, and finally, tested and prepared the application for deployment.

Angular Rails is a powerful combination that allows you to leverage the strengths of both Angular and Ruby on Rails to build modern, responsive, and scalable web applications. With the knowledge gained from this guide, you're now equipped to embark on your own Angular Rails development journey and create amazing web applications.

Remember, this guide is just the beginning. There's always more to learn and explore in the world of web development. Keep practicing, experimenting, and staying up-to-date with the latest technologies and best practices. Happy coding!