Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion app/controllers/customers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,36 @@ def index
)
end

private
def show
@customer = Customer.find_by(id: params[:id])

unless @customer
render json: {
errors: ['Customer Not Found'],
}, status: :bad_request

return
end

rentals = @customer.rentals.map do |rental|
{
id: rental.id,
customer_id: rental.customer_id,
movie_id: rental.movie_id,
name: @customer.name,
title: rental.movie.title,
checkout_date: rental.checkout_date,
due_date: rental.due_date,
returned: rental.returned
}
end

render json: rentals.as_json(), status: :ok
return
end

private

def parse_query_args
errors = {}
@sort = params[:sort]
Expand Down
34 changes: 33 additions & 1 deletion app/controllers/movies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class MoviesController < ApplicationController
before_action :require_movie, only: [:show]

def index
if params[:query]
if params[:query] # maybe the user search input?
data = MovieWrapper.search(params[:query])
else
data = Movie.all
Expand All @@ -11,7 +11,9 @@ def index
render status: :ok, json: data
end

# runs require_movie before this action
def show
# if movie exists, status: ok and return movie info
render(
status: :ok,
json: @movie.as_json(
Expand All @@ -21,6 +23,32 @@ def show
)
end


def create
movie = Movie.new(movie_params)

# if movie is already in db, don't add
if Movie.find_by(external_id: movie.external_id)
render json: {
errors: "This movie is already in the database"
}, status: :forbidden
return
end

if movie.save
# render json: movie.as_json(only: [:id, :title, :overview, :release_date, :image_url, :external_id]), status: :created
# return
render json: movie.as_json(only: [:id]), status: :created
return

else
render json: {
errors: movie.errors.messages
}, status: :bad_request

end
end

private

def require_movie
Expand All @@ -29,4 +57,8 @@ def require_movie
render status: :not_found, json: { errors: { title: ["No movie with title #{params["title"]}"] } }
end
end

def movie_params
return params.permit(:title, :overview, :release_date, :image_url, :external_id, :inventory)
end
end
4 changes: 2 additions & 2 deletions app/controllers/rentals_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ class RentalsController < ApplicationController
before_action :require_movie, only: [:check_out, :check_in]
before_action :require_customer, only: [:check_out, :check_in]

# TODO: make sure that wave 2 works all the way
def check_out
rental = Rental.new(movie: @movie, customer: @customer, due_date: params[:due_date])

Expand All @@ -14,7 +13,7 @@ def check_out
end

def check_in
rental = Rental.first_outstanding(@movie, @customer)
rental = Rental.first_outstanding(@movie, @customer) # grabs first rental that matches movie & customer and is not returned
unless rental
return render status: :not_found, json: {
errors: {
Expand All @@ -31,6 +30,7 @@ def check_in
end

def overdue
# return all rentals where returned: false, and due date is before today
rentals = Rental.overdue.map do |rental|
{
title: rental.movie.title,
Expand Down
1 change: 1 addition & 0 deletions app/models/customer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ class Customer < ApplicationRecord
has_many :rentals
has_many :movies, through: :rentals

# returns number of movies checked out
def movies_checked_out_count
self.rentals.where(returned: false).length
end
Expand Down
3 changes: 3 additions & 0 deletions app/models/movie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ class Movie < ApplicationRecord
has_many :rentals
has_many :customers, through: :rentals

validates :title, uniqueness: true, presence: true
# validates :inventory, presence: true

def available_inventory
self.inventory - Rental.where(movie: self, returned: false).length
end
Expand Down
1 change: 1 addition & 0 deletions app/models/rental.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def self.overdue
end

private
# due_date must be after today's date
def due_date_in_future
return unless self.due_date
unless due_date > Date.today
Expand Down
4 changes: 2 additions & 2 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html

resources :customers, only: [:index]
resources :customers, only: [:index, :show]

resources :movies, only: [:index, :show], param: :title
resources :movies, only: [:index, :show, :create], param: :title # show uses title instead of ID

post "/rentals/:title/check-out", to: "rentals#check_out", as: "check_out"
post "/rentals/:title/return", to: "rentals#check_in", as: "check_in"
Expand Down
63 changes: 33 additions & 30 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,51 @@
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
# This file is the source Rails uses to define your schema when running `rails
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20180618042754) do
ActiveRecord::Schema.define(version: 2018_06_18_042754) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

create_table "customers", force: :cascade do |t|
t.string "name"
t.string "name"
t.datetime "registered_at"
t.string "address"
t.string "city"
t.string "state"
t.string "postal_code"
t.string "phone"
t.float "account_credit"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "address"
t.string "city"
t.string "state"
t.string "postal_code"
t.string "phone"
t.float "account_credit"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "movies", force: :cascade do |t|
t.string "title"
t.text "overview"
t.date "release_date"
t.integer "inventory"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_url"
t.integer "external_id"
t.string "title"
t.text "overview"
t.date "release_date"
t.integer "inventory"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_url"
t.integer "external_id"
end

create_table "rentals", force: :cascade do |t|
t.integer "customer_id"
t.integer "movie_id"
t.date "checkout_date"
t.date "due_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "returned"
t.integer "customer_id"
t.integer "movie_id"
t.date "checkout_date"
t.date "due_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "returned"
t.index ["customer_id"], name: "index_rentals_on_customer_id"
t.index ["movie_id"], name: "index_rentals_on_movie_id"
end
Expand Down
10 changes: 7 additions & 3 deletions lib/movie_wrapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@ class MovieWrapper

BASE_IMG_URL = "https://image.tmdb.org/t/p/"
DEFAULT_IMG_SIZE = "w185"
DEFAULT_IMG_URL = "http://lorempixel.com/185/278/"
# DEFAULT_IMG_URL = "http://lorempixel.com/185/278/"
DEFAULT_IMG_URL = "https://i.imgur.com/Uw59wWE.png?1"


def self.search(query, retries_left=3)
raise ArgumentError.new("Can't search without a MOVIEDB_KEY. Please check your .env file!") unless KEY

url = BASE_URL + "search/movie?api_key=" + KEY + "&query=" + query

response = HTTParty.get(url)
response = HTTParty.get(url) # MovieDB API call

if response.success?
# if no results, return empty array
if response["total_results"] == 0
return []
# if results, create new Movie for each result
else
movies = response["results"].map do |result|
self.construct_movie(result)
Expand All @@ -25,7 +29,7 @@ def self.search(query, retries_left=3)
elsif retries_left > 0
sleep(1.0 / (2 ** retries_left))

return self.search(query, retries_left - 1)
return self.search(query, retries_left - 1) # recursively call search while there are more than 0 retries_left
else
raise "Request failed: #{url}"
end
Expand Down
55 changes: 55 additions & 0 deletions test/controllers/movies_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,59 @@ class MoviesControllerTest < ActionDispatch::IntegrationTest

end
end

describe "create" do
let(:movie_params) {
{
title: "Parasite",
overview: "test!",
inventory: 10,
image_url: "image test",
external_id: 123976
}
}

it "creates a movie with valid data" do
count = Movie.count

expect {
post movies_path, params: movie_params
}.must_differ "Movie.count", 1

expect(Movie.count).must_equal count + 1

must_respond_with :created
end

it "will respond with bad_request for invalid data" do
movie_params[:title] = nil

expect {
post movies_path, params: movie_params
}.wont_change "Movie.count"

must_respond_with :bad_request

expect(response.header['Content-Type']).must_include 'json'
body = JSON.parse(response.body)

expect(body["errors"].keys).must_include "title"
end


it "cannot add the same movie twice" do
count = Movie.count

post movies_path, params: movie_params

expect {
post movies_path, params: movie_params
}.wont_differ "Movie.count"

expect(Movie.count).must_equal count + 1

must_respond_with :forbidden
expect(body).must_include "This movie is already in the database"
end
end
end