vanderleipinto / TT4

0 stars 0 forks source link

TT4 01 Desafio API #2

Closed vanderleipinto closed 6 months ago

vanderleipinto commented 6 months ago

Desafio API

Criar um endpoint que faça a leitura de um arquivo .csv, popule o banco de dados com essas informações e com isso será necessário exibir todos os registros em json.

Requisitos:

● O desafio deve ser desenvolvido utilizando Ruby e tendo o Rails como framework; ● Seguindo o padrão API RESTful; ● Seguir o Rubocop style-guide; ● A leitura do arquivo .csv deve ser através de um endpoint diferente da listagem de títulos; ● Ordenar pelo ano de lançamento; ● Filtrar os registros por ano de lançamento, gênero, país*; ● Garantir que não haja duplicidade de registros; ● O projeto deve ser disponibilizado em um repositório aberto no GitHub. Envie a URL assim que possível; ● A response do endpoint deve obedecer o padrão abaixo:

[  
  {
        "id": 656,
        "title": "13 Reasons Why",
        "genre": "TV Show",
        "release_year": "2020",
        "country": "United States",
        "date_added": "2020-06-05",
        "description": "After a teenage girl's perplexing suicide, a classmate receives a series of tapes that unravel the mystery of her tragic choice."
    }
]

Dicas: ● Testes são bem-vindos;; ● Tipo de banco de dados em aberto, pode escolher tanto relacional quanto não relacional; ● O filtro pode ser aplicado por 1 ou mais itens, mas devem atender aos requisitos; ● O arquivo .csv, entitulado netflix_titles.csv, poderá ser encontrado no anexo do email com o desafio;

vanderleipinto commented 6 months ago

Criação do projeto

O projeto foi criado usando o comando rails new TT4 --api -d mysql

O comando rails new TT4 --api -d mysql é utilizado para criar um novo projeto Rails chamado "TT4" configurado como uma API e utilizando o banco de dados MySQL. Vamos analisar cada opção fornecida:

Portanto, o comando rails new TT4 --api -d mysql, cria um novo projeto Rails configurado como uma API e utilizando o banco de dados MySQL como backend de armazenamento de dados. Isso é útil quando se cria uma aplicação que servirá principalmente como uma API JSON e não precisa de toda a complexidade de uma aplicação Rails tradicional com views HTML.

Adicionamos a gem 'csv' no arquivo Gemfile

vanderleipinto commented 6 months ago

Criação do model movies

O model foi criado usando o comando rails g scaffold movies show_id type director cast:text country date_added release_year rating duration listed_in:text description:text Os atributos foram retirados do header do arquivo csv.

O comando rails g scaffold é uma forma de gerar rapidamente uma estrutura básica para um recurso no Rails, incluindo um modelo, uma migração de banco de dados, um controller e views associadas. Vamos analisar os componentes do comando fornecido:

Portanto, ao executar o comando rails g scaffold movies show_id type director cast:text country date_added release_year rating duration listed_in:text description:text,que está sendo criado um scaffold completo para o recurso "movies", incluindo um modelo Movie com os atributos especificados, uma migração de banco de dados para criar a tabela correspondente no banco de dados, um controller MoviesController com métodos para manipular operações CRUD, como o projeto foi criado focado no api, as views não serão criadas.

O arquivo app/models/movie.rb ficou da seguinte maneira:

class Movie < ApplicationRecord
  validates :title, uniqueness: true
end

validates :title, uniqueness: true => Aqui faz-se uma validação de modo que o banco de dados não aceita dois movies com o mesmo title.

vanderleipinto commented 6 months ago

Configuração e geração do Banco de dados.

Vamos alterar o arquivo config/database.yml para que o sistema possa acessar o banco de dados. Vamos adicionar a senha do banco de dados na nossa máquina. No nosso caso 1234

``yml default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: 1234 socket: /var/run/mysqld/mysqld.sock


Agora podemos gerar o banco de dados com o comando:
`rails db:create`

Uma vez criado o bando de dados vamos adicionar a tabela do movies com o comando:
`rails db:migrate`

Esse comando usa como parâmetro o arquivo gerado anteriormente com o comando rails g scaffold. Esse comando criou um arquivo em db/migrate/XXX_create_movies.rb. 

