Aula 1 – Back-end com Ruby on Rails
Planejamento: 00:02:53
Criação do Projeto: 00:15:09
Gerando os models: 00:19:24
Relacionamentos: 00:27:22
Melhorando os models: 00:31:37
Preparando os Controllers: 00:36:15
Incluindo imagens nos models: 00:42:26
Preparando os dados de teste: 00:46:12
Preparando os controllers: 00:55:05
Filtros: 01:18:15
Criando um novo pedido: 01:25:27
Configurando o CORS na API: 01:43:53
Sumário
0 – Links importantes
- Guia para instalar as dependências: https://onebitcode.com/guia-de-instalacao-do-ruby-on-rails
- API completa no GitHub: https://github.com/OneBitCodeBlog/onebitfoodV2-api
A ideia inicial
Criar um APP inspirado no Ifood usando Ruby On Rails como API e Next.js como cliente Web
-
Mockups
-
Modelo do banco de dados
-
Ferramenta:
-
-
Documentação dos endpoints
-
Ferramenta: https://www.postman.com
-
Material: https://documenter.getpostman.com/view/10378249/TzRPk9yD
-
Dependências
A seguir, veja as dependências para este projeto
-
Ruby 3.0.1
-
Ruby on Rails 6.0
-
Sqlite
Instalação
Criando o projeto
Nesta etapa você criará e realizará as configurações iniciais do projeto.
-
Crie o projeto executando o seguinte comando
1rails new OneBitFood --api -
Entre na pasta do projeto
1cd OneBitFood -
Adicione as seguintes gems ao seu Gemfile
12gem 'ransack'gem 'rack-cors'-
Ransack
-
Para realizar as pesquisas
-
-
Rack Cors
-
Para conseguirmos chamar nossa API com segurança através do frontend
-
-
-
Instale as gems
1bundle install
Banco de dados
-
Crie o banco de dados executando o comando
1rails db:create
Gerando os Models
Nesta etapa você irá gerar os modelos do projeto.
-
Crie um model para Categoria dos Restaurantes
1 |
rails g model Category title |
-
Crie o model de Restaurante
1 |
rails g model Restaurant name description:text delivery_tax:float city street neighborhood number complement category:references |
-
Para que os restaurantes possam gerenciar suas categorias de produtos, crie o model ProductCategory
1 |
rails g model ProductCategory title restaurant:references |
-
Crie o model Product que representará os produtos oferecidos por um restaurante
1 |
rails g model Product name description:text price:float product_category:references |
-
Crie o model de Pedidos
1 |
rails g model Order name phone_number total_value:float status:integer restaurant:references city street neighborhood number complement |
-
Crie um model para gerenciar os Itens de um Pedido
1 |
rails g model OrderProduct quantity:integer order:references product:references |
Migration
-
Vá até a Migration de criação da tabela Order e adicione um valor padrão para o status de um pedido
1t.integer :status, default: 0 -
Execute as migrations
1rails db:migrate
Nesta aula você irá configurar os relacionamentos entre os models do projeto.
1 – A mesma Categoria pode ser de N Restaurantes. Mapeie o relacionamento adicionando ao model category.rb
1 |
has_many :restaurants |
2 – Um restaurante pode ter N Categorias de Produtos, N Pedidos e N Avaliações Faça o relcionamento estre essas tabelas adicionando ao model restaurant.rb
1 2 |
has_many :product_categories has_many :orders |
3 – Uma Categoria de Produto pode ser de N Produtos Mapeie esta relação adicionando ao model product_category.rb
1 |
has_many :products |
4 – Um Pedido pode ter N Itens do Pedido Faça este relacionamento adicionando ao model order.rb
1 |
has_many :order_products |
5 – Um Produto pode estar em N Itens do pedido Mapeie o relacionamento adicionando ao model product.rb
1 |
has_many :order_products |
Nesta aula você irá configurar as validações e o enum para os seus Models.
Validações
-
Adicione as validações para o model Retaurantes
app/models/restaurant.rb
1validates :name, :delivery_tax, :city, :neighborhood, :street, :number, presence: true -
Faça as validações no model de Categorias de Restaurante
app/models/category.rb
1validates :title, presence: true -
Adicione as validações para o model de Pedidos
app/models/order.rb
1validates :name, :phone_number, :total_value, :city, :neighborhood, :street, :number, presence: true -
Realize validações no model de Itens do Pedido
app/models/order_product.rb
1validates :quantity, presence: true -
Faça as validações em Categoria de Produto
app/models/product_category.rb
1validates :title, presence: true -
Adicione as validações para Produto
app/models/product.rb
1validates :name, :price, presence: true
Enum
-
Um Pedido pode estar em andamento ou entregue Para fazer este controle vá ao model Pedido e adicione o seguinte enum
1 |
enum status: { waiting: 0, delivered: 1 } |
Nesta aula você criará os Controllers e Rotas do seu projeto.
Controllers
Abra o terminal, vá até a pasta do projeto e realize as seguintes instruções
-
Crie o controller Categories com a action index
1rails g controller Categories index --skip-routes -
Crie o controller Restaurants com as actions index, show e search
1rails g controller Restaurants index show --skip-routes -
Crie o controller Orders com as actions create e show
1rails g controller Orders create show --skip-routes -
Crie o controller AvailableCities com a action index:
1rails g controller AvailableCities index --skip-routes
Rotas
-
Vá até o arquivo config/routes.rb e adicione as rotas da sua aplicação
123456scope "/api", defaults: {format: :json} doresources :categories, only: [:index]resources :restaurants, only: [:index, :show]resources :orders, only: [:create, :show]resources :available_cities, only: [:index]end
Nesta aula você utilizará o Active Storage para permitir que Categorias, Restaurantes, e Produtos tenham uma imagem de apresentação.
Active Storage
-
Faça a instalação do Active Storage executando o comando
1rails active_storage:install -
Configure para que os arquivos sejam salvos localmente no anbiente de desenvolvimento
config/environments/development.rb
1Rails.application.routes.default_url_options[:host] = 'localhost:3000' -
Execute a migration que foi criada
1rails db:migrate
Models
Para adicionar a possibilidade de um model possuir uma imagem faça:
-
Vá até o model de Categorias e inclua o seguinte código
app/models/category.rb
1has_one_attached :image -
Faça o mesmo processo para o model de Restaurante
app/models/restaurant.rb
1has_one_attached :image -
E por fim, o mesmo para o model de Produtos
1has_one_attached :image
Nessa aula você incluira os dados que serão usados para teste
-
Baixe as imagens do seguinte links (https://drive.google.com/file/d/1vKVyrYw8uMvsfU56n7JjftsvDLNSou-M/view?usp=sharing), descompacte a pasta e coloque em
/public
-
No arquivo seeds.rb coloque:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233Product.destroy_allProductCategory.destroy_allRestaurant.destroy_allCategory.destroy_allputs 'Criando Categorias'path_image = 'public/images/categories/mexican.jpg'c = Category.create(id: 1, title: 'mexicana')c.image.attach(io: File.open(path_image), filename: 'mexican.jpg')path_image = 'public/images/categories/italian.jpeg'c = Category.create(id: 2, title: 'italiana')c.image.attach(io: File.open(path_image), filename: 'italian.jpeg')path_image = 'public/images/categories/japonese.jpeg'c = Category.create(id: 3, title: 'japonesa')c.image.attach(io: File.open(path_image), filename: 'japonese.jpeg')path_image = 'public/images/categories/vegan.jpeg'c = Category.create(id: 4, title: 'vegana')c.image.attach(io: File.open(path_image), filename: 'vegan.jpeg')path_image = 'public/images/categories/peruvian.jpg'c = Category.create(id: 5, title: 'peruana')c.image.attach(io: File.open(path_image), filename: 'peruana.jpg')puts 'Cadastrando Restaurantes'# Mexican Restaurantspath_image = 'public/images/restaurants/1.jpeg'r = Restaurant.create!(name: 'Los Sombreros',description: 'Nossa missão tem sido ajudar as pessoas a alcançar seus objetivos de saúde e bem-estar. Embora tenhamos mudado ao longo dos anos, nossos valores permaneceram os mesmos.',delivery_tax: 5.50,city: 'São Paulo', street: 'Bela terra',number: '1393', neighborhood: 'Mercês', category_id: 1)r.image.attach(io: File.open(path_image), filename: '1.jpg')pc = ProductCategory.create!(title: 'Pratos Mexicanos', restaurant: r)prod = Product.create!(name: 'Nacho Guacamole', price: 19, description: 'Tortilhas com Guacamole', product_category: pc)prod.image.attach(io: File.open('public/images/products/nachosg.jpg'), filename: 'nachosg.jpg')prod = Product.create!(name: 'Nacho', price: 19, description: 'Tortilhas com milho', product_category: pc)prod.image.attach(io: File.open('public/images/products/nachosg2.jpeg'), filename: 'nachosg2.jpeg')# Curitibapath_image = 'public/images/restaurants/1.jpeg'r = Restaurant.create!(name: 'Los Sombreros - CWB',description: 'Nossa missão tem sido ajudar as pessoas a alcançar seus objetivos de saúde e bem-estar. Embora tenhamos mudado ao longo dos anos, nossos valores permaneceram os mesmos.',delivery_tax: 5.50,city: 'Curitiba', street: 'Bela terra',number: '1393', neighborhood: 'Mercês', category_id: 1)r.image.attach(io: File.open(path_image), filename: '1.jpg')pc = ProductCategory.create!(title: 'Pratos Mexicanos', restaurant: r)prod = Product.create!(name: 'Nacho Guacamole', price: 19, description: 'Tortilhas com Guacamole', product_category: pc)prod.image.attach(io: File.open('public/images/products/nachosg.jpg'), filename: 'nachosg.jpg')prod = Product.create!(name: 'Nacho', price: 19, description: 'Tortilhas com milho', product_category: pc)prod.image.attach(io: File.open('public/images/products/nachosg2.jpeg'), filename: 'nachosg2.jpeg')path_image = 'public/images/restaurants/2.jpeg'r = Restaurant.create!(name: 'Ola Que Tal',description: 'Para alcançar e manter essa distinção em comida e vinho, serviço, ambiente e ambiente, o restaurante ganha reputação de primeira classe por gastronomia, hospitalidade graciosa e informada, conforto e beleza que atraem clientes novos e repetidos ano após ano.',delivery_tax: 5.50,city: 'São Paulo', street: 'Aminta de Barros',number: '659', neighborhood: 'Centro', category_id: 1)r.image.attach(io: File.open(path_image), filename: '2.jpg')pc = ProductCategory.create!(title: 'Pratos Mexicanos', restaurant: r)prod = Product.create!(name: 'Burrito', price: 19, description: 'Tortilhas com Guacamole', product_category: pc)prod.image.attach(io: File.open('public/images/products/bt.jpg'), filename: 'bt.jpg')prod = Product.create!(name: 'Quesadilha', price: 25, description: 'Tortilhas de queijo', product_category: pc)prod.image.attach(io: File.open('public/images/products/quesa.jpeg'), filename: 'quesa.jpeg')#Curitibapath_image = 'public/images/restaurants/2.jpeg'r = Restaurant.create!(name: 'Ola Que Tal - CWB',description: 'Para alcançar e manter essa distinção em comida e vinho, serviço, ambiente e ambiente, o restaurante ganha reputação de primeira classe por gastronomia, hospitalidade graciosa e informada, conforto e beleza que atraem clientes novos e repetidos ano após ano.',delivery_tax: 5.50,city: 'Curitiba', street: 'Aminta de Barros',number: '659', neighborhood: 'Centro', category_id: 1)r.image.attach(io: File.open(path_image), filename: '2.jpg')pc = ProductCategory.create!(title: 'Pratos Mexicanos', restaurant: r)prod = Product.create!(name: 'Burrito', price: 19, description: 'Tortilhas com Guacamole', product_category: pc)prod.image.attach(io: File.open('public/images/products/bt.jpg'), filename: 'bt.jpg')prod = Product.create!(name: 'Quesadilha', price: 25, description: 'Tortilhas de queijo', product_category: pc)prod.image.attach(io: File.open('public/images/products/quesa.jpeg'), filename: 'quesa.jpeg')# Italian Restaurantspath_image = 'public/images/restaurants/3.jpeg'r = Restaurant.create!(name: 'Bravo',description: 'Estamos empenhados em usar os melhores ingredientes em nossas receitas. Nenhum alimento deixa a nossa cozinha que nós mesmos não comeríamos.',delivery_tax: 3.50,city: 'São Paulo', street: 'Rua via mar',number: '250', neighborhood: 'Centro', category_id: 2)r.image.attach(io: File.open(path_image), filename: '3.jpg')pc = ProductCategory.create!(title: 'Porções', restaurant: r)prod = Product.create!(name: 'Berinjela à parmegiana', price: 78, description: 'Com arroz e fritas', product_category: pc)prod.image.attach(io: File.open('public/images/products/berinjela.jpg'), filename: 'berinjela.jpg')prod = Product.create!(name: 'Fritas', price: 35, description: 'Bata frita com bacon', product_category: pc)prod.image.attach(io: File.open('public/images/products/fritas.jpg'), filename: 'fritas.jpg')#Maceiopath_image = 'public/images/restaurants/3.jpeg'r = Restaurant.create!(name: 'Bravo - Maceio',description: 'Estamos empenhados em usar os melhores ingredientes em nossas receitas. Nenhum alimento deixa a nossa cozinha que nós mesmos não comeríamos.',delivery_tax: 3.50,city: 'Maceio', street: 'Rua via mar',number: '250', neighborhood: 'Centro', category_id: 2)r.image.attach(io: File.open(path_image), filename: '3.jpg')pc = ProductCategory.create!(title: 'Porções', restaurant: r)prod = Product.create!(name: 'Berinjela à parmegiana', price: 78, description: 'Com arroz e fritas', product_category: pc)prod.image.attach(io: File.open('public/images/products/berinjela.jpg'), filename: 'berinjela.jpg')prod = Product.create!(name: 'Fritas', price: 35, description: 'Bata frita com bacon', product_category: pc)prod.image.attach(io: File.open('public/images/products/fritas.jpg'), filename: 'fritas.jpg')path_image = 'public/images/restaurants/4.jpeg'r = Restaurant.create!(name: 'La Pergoletti',description: 'Nossa missão é estabelecer relações comerciais benéficas com diversos fornecedores que compartilham nosso compromisso com o atendimento ao cliente, qualidade e preços competitivos.',delivery_tax: 6.70,city: 'São Paulo', street: 'Rua Joaquim Pinto',number: '929', neighborhood: 'Vila Gomes Cardim', category_id: 2)r.image.attach(io: File.open(path_image), filename: '4.jpg')pc = ProductCategory.create!(title: 'Fogazzas (Individuais)', restaurant: r)prod = Product.create!(name: 'Fogazza Bacon', price: 12, description: 'Bacon, parmesão e mussarela.', product_category: pc)prod.image.attach(io: File.open('public/images/products/fogazza.jpg'), filename: 'fogazza.jpg')prod = Product.create!(name: 'Fogazza A moda da Casa', price: 12, description: 'Calabresa, bacon, palmito e mussarela.', product_category: pc)prod.image.attach(io: File.open('public/images/products/fogazza.jpg'), filename: 'fogazza.jpg')# Japonese Restaurantspath_image = 'public/images/restaurants/5.jpeg'r = Restaurant.create!(name: 'Sushi Eterno',description: 'Existimos para garantir que cada hóspede receba um serviço rápido, profissional, amigável e cortês.',delivery_tax: 7.50,city: 'São Paulo', street: 'Avenida Manoel Domingos Pinto',number: '507', neighborhood: 'Parque Anhangüera', category_id: 3)r.image.attach(io: File.open(path_image), filename: '5.jpg')pc = ProductCategory.create!(title: 'Entrada', restaurant: r)prod = Product.create!(name: 'Temaki', price: 19.99, description: 'Enrolado de arroz com alga marinha em forma de cone', product_category: pc)prod.image.attach(io: File.open('public/images/products/temaki.jpeg'), filename: 'temaki.jpeg')prod = Product.create!(name: 'Sashimi', price: 30.90, description: 'Peixe cru fatiado, salmao, atum e peixe prego', product_category: pc)prod.image.attach(io: File.open('public/images/products/sashimi.jpg'), filename: 'sashimi.jpg')#Maceiopath_image = 'public/images/restaurants/5.jpeg'r = Restaurant.create!(name: 'Sushi Eterno - Maceio',description: 'Existimos para garantir que cada hóspede receba um serviço rápido, profissional, amigável e cortês.',delivery_tax: 7.50,city: 'Maceio', street: 'Avenida do mar',number: '2344', neighborhood: 'Belo mar', category_id: 3)r.image.attach(io: File.open(path_image), filename: '5.jpg')pc = ProductCategory.create!(title: 'Entrada', restaurant: r)prod = Product.create!(name: 'Temaki', price: 19.99, description: 'Enrolado de arroz com alga marinha em forma de cone', product_category: pc)prod.image.attach(io: File.open('public/images/products/temaki.jpeg'), filename: 'temaki.jpeg')prod = Product.create!(name: 'Sashimi', price: 30.90, description: 'Peixe cru fatiado, salmao, atum e peixe prego', product_category: pc)prod.image.attach(io: File.open('public/images/products/sashimi.jpg'), filename: 'sashimi.jpg')path_image = 'public/images/restaurants/6.jpeg'r = Restaurant.create!(name: 'Okuyamah',description: 'Restaurante conceituado, vencedor por 5 vezes como melhor restaurante Japones de São Paulo.',delivery_tax: 8.30,city: 'São Paulo', street: 'Rua Francisco Artassio',number: '134', neighborhood: 'Jardim das Laranjeiras', category_id: 3)r.image.attach(io: File.open(path_image), filename: '6.jpg')pc = ProductCategory.create!(title: 'Entrada', restaurant: r)prod = Product.create!(name: 'Hossomaki 16 unidades', price: 20.90, description: 'Enrolado fino com folha de alga marinha por fora.', product_category: pc)prod.image.attach(io: File.open('public/images/products/hosomaki.jpg'), filename: 'hosomaki.jpg')prod = Product.create!(name: 'Hot roll - 10 unidades', price: 12, description: '10 unidades.', product_category: pc)prod.image.attach(io: File.open('public/images/products/hot-holl.jpg'), filename: 'hot-holl.jpg')#Maceiopath_image = 'public/images/restaurants/6.jpeg'r = Restaurant.create!(name: 'Okuyamah - Maceio',description: 'Restaurante conceituado, vencedor por 5 vezes como melhor restaurante Japones de São Paulo.',delivery_tax: 8.30,city: 'Maceio', street: 'Rua Francisco Artassio',number: '134', neighborhood: 'Jardim das Laranjeiras', category_id: 3)r.image.attach(io: File.open(path_image), filename: '6.jpg')pc = ProductCategory.create!(title: 'Entrada', restaurant: r)prod = Product.create!(name: 'Hossomaki 16 unidades', price: 20.90, description: 'Enrolado fino com folha de alga marinha por fora.', product_category: pc)prod.image.attach(io: File.open('public/images/products/hosomaki.jpg'), filename: 'hosomaki.jpg')prod = Product.create!(name: 'Hot roll - 10 unidades', price: 12, description: '10 unidades.', product_category: pc)prod.image.attach(io: File.open('public/images/products/hot-holl.jpg'), filename: 'hot-holl.jpg')# Vegan Restaurantspath_image = 'public/images/restaurants/7.jpeg'r = Restaurant.create!(name: 'Club Life',description: 'NOSSA ESPECIALIDADE. pratos vegetais de alta qualidade,com opções de alimentos integrais, sem glúten e sem lactose.',delivery_tax: 5.70,city: 'São Paulo', street: 'Alameda dos Uapês',number: '933', neighborhood: 'Planalto Paulista', category_id: 4)r.image.attach(io: File.open(path_image), filename: '7.jpg')pc = ProductCategory.create!(title: 'Saladas, molhos e wraps', restaurant: r)prod = Product.create!(name: 'Coleslaw', price: 8.99, description: 'Repolho roxo, couve, cenoura, cebola, maionese de castanha e xylitol', product_category: pc)prod.image.attach(io: File.open('public/images/products/coleslaw.jpg'), filename: 'coleslaw.jpg')prod = Product.create!(name: 'Side salad', price: 9.90, description: 'Mix de folhas com cenoura ralada, tomatinho sweet e semente de girassol.', product_category: pc)prod.image.attach(io: File.open('public/images/products/side-salad.jpeg'), filename: 'side-salad.jpeg')path_image = 'public/images/restaurants/8.jpeg'r = Restaurant.create!(name: 'Casa Natural',description: 'Oferecemos, desde 1981, refeições ovo-lacto-vegetarianas, leves, saudáveis, balanceadas e principalmente saborosas, procurando aliar o sabor, a qualidade de vida e o bem-estar dos clientes.',delivery_tax: 8.30,city: 'São Paulo', street: 'Rua Natal',number: '938', neighborhood: 'Cantinho do Céu', category_id: 4)r.image.attach(io: File.open(path_image), filename: '8.jpg')pc = ProductCategory.create!(title: 'Saladas, molhos e wraps', restaurant: r)prod = Product.create!(name: 'Salada de quinoa', price: 20.90, description: 'Alface americana, roxa, frisee, quinoa cozida, cenoura, tomate, damasco dessecado, amendoa crua.', product_category: pc)prod.image.attach(io: File.open('public/images/products/salada-de-quinoa.jpg'), filename: 'salada-de-quinoa.jpg')prod = Product.create!(name: 'Coleslaw', price: 11, description: 'Repolho roxo, couve, cenoura, cebola, maionese de castanha e xylitol', product_category: pc)prod.image.attach(io: File.open('public/images/products/coleslaw2.jpeg'), filename: 'coleslaw2.jpeg') -
Inclua no banco de dados:
1rails db:seedObs: Se você tiver algum problema para rodar os seeds de uma única vez, rode rails c
Nesta aula vamos incluir os métodos para devolver os restaurantes e as categorias
-
Adicione o seguinte código a action index, no controller de Categorias
app/controllers/categories_controller.rb
12@categories = Category.all.order(:title)render json: @categories -
Crie o arquivo index.json.jbuilder em /views/categories e coloque nele:
12345json.array! @categories do |category|json.id category.idjson.title category.titlejson.image_url polymorphic_url(category.image) if category.image.attached?end -
Adicione o seguinte código a action index, no controller Restaurants:
app/controllers/restaurants_controller.rb
1@restaurants = Restaurant.all -
Crie o arquivo index.json.jbuilder em /views/restaurantes e coloque nele:
123json.array! @restaurants do |restaurant|json.partial! restaurantend -
Crie o arquivo _restaurant.json.jbuilder em /views/restaurantes e coloque nele:
12345678910111213141516171819json.id restaurant.idjson.name restaurant.namejson.description restaurant.descriptionjson.status restaurant.statusjson.delivery_tax restaurant.delivery_taxjson.city restaurant.cityjson.street restaurant.streetjson.neighborhood restaurant.neighborhoodjson.number restaurant.numberjson.complement restaurant.complementjson.reference restaurant.referencejson.cep restaurant.cepjson.review restaurant.reviews&.average(:value).round()json.image_url polymorphic_url(restaurant.image) if restaurant.image.attached?json.product_categories restaurant.product_categories do |product_category|json.partial! 'product_categories/product_category', product_category: product_categoryend -
Crie o arquivo _product_category.json.jbuilder em /views/product_categories e coloque nele:
123456json.id product_category.idjson.title product_category.titlejson.products product_category.products do |product|json.partial! 'products/product', product: productend -
Crie o arquivo _product.json.jbuilder em /views/products e coloque nele:
12345json.id product.idjson.name product.namejson.description product.descriptionjson.price product.pricejson.image_url polymorphic_url(product.image) if product.image.attached? -
No Controller app/controllers/restaurants_controller.rb adicione:
1before_action :set_restaurant, only: :show -
Inclua nos métodos privados do controller:
123def set_restaurant@restaurant = Restaurant.find(params[:id])end -
Crie o arquivo show.json.jbuilder em /views/restaurantes e coloque nele:
1json.partial! @restaurant -
No Controller app/controllers/available_cities.rb na action index adicione:
1@available_cities = Restaurant.all.map { |r| r.city }.uniq -
Crie a seguinte estrutura:
12mkdir views/available_citiestouch views/available_cities/index.json.jbuilder -
Coloque no arquivo criado:
1json.available_cities @available_cities
Nesta aula você criará os filtros por Categorias, Restaurantes e Cidade
-
No método index do controller Restaurantes adicione
app/controllers/restaurants_controller.rb
123456def index@restaurants = Restaurant.allfilter_by_query if params[:q]filter_by_city if params[:city]filter_by_category if params[:category]end -
Agora coloque nos métodos privados:
12345678910111213def filter_by_query@restaurants = @restaurants.ransack(name_or_description_cont: params[:q]).resultenddef filter_by_city@restaurants = @restaurants.where(city: params[:city])enddef filter_by_category@restaurants = @restaurants.select do |r|r.category.title == params[:category]endend
Nessa aula você implementará a funcionalidade de Realizar um Pedido
-
Adicione um callback para salvar o valor total do pedido.
Vá até o model de Pedido e adicione o seguninte código
app/models/order.rb
123456789101112before_validation :set_priceprivatedef set_pricefinal_price = 0order_products.each do |order_product|final_price += order_product.quantity * order_product.product.priceendself.total_value = final_priceend -
Para permitir que os Itens de um Pedido sejam salvos junto ao Pedido utilize Nested Attributes
Vá até o model order.rb e adicione a linha a seguir
1accepts_nested_attributes_for :order_products, allow_destroy: true -
Agora adicione o seguinte código ao controller de Pedidos
1234567891011121314151617181920212223242526272829class OrdersController < ApplicationControllerbefore_action :set_order, only: :showdef createorder = Order.new(order_params)if order.saverender json: @order, status: :createdelserender json: order.errors, status: :unprocessable_entityendenddef showrender json: @orderendprivatedef set_order@order = Order.find(params[:id])enddef order_paramsparams.require(:order).permit(:name, :phone_number, :restaurant_id, :address,order_products_attributes: %i[quantity comment product_id])endend -
Crie o arquivo _show.json.jbuilder em /views/orders e coloque nele:
1json.partial! @order -
Crie o arquivo _order.json.jbuilder em /views/orders e coloque nele:
12345json.id order.idjson.restaurant_id order.restaurant_idjson.total_value order.total_valuejson.status order.statusjson.address order.address
Nesta aula vamos ajustar a API para que ela permita chamadas vindas do javascript do Browser
-
Instale a gem rodando:
1bundle install -
Agora substitua o conteúdo do arquivo config/initializers/cors.rb por:
123456789Rails.application.config.middleware.insert_before 0, Rack::Cors doallow doorigins '*'resource '*',headers: :any,methods: [:get, :post, :put, :patch, :delete, :options, :head]endend