
Introdução 🙂
Os Apps profissionais seguem há algum tempo na direção de ter uma divisão entre o backend (API) e o front end (Cliente Web), recentemente foi lançado a versão 2 do Angular (que tem pouco a ver com a versão 1) e também a versão 5 do Rails (que tem muito a ver com a versão 4 🙂 ), nesse tutorial eu vou demonstrar como conectar essas duas tecnologias para criar um App incrível \o/.
Nós vamos criar um CRUD de uma pequena aplicação de FAQ, e para fazer isso mais rapidamente nós vamos usar uma ferramenta bem legal que chama Angular-CLI (command line interface), que vai nos permitir gerar o projeto Angular 2, os components e os services facilmente (similar aos generates do Rails).
O que vamos aprender?
- Como criar um CRUD em uma aplicação Rails 5
- Como criar um CRUD em uma aplicação Angular 2
- Como conectar o Rails 5 com o Angular 2
INGREDIENTES
- Ruby 2.3.1
- Rails 5
- Sqlite3
- Angular 2
- Angular-CLI
Objetivos
Criar um Pequeno App que nos permita criar questões para um FAQ, com o front end em Angular 2 e o Backend no Rails 5.
Passo a Passo
- Rails 5
- Criar o Projeto Rails Api
- Gerar o CRUD
- Incluir o CORS
- Angular 2
- Criar o Projeto Angular usando o Angular-CLI
- Configurar nosso projeto
- Criar nossos components
- Criar nosso service
- Editar nossas views
- Conectar tudo isso 🙂
Mãos à Obra \o/
Parte 1 – Criando o projeto Rails 5
Primeiro vamos gerar o nosso projeto Rails 5 API que vai ser consumido via JSON pelo projeto Angular 2.
- Para começar, rode no seu console o comando para gerar o projeto:
1rails new noticias --api
*a flag –api significa que o rails vai configurar o projeto como uma API pra gente - Agora vamos gerar nosso scaffold, rode:
1rails g scaffold questions title:string text:text - Rode as migrations:
1rake db:migrate - Agora vamos configurar o CORS para que nosso APP possa receber chamada de outros domínios, primeiro no seu Gemfile adicione:
1gem 'rack-cors'
*O que é CORS - Rode o bundle, para instalar a Gem:
1bundle - Agora no arquivo config/application.rb, substitua o conteúdo por:
123456789101112131415161718192021222324252627282930313233343536require_relative 'boot'require "rails"# Pick the frameworks you want:require "active_model/railtie"require "active_job/railtie"require "active_record/railtie"require "action_controller/railtie"require "action_mailer/railtie"require "action_view/railtie"require "action_cable/engine"# require "sprockets/railtie"require "rails/test_unit/railtie"# Require the gems listed in Gemfile, including any gems# you've limited to :test, :development, or :production.Bundler.require(*Rails.groups)module Newsclass Application < Rails::Applicationconfig.middleware.insert_before 0, "Rack::Cors" doallow doorigins '*'resource '*', :headers => :any, :methods => [:get, :post, :options, :delete, :put]endend# Settings in config/environments/* take precedence over those specified here.# Application configuration should go into files in config/initializers# -- all .rb files in that directory are automatically loaded.# Only loads a smaller set of middleware suitable for API only apps.# Middleware like session, flash, cookies can be added back manually.# Skip views, helpers and assets when generating a new resource.config.api_only = trueendend - Para testar, rode o servidor e visite http://localhost:3000/questions
- Pronto \o/, nossa aplicação Rails já está pronta. Agora vamos para o Angular 2 🙂
Pausa para o Merchan do BEM! 🙂
BOOTCAMP ONE BIT CODE – SUBA DE LEVEL NO MUNDO DO RUBY ON RAILS
Este é o último final de semana para se inscrever no primeiro Bootcamp online do OneBitCode!
Neste curso, nós vamos criar do zero um site similar ao Airbnb usando Rails 5 como Api e Angular 2 como cliente Web.
O curso vai ter vídeo aulas semanais, live de 2 horas por semana, suporte total às dúvidas e um Slack exclusivo para os alunos desenvolverem network.
O curso vai ser ÉPICO, então confere a Landing Page dele e faça parte do grupo de alunos One Bit Code! \o/
Conheça o Bootcamp!
Parte 2 – Criando o App Angular 2
Agora sim começa a parte mais emocionante complicada, vamos criar nosso APP Angular 2 e para fazer isso vamos usar o Angular-CLI.
Dependências
Primeiro, vamos começar com as dependências.
- Você vai precisar ter o NPM instalado na sua máquina. Para instalar no Ubuntu:
1sudo apt-get install npm
Para instalar no Mac:
1brew install node - Agora você precisa instalar o Angular-CLI:
1sudo npm install -g @angular/cli --allow-root
Criação do App
Finalmente, vamos a criação do App.
- Para gerar o projeto, rode na pasta desejada (fora do projeto Rails) no console:
1ng new questions - Agora vamos ver se tudo funcionou corretamente, dentro do projeto, rode no console:
1ng serve --port 9000 - Acesse no seu browser, http://localhost:9000, deve aparecer uma mensagem dizendo que funcionou 🙂
- Agora vamos gerar nossos components, rode:
1ng generate component questions
*Os components são o coração do Angular 2, eles são a principal maneira que nós criamos elementos, definimos as views e a lógica - Depois rode:
1ng generate component questions/question-form - Agora vamos gerar nosso Modelo de dados, crie uma pasta no caminho “/src/app/questions/” com o nome shared (“/src/app/questions/shared”).
- Depois crie um arquivo dentro dessa pasta chamado “question.ts” e coloque o seguinte conteúdo:
12345export class Question {id: number;title: string;text: string;} - Vamos criar nosso Service (ele serve para o Angular 2 conversar com a API), no console rode o comando:
1ng generate service questions/shared/question - Agora vamos adicionar o router outlet para fazer nossas rotas funcionarem, no nosso arquivo ‘src/app/app.componet.html’ substitua o conteúdo por:
12345<h1>Simple Faq creator</h1><hr /><router-outlet></router-outlet> - Agora nós vamos criar o nosso arquivo de rotas (que vai gerenciar nossas URLs), no caminho “src/app/” crie o arquivo “app.routing.ts” e preencha ele com o seguinte conteúdo:
*Note os comentários no código
12345678910111213141516171819import { ModuleWithProviders } from '@angular/core';// Importa o modulo de rotas do Angular 2import { Routes, RouterModule } from '@angular/router';// Importa seus componentes criadosimport { QuestionsComponent } from './questions/questions.component';import { QuestionFormComponent } from './questions/question-form/question-form.component';// Cria nossas Rotasconst appRoutes: Routes = [{ path: '', pathMatch: 'full', component: QuestionsComponent },{ path: 'questions/new', component: QuestionFormComponent},{ path: 'questions/:id', component: QuestionFormComponent},{ path: 'questions/:id/edit', component: QuestionFormComponent}];// Exporta a constante routing para importarmos ela no arquivo app.module.tsexport const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes); - Agora nós precisamos alterar nosso arquivo ‘src/app/app.module.ts’ para incluir nosso arquivo de rotas e algumas dependências do projeto, seu arquivo deve ficar assim:
*Note os comentários no código
1234567891011121314151617181920212223242526272829303132// Dependências do Angular 2import { BrowserModule } from '@angular/platform-browser';import { NgModule } from '@angular/core';import { FormsModule } from '@angular/forms';import { HttpModule } from '@angular/http';import { AppComponent } from './app.component';import { QuestionsComponent } from './questions/questions.component';// Adicionamos o arquivo routingimport { routing } from './app.routing';// Inclui nossos componentsimport { QuestionFormComponent } from './questions/question-form/question-form.component';import { QuestionService } from './questions/shared/question.service';// Adicionamos em imports a contant routing e também nosso service em Providers@NgModule({declarations: [AppComponent,QuestionsComponent,QuestionFormComponent],imports: [BrowserModule,FormsModule,HttpModule,routing],providers: [QuestionService],bootstrap: [AppComponent]})export class AppModule { } - Agora nós vamos editar nossos components, para começar vamos editar nosso componente de listagem, no arquivo ‘/src/app/questions/questions.component.ts’ substitua o conteúdo por:
*Note os comentários no código
1234567891011121314151617181920212223242526272829303132333435import { Component, OnInit } from '@angular/core';// Importa nosso Serviceimport { QuestionService } from './shared/question.service';// Importa nosso modelimport {Question} from "./shared/question";@Component({selector: 'app-questions',templateUrl: './questions.component.html',styleUrls: ['./questions.component.css']})export class QuestionsComponent implements OnInit {private questions: Question[] = [];constructor(private questionService: QuestionService) { }// Pega a listagem de Questions ao iniciarngOnInit() {this.questionService.getQuestions().subscribe(data => this.questions = data);}// Apaga a questãodeleteQuestion(questions) {if (confirm("Você tem certeza que quer deletar a questions " + questions.title + "?")) {var index = this.questions.indexOf(questions);this.questions.splice(index, 1);this.questionService.deleteQuestion(questions.id).subscribe(null);}}} - Pronto, a parte lógica da listagem está ok (exceto pelo service ainda), agora vamos editar a aparência da aplicação, no arquivo ‘/src/app/questions/questions.component.html’ adicione o seguinte html:
123456789101112131415161718192021222324252627282930313233343536<p>Displaying {{ questions.length }} questions.</p><table><thead><tr><th data-field="name">Titulo</th><th data-field="name">Texto</th></tr></thead><tbody><tr *ngFor="let q of questions"><td>{{ q.title }}</td><td>{{ q.text }}</td><td><a [routerLink]="['/questions', q.id]">Editar</a></td><td><a (click)="deleteQuestion(q)" href="">Deletar</a></td></tr></tbody></table><div style="bottom: 45px; right: 24px;"><a routerLink="/questions/new">Novo</a></div> - Agora vamos para o próximo component, no arquivo /src/app/questions/question-form/question-form.component.ts’ cole o seguinte código para podermos editar e criar questions:
*Note os comentários no código
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061import { Component, OnInit } from '@angular/core';// Importa nosso service para conseguirmos falar com a APIimport { QuestionService } from '../shared/question.service';// Importa nosso Modelimport {Question} from "../shared/question";// Importa o Router para podermos conseguir pegar o parâmetro idimport { Router, ActivatedRoute } from '@angular/router';@Component({selector: 'app-question-form',templateUrl: './question-form.component.html',styleUrls: ['./question-form.component.css']})export class QuestionFormComponent implements OnInit {// Cria uma variável string para falarmos se é uma edição ou criação de Questiontitle: string;// Pega nosso Model e coloca na variável questionquestion: Question = new Question();constructor(//Declara nossas dependênciasprivate questionService: QuestionService,private router: Router,private route: ActivatedRoute) { }// Esse método rola enquanto a página é carregada para preencher// a question caso seja ediçãongOnInit() {var id = this.route.params.subscribe(params => {var id = params['id'];this.title = id ? 'Edit Faq Question' : 'Create Faq Question';if (!id)return;this.questionService.getQuestion(id).subscribe(question => this.question = question,response => {});});}// Nós chamamos esse método no form quando estamos prontos para criar// uma questão ou editarsave() {var result;if (this.question.id){result = this.questionService.updateQuestion(this.question);} else {result = this.questionService.addQuestion(this.question);}result.subscribe(data => this.router.navigate(['/']));}} - Pronto, a parte lógica da edição/criação está ok (exceto pelo service ainda), agora vamos editar a aparência da aplicação, no arquivo ‘/src/app/questions/question-form/question-form.component.html’ adicione o seguinte html:
12345678910111213141516<div class="container"><h1>{{ title }}</h1><form (ngSubmit)="save()"><div><label for="name">Title</label><input type="text" id="title" required [(ngModel)]="question.title" name='title'></div><div><label for="text">Text</label><input type="text" id="text" required [(ngModel)]="question.text" name='text'></div><button type="submit">Submit</button></form><hr /><a routerLink="/">Back to Questions</a></div> - Excelente, nossos components estão ok, agora vamos configurar nosso service. No arquvio ‘src/app/questions/shared/questions.service.ts’ susbstitua o conteúdo pelo seguinte código:
*Note os comentários no código
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647import { Injectable } from '@angular/core';import { Http } from '@angular/http';import 'rxjs/add/operator/map';import 'rxjs/add/operator/do';import 'rxjs/add/operator/catch';import { Observable } from 'rxjs/Rx';@Injectable()export class QuestionService {// URL da nossa APIprivate url: string = "http://localhost:3000/questions";constructor(private http: Http) { }// Pega as questions na APIgetQuestions(){return this.http.get(this.url).map(res => res.json());}// Pega uma question na APIgetQuestion(id){return this.http.get(this.url + '/' + id).map(res => res.json());}// Adiciona uma question na APIaddQuestion(question){return this.http.post(this.url, {'question': question}).map(res => res.json());}// Atualiza uma question na APIupdateQuestion(question){return this.http.put(this.url + '/' + question.id, {'question': question}).map(res => res.json());}// Apaga uma question no servidordeleteQuestion(id){return this.http.delete(this.url + '/' + id).map(res => res.json());}} - Pronto \o/, agora vamos testar.
- Rode no seu console:
1ng serve --port 9000 - Acessando no browser, seu resultado deve ser similar a este:
* É claro que não é um Faq muito bonito, mas ele funciona e é suficiente para demonstrar a integração 🙂
- Agora você pode criar novas questões, editá-las e deletá-las \o/, parabéns nós conseguimos!

Não perca nenhum conteúdo
Receba nosso resumo semanal com os novos posts, cursos, talks e vagas o/
CONCLUSÃO
Pronto, conseguimos fazer o nosso não tão simples CRUD, mas valeu a pena :). É claro que esse é um tutorial introdutório apenas para te dar uma visão geral de como o Angular 2 e o Rails 5 podem se comunicar e também para abrir um pouco a sua mente para a estrutura do Angular 2. Mas tenho certeza que você notou a riqueza dos dois frameworks e as possibilidades ilimitadas que eles trazem se usados juntos 🙂
Como de costume o Código completo da aplicação está no Github, caso você queria clonar o código, clique aqui para ver a parte do Angular 2 e kansas city backpage women seeking men para acessar a parte do Rails 5. Aproveita e me segue lá \o/
Apenas informando novamente que o Bootcamp do OneBitCode está com as inscrições abertas (quase fechando já) e nesse bootcamp nós vamos nos aprofundar muito no Rails 5 e também no Angular 2 (fullstack) através da criação de um clone do Airbnb, então se você ainda não viu a landing page, adult nude dating simulator. Vai ser épico, não deixe essa chance passar! \o/
Se você ficou com dúvidas ou tem sugestões de posts para o Blog comenta aí em baixo ou me adiciona no Facebook https://onebitcode.com/best-dating-sites-free-2019/.
Muito Obrigado,
Sua presença aqui é uma honra para mim,
Leonardo Scorza 🙂
Primeira vez no OneBitCode? Curtiu esse conteúdo?
O OneBitCode tem muito mais para você!
O OneBitCode traz conteúdos de qualidade, e em português, sobre programação com foco em Ruby on Rails e também JavaScript.
Além disso, aqui sempre levamos à você conteúdos valiosos sobre a carreira de programação, dicas sobre currículos, portfólios, perfil profissional, soft skills, enfim, tudo o que você precisa saber para continuar evoluindo como Programador(a)!
Fique por dentro de todos os conteúdos o/
Nossas redes sociais:
📹 • over 60 dating servi cve [Live todas as terças-feiras às 19h)
💻 • https://linkedin.com/company/onebitcode
🙂 • https://facebook.com/onebitcode
📱 • https://instagram.com/one_bit_code
🐦 • https://twitter.com/onebitcode
Nossos cursos:
🥇 • Programador Full Stack Javascript em 8 Semanas
💎 • Curso Completo de Ruby
⚙ • Minicurso: API Rails 5 Completo
🐞 • Minicurso de Testes para Ruby on Rails com RSpec
Espero que curta nossos conteúdos e sempre que precisar de ajuda, fala com a gente!
Estamos aqui para você 🙂
Bem-vindo à família OneBitCode o/