```ruby
class CreateMovies < ActiveRecord::Migration[7.1]
  def change
    create_table :movies do |t|
      t.string :show_id
      t.string :genre 
      t.string :title
      t.string :director
      t.text :cast
      t.string :country
      t.date :date_added
      t.string :release_year
      t.string :rating
      t.string :duration
      t.text :listed_in
      t.text :description

      t.timestamps
    end
  end
end

OBS: Substituímos o header type por genre já que type é uma palavra privada e não é aceita como nome de coluna no banco de dados. Faremos as mudanças necessárias no controller.

Agora já temos o banco de dados com a tabela necessária para a inserção de dados.

vanderleipinto commented 6 months ago

Alteração do arquivo routes.rb

Adicionada a seguinte rota:

  resources :movies, only: [:index, :create]
  get '/movies/read_csv', to: 'movies#read_csv'

O arquivo routes.rb é uma parte fundamental de um aplicativo Rails. Ele é responsável por definir as rotas da aplicação, ou seja, as URLs que o aplicativo responderá e quais controladores e ações serão acionados em resposta a essas URLs.

O comando resources é uma forma conveniente de definir rotas RESTful em um aplicativo Rails. Ele gera automaticamente várias rotas padrão que são comumente usadas em uma arquitetura RESTful, incluindo rotas para criar, ler, atualizar e excluir recursos.

Por exemplo, ao adicionar resources :movies ao arquivo routes.rb, estão sendo geradas automaticamente as seguintes rotas:

Essas rotas podem ser personalizadas ou ampliadas conforme necessário, mas o comando resources fornece uma maneira rápida e fácil de definir as rotas básicas para um recurso em um aplicativo Rails. O arquivo routes.rb é onde todas essas rotas são definidas e configuradas para o aplicativo.

Como foi o caso da adição da rota get '/movies/read_csv', to: 'movies#read_csv'

Essa é uma rota para a action que lê o arquivo csv, altera alguns dados e salva no banco de dados.

vanderleipinto commented 6 months ago

Alteração do arquivo movies_controller.rb

O arquivo app/controllers/movies_controller.rb foi criado automaticamente com as actions necessárias para uma API. Agora faremos algumas alterações para o funcionamento do sistema de acordo com nossas necessidades.

Criação da action read_csv.

Responsável pela

  • Leitura do arquivo csv
  • Conversão o valor do campo date_added(string) para Date
  • Modificão da key type para genre para se adequar ao banco de dados.
 def read_csv    
    csv_data  = []

    CSV.foreach('app/data/TT_ 4 - netflix_titles.csv', headers: true) do |row|
      csv_data << row.to_hash
    end 

    #converte o valor do campo date_added(string) para Date modifica  a key type para movie_type
    csv_data.each do |item|
      item['genre'] = item['type']
      item.delete('type')
      item['date_added'] = Date.strptime(item['date_added'],"%h %d, %y")
    end

    #insere todos os valores no Banco de Dados
    csv_data.each do |movie_data|
      Movie.create(movie_data)
    end   

    render json: Movie.all
  end

A sequir ele faz a leitura do arquivo csv. Transforma em hash e insere na array csv_data

    csv_data  = []
    #Leitura do arquivo csv. Transforma em hash e insere na array csv_data
    CSV.foreach('app/data/TT_ 4 - netflix_titles.csv', headers: true) do |row|
      csv_data << row.to_hash
    end 

Obs: o CSV é da gem 'csv'.

Então faz-se a conversão do valor do campo date_added(string) para Date e modificação da key type para movie_type

    #converte o valor do campo date_added(string) para Date modifica  a key type para movie_type
    csv_data.each do |item|
      item['genre'] = item['type']
      item.delete('type')
      item['date_added'] = Date.strptime(item['date_added'],"%h %d, %y")
    end

Agora é só percorrer a hash e inserir no banco de dados, seguindo o código abaixo.

 #insere todos os valores no Banco de Dados
    csv_data.each do |movie_data|
      Movie.create(movie_data)
    end   

Alteração da action index

def index
    @movies = Movie.select(:id, :title, :genre, :release_year, :country , :date_added, :description ).order(:release_year)

    # Filtragem por ano
    @movies = @movies.where("genre like ? and country like ? and release_year like ?" ,"%#{params[:genre]}%", "%#{params[:country]}%", "%#{params[:release_year]}%")  

    render json: @movies
  end

A variável @movies vai consultar o banco de dados fazendo um select somente para os dados que queremos: @movies = Movie.select(:id, :title, :genre, :release_year, :country , :date_added, :description ).order(:release_year)

A sequir temos a filtragem dos dados de acordo com os parâmetros recebidos:

    @movies = @movies.where("genre like ? and country like ? and release_year like ?" ,"%#{params[:genre]}%", "%#{params[:country]}%", "%#{params[:release_year]}%")  

E então renderizamos o resultado em formato de json.