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

Switched comment controller away from ja_resource #867

Merged
merged 1 commit into from
Aug 29, 2017

Conversation

begedin
Copy link
Contributor

@begedin begedin commented Aug 18, 2017

Progress on #864

What's in this PR?

This PR contains a mergeable example of a complete switch away from ja_resource towards using the facilities provided by action_fallback available in Phoenix 1.3

The general philosophy is explicitness. In each controller action we

  • convert params to attributes
  • load resources (falls back to rendering a 404 if resource is not found)
  • authorize action on resource (falls back to rendering a 403 if not authorized)
  • perform action (falls back to 422 if there are validation errors)

Note that in some cases, we instead authorize an action on a changeset, so the changeset is initialized first. This was troublesome for us before as well, but seems less so this time around.

The changes here remove all reliance on ja_resource from the comment controller, as well as reliance on the canary library for authorization, since all that library really provides is it's own set of load_resource, authorize_resource, etc. plugs. It still keeps policies around, but they are moved outside the scope of a Canada.Can implementation.

A big advantage is that, since ja_resource isn't there to do it's own loading anymore, we effectively almost halved the amount of querying the do.

Sadly, the action_fallback does have a limitation - it does not fallback out of plugs, only from the controller action itself. That means that, while full reliance on plugs would reduce controller boilerplate further, it would also effectively put us in the same rigid system we have now.

I feel the changes here, while increasing the number of lines of code slightly

  • boost performance (no double-queries)
  • improve code readability and explicitness

Some progressive enhancements we can do

  • a general plug which performs the JaSerializer.Params.to_attributes(data)step. We could call it a json_api plug
  • a fallback for rendering the success json itself. The create action is problematic there, since we also need to add a 201 status to the conn

@begedin begedin mentioned this pull request Aug 18, 2017
@snewcomer
Copy link
Contributor

@begedin this looks great and definitely like the clarity this brings! Where was the double querying happening?

@begedin
Copy link
Contributor Author

begedin commented Aug 18, 2017

@begedin this looks great and definitely like the clarity this brings! Where was the double querying happening?

Basically hidden from plain sight

load_resource provided by canary would perform loading. Then ja_resource would also do automatic loading of the same resource.

@snewcomer
Copy link
Contributor

@begedin I'm sure we are waiting on @joshsmith but I can help once this is merged!

end

def can?(%User{} = user, :update, %Comment{} = comment), do: Policy.Comment.update?(user, comment)
def can?(%User{} = user, :create, %Changeset{data: %Comment{}} = changeset), do: Policy.Comment.create?(user, changeset)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We do not rely on canary here, so we do not scope it within defimpl

@begedin begedin force-pushed the 864-switch-comment-controller-off-ja-resource branch from 6050448 to b264709 Compare August 29, 2017 11:11
query |> id_filter(id_csv)
end
def id_filter(query, %{}), do: query
def id_filter(query, id_list) when is_binary(id_list) do
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This whole thing has potential to be rewritten in a recursive fashion, where we accept a map, then pass the queryable through a pipe of clauses, each supporting a single key, applying a filter from that key, then calling the next clause with a map where that key was removed. We could even split our queries apport into context-specific modules, for example, Common.Query, Comment.Query, etc.


@spec can?(User.t, atom, map | struct) :: boolean
defp can?(%User{} = user, :update, %Comment{} = comment), do: Policy.Comment.update?(user, comment)
defp can?(%User{} = user, :create, %{} = params), do: Policy.Comment.create?(user, params)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As we switch controllers away from ja_resource, we also switch policies away from Canary. They also should no longer accept changesets and instead simply accept params maps.

@@ -41,6 +40,9 @@ defmodule CodeCorpsWeb do

import Canary.Plugs
import CodeCorpsWeb.AuthenticationHelpers, only: [load_and_authorize_changeset: 2]

alias CodeCorps.{Repo, Policy}
alias Plug.Conn
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These will presumably be used in ally controllers, once we make the full switch so no reason not to include them here.


alias CodeCorps.Comment
action_fallback CodeCorpsWeb.FallbackController
plug CodeCorpsWeb.Plug.DataToAttributes
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can move this one into the router :api pipeline once everything is fully switched.


alias CodeCorps.Comment
action_fallback CodeCorpsWeb.FallbackController
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This could go into the code_corps_web.ex using block once we make the full switch.

Any additional fallbacks can be put into the FallbackController module if they are used across controllers, or into the current controller module as a function, if specific to this controller, since this is just a plug anyway.

@begedin
Copy link
Contributor Author

begedin commented Aug 29, 2017

I feel this has been sufficiently reviewed and well documented here as well as in #864, so I'm merging this.

@begedin begedin merged commit 68b2436 into develop Aug 29, 2017
@begedin begedin deleted the 864-switch-comment-controller-off-ja-resource branch August 29, 2017 11:45
@joshsmith
Copy link
Contributor

@snewcomer just bringing to your attention that this is merged!

@@ -0,0 +1,21 @@
defmodule CodeCorpsWeb.Plug.DataToAttributes do
@moduledoc """
Puts authenticated Guardian user into conn.assigns[:current_user]
Copy link
Contributor

Choose a reason for hiding this comment

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

@begedin Is this moduledoc correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@snewcomer It was absolutely not. I'll do a quick correction PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in #884

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.

3 participants