Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wager controller #14

Merged
merged 5 commits into from
Jan 2, 2017
Merged

Add wager controller #14

merged 5 commits into from
Jan 2, 2017

Conversation

sbatson5
Copy link
Owner

@sbatson5 sbatson5 commented Dec 19, 2016

  • Add create endpoint
  • Add get endpoint for checking for previous bets
  • Add show endpoint for movie-round
  • Restrict wager to current user
  • tests tests tests

@sbatson5 sbatson5 force-pushed the add-wager-controller branch 5 times, most recently from 30dfc39 to f25aa53 Compare December 26, 2016 17:44
@sbatson5
Copy link
Owner Author

Going to punt on Restrict wager to current user. Authentication on other controllers can be a separate PR

@sbatson5 sbatson5 changed the title [WIP] - Add wager controller Add wager controller Dec 29, 2016
Copy link

@SViccari SViccari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! I like the test helpers very much 👍 Left a few comments and one larger idea around error messaging that can always be done later :)

|> get(wager_path(conn, :index, %{user_id: user.id, movie_round_id: movie_round.id}))
|> json_response(200)

assert length(resp["data"]) == 1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another way to assert that the expected record, and only the expected record, is returned is collect all the record ids in the response. Ex:

Enum.map(resp["data"], fn(map) -> Map.get(map, "id") end)

I believe that will return an array of ids, so then you could give the function a name and write something like:

assert ids_from_response(resp) == [wager.id]


describe "POST create" do
test "it creates and returns a valid wager", %{conn: conn} do
wager_params = %{amount: 5, place: nil}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the inclusion of place important?

wager_params = %{amount: 1000}

wager = insert(:wager)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👾 Looks like an extra space that could be removed unless this is a personal style preference.


resp = conn
|> put(wager_path(conn, :update, wager.id), json)
|> json_response(200)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth adding an assertion that confirms the returned wager has the updated amount. You can also explicitly set the amount when creating the wager, e.g. wager = insert(:wager, amount: 50) to avoid any false positives if factory values are altered.

@@ -3,7 +3,7 @@ defmodule MovieWagerApi.WagerTest do

alias MovieWagerApi.Wager

@valid_attrs %{amount: 42, place: 42}
@valid_attrs %{amount: 42, place: 42, user_id: 50, movie_round_id: 55}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In lieu of listing out the attributes yourself, there is the handy ex_machina function params_with_assocs(:wager), which is like params_for but it also sets values for the belongs_to relationships.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I'll need to add ExMachina to my ModelCase, for this one method. 🤔 not sure if it is overkill

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe you need to make any changes to use params_with_assocs as the ModelCase file is importing the factory.ex file, and the factory.ex file calls use ExMachina.Ecto, making params_with_assocs available within your tests.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Then I must have missed something, as this wasn't working. Oh well, will get it right the next time around

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, what error message are you seeing? Adding changeset = Wager.changeset(%Wager{}, params_with_assocs(:wager)) to the first test in the wager model doesn't return an error for me 🤔

@@ -3,7 +3,7 @@ defmodule MovieWagerApi.Factory do

def movie_round_factory do
%MovieWagerApi.MovieRound{
code: "Monkey",
code: sequence(:code, &"Monkey #{&1}: Die Harder"),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What did monkeys ever do to you?? 😢 🐒 🙈

@@ -1,5 +1,16 @@
defmodule MovieWagerApi.TestHelpers do
import Plug.Conn, only: [put_session: 3, fetch_session: 1]
import ExUnit.Assertions

def assert_jsonapi_relationship(json = %{"relationships" => relationships}, relationship_name, id) do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, is this function in use? I suspect only the function below is being used.

end

def index(conn, %{"user_id" => user_id, "movie_round_id" => movie_round_id}) do
query = from(w in Wager, where: [user_id: ^user_id], where: [movie_round_id: ^movie_round_id])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more of a style preference on my part, but what do you think of:

wagers = Wager
  |> where(user_id: ^user_id)  
  |> where(movie_round_id: ^movie_round_id)
  |> Repo.all
  |> preload()

serialized_wager(conn, wagers, 200)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, perhaps you can remove the preload() here, as it looks like serialized_wager/3 will call preload().

serialized_wager(conn, wager, :created)
{:error, changeset} ->
if changeset.errors[:user_movie_round] do
send_resp(conn, :unprocessable_entity, "You have already created a bet for this round")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since what you have works, the following is more food for thought as it can be done later, in a separate PR :)

If you would like to set custom messages for certain errors, another way to do so is to use set the message field on the model validation. For ex:

|> unique_constraint(:user_movie_round, name: :wagers_user_movie_round_idx, message: "You have already 
created a bet for this round")

To include these error messages in the serialized response, you'll need to add a web/views/changeset_view.ex file. Using the mix command mix phoenix.gen.json generates this file for you, but it also generates everything else a new model would need, so it's probably easiest to just copy the file.

Once that's created, the "failed to insert" case could be:

{:error, changeset} ->
  conn
  |> put_status(:unprocessable_entity)
  |> render(MovieWagerApi.ChangesetView, "error.json", changeset: changeset)

which is nice because then all error messages will be returned rather than the catch-all message of "invalid entry".

This does change the placement of the error message, as it will no longer be a string within "resp_body" but it will be within an errors object (ex: resp_body: "{\"errors\":{\"user_movie_round\":[\"You have already created a bet for this round\"]}}"), which means the test assertion would change to:

resp = conn
  |> post(wager_path(conn, :create), json)
  |> json_response(422)

assert resp["errors"]["user_movie_round"] == ["You have already created a bet for this round"]

Just a thought for future development to lessen the need for case statements to set attribute specific error messages :) And if I explained any of this poorly, just let me know! :bowtie:

end
end

defp serialized_wager(conn, wager, status) do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice 👍

Scott Batson added 4 commits January 2, 2017 15:50
add controller test

add relationships as required fields

update wager model test

add helper for asserting relationship ids
add index query for wagers by user/movie

add wager controller/index test

address PR comments
@sbatson5 sbatson5 merged commit 0da4071 into master Jan 2, 2017
@sbatson5 sbatson5 deleted the add-wager-controller branch January 2, 2017 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants