Wildlife Tracker Challenge The Forest Service is considering a proposal to place in conservancy a forest of virgin Douglas fir just outside of Portland, Oregon. Before they give the go ahead, they need to do an environmental impact study. They've asked you to build an API the rangers can use to report wildlife sightings.
Story 1: In order to track wildlife sightings, as a user of the API, I need to manage animals.
Branch: animal-crud-actions
Acceptance Criteria
Create a resource for animal with the following information: common name and scientific binomial🐻 Can see the data response of all the animals🐻 def index animals = Animal.all render json: animals end
Can create a new animal in the database🐻 def create animal = Animal.create(animal_params) render json: animal end
private def animal_params params.require(:animal).permit(:common_name, :scientific_binomial) end
Can update an existing animal in the database🐻 def update animal = Animal.find(params[:id]) animal.update(animal_params) render json: animal end
Can remove an animal entry in the database🐻! def destroy animal = Animal.find(params[:id]) animal.destroy render json: animal end
Story 2: In order to track wildlife sightings, as a user of the API, I need to manage animal sightings.
Branch: sighting-crud-actions
Acceptance Criteria
Create a resource for animal sightings with the following information: latitude, longitude, date Hint: An animal has_many sightings (rails g resource Sighting animal_id:integer ...) Hint: Date is written in Active Record as yyyy-mm-dd (“2022-07-28") Can create a new animal sighting in the database Can update an existing animal sighting in the database Can remove an animal sighting in the database
Story 3: In order to see the wildlife sightings, as a user of the API, I need to run reports on animal sightings.
Branch: animal-sightings-reports
Acceptance Criteria
Can see one animal with all its associated sightings🐻 (added sightings to db) http://localhost:3000/animals { "latitude": "48843", "longitude": "39208", "date": "3-27-2024", "animal_id": 2 } (added .includes to animal controller show method) def show animal = Animal.find(params[:id]) render json: animal, include: :animal_sightings end http://localhost:3000/animals/2 Hint: Checkout this example on how to include associated records Can see all the animal sightings during a given time period🐻 Hint: Your controller can use a range to look like this: class SightingsController < ApplicationController def index sightings = Sighting.where(date: params[:start_date]..params[:end_date]) render json: sightings end end Hint: Be sure to add the start_date and end_date to what is permitted in your strong parameters method Hint: Utilize the params section in Postman to ease the developer experience Hint: Routes with params (added a date outside the boundary) http://localhost:3000/animal_sightings { "latitude": "48843", "longitude": "39208", "date": "1-27-2025", "animal_id": 2 } (updated animal_sightings controller) def index # animal_sightings = AnimalSighting.all # sightings = Sighting.where(date: params[:start_date]..params[:end_date]) animal_sightings = AnimalSighting.where(date: params[:start_date]..params[:end_date]) render json: animal_sightings end private def animal_sighting_params params.require(:animal_sighting).permit(:latitude, :longitude, :date, :animal_id) end (used params to help route) http://localhost:3000/animal_sightings/?start_date=2024-01-01&end_date=2024-12-31 [ { "id": 2, "latitude": "48843", "longitude": "39208", "date": "2024-12-14", "created_at": "2024-03-29T20:42:09.698Z", "updated_at": "2024-03-29T21:10:34.774Z", "animal_id": 2 } ]
Stretch Challenges Story 4: In order to see the wildlife sightings contain valid data, as a user of the API, I need to include proper specs.
Branch: animal-sightings-specs
Acceptance Criteria Validations will require specs in spec/models and the controller methods will require specs in spec/requests.
Can see validation errors if an animal doesn't include a common name and scientific binomial Can see validation errors if a sighting doesn't include latitude, longitude, or a date Can see a validation error if an animal's common name exactly matches the scientific binomial Can see a validation error if the animal's common name and scientific binomial are not unique Can see a status code of 422 when a post request can not be completed because of validation errors Hint: Handling Errors in an API Application the Rails Way (in animal_sightings_controller.rb) def update animal_sighting = AnimalSighting.find(params[:id]) animal_sighting.update!(animal_sighting_attributes) animal_sighting.update(animal_sighting_params) render json: animal_sighting end (in animals_controller.rb) def create animal = Animal.new(animal_params) if animal.save render json: animal else render json: animal.errors, status: :unprocessable_entity end end def update animal = Animal.find(params[:id]) animal.update!(animal_attributes) animal.update(animal_params) render json: animal end (in REQUESTS folder within specs folder: animal_spec.rb) require 'rails_helper' RSpec.describe "Animals", type: :request do describe 'POST /animals' do context 'when the request is invalid' do let(:invalid_attributes) { { common_name: nil, scientific_binomial: 'Test' } }
it 'returns status code 422' do
post '/animals', params: { animal: invalid_attributes }
expect(response).to have_http_status(422)
end
end
end
end (in REQUESTS folder within specs folder: animal_sightings_spec.rb) require 'rails_helper'
RSpec.describe "Animals", type: :request do describe "POST /animals" do context "when the request is invalid" do let(:invalid_attributes) { { common_name: nil, scientific_binomial: 'Test' } }
it 'returns status code 422' do
post '/animals', params: { animal: invalid_attributes }
expect(response).to have_http_status(422)
end
end
end end
Story 5: In order to increase efficiency, as a user of the API, I need to add an animal and a sighting at the same time.
Branch: submit-animal-with-sightings
Acceptance Criteria
Can create new animal along with sighting data in a single API request Hint: Look into accepts_nested_attributes_for (in animal.rb) class Animal < ApplicationRecord has_many :animal_sightings accepts_nested_attributes_for :animal_sightings end (in animals_controller.rb) def animal_params params.require(:animal).permit(:common_name, :scientific_binomial, animal_sightings_attributes: [:latitude, :longitude, :date]) end (in post man) http://localhost:3000/animals { "animal": { "common_name": "brown panther", "scientific_binomial": "panther brown", "animal_sightings_attributes": [ { "latitude": 12.345, "longitude": 67.890, "date": "2024-03-23" } ] } }