3

Context

Here's the PostsController from the blog example in the IHP guide:

instance Controller PostsController where
    action PostsAction = do
        posts <- query @Post
            |> orderByDesc #createdAt
            |> fetch
        render IndexView { .. }

    action NewPostAction = do
        let post = newRecord
        render NewView { .. }

    action ShowPostAction { postId } = do
        post <- fetch postId
            >>= pure . modify #comments (orderByDesc #createdAt)
            >>= fetchRelated #comments 
        render ShowView { .. }

    action EditPostAction { postId } = do
        post <- fetch postId
        render EditView { .. }

    action UpdatePostAction { postId } = do
        post <- fetch postId
        post
            |> buildPost
            |> ifValid \case
                Left post -> render EditView { .. }
                Right post -> do
                    post <- post |> updateRecord
                    setSuccessMessage "Post updated"
                    redirectTo EditPostAction { .. }

    action CreatePostAction = do
        let post = newRecord @Post
        post
            |> buildPost
            |> ifValid \case
                Left post -> render NewView { .. } 
                Right post -> do
                    post <- post |> createRecord
                    setSuccessMessage "Post created"
                    redirectTo PostsAction

    action DeletePostAction { postId } = do
        post <- fetch postId
        deleteRecord post
        setSuccessMessage "Post deleted"
        redirectTo PostsAction

Factoring out an action

Let's suppose I have a controller where one of the action definitions is getting really long and I'd like to maybe put it in a separate file.

Just as an example, let's try to move this one out:

action PostsAction = do
    posts <- query @Post
        |> orderByDesc #createdAt
        |> fetch
    render IndexView { .. }

I tried to setup a separate standalone function:

actionPostsAction = do
    posts <- query @Post
        |> orderByDesc #createdAt
        |> fetch
    render IndexView { .. }

Then my action definition could just be:

action PostsAction = actionPostsAction

However, when I setup the standalone function I get some errors reported in vscode:

enter image description here

Question

What's a good way to factor out an action? Is there a way to do this?

The guide has a section on Controller & Actions but I didn't notice anything there about splitting out actions. Let me know if I missed something there or if there's another place which talks about this.

dharmatech
  • 8,979
  • 8
  • 42
  • 88
  • 1
    I believe if you disable the monomorphism restriction for the file, it will allow this signature to be inferred `{-# LANGUAGE NoMonomorphismRestriction #-}` – luqui Aug 08 '21 at 21:11
  • @luqui You're absolutely right. This also worked perfectly. Thank you! – dharmatech Aug 09 '21 at 04:58
  • 1
    @luqui I posted a video [here](https://ihp.digitallyinduced.com/community/ShowThread?threadId=0ebeb6dc-4951-466e-a602-329620fad5e8) demonstrating an alternative layout for IHP projects. Your hint here helped me with that so thanks again! – dharmatech Aug 13 '21 at 13:42

1 Answers1

3

I think this is one of the cases where an explicit type signature is necessary, this should work:

actionPostsAction
  :: ( ?context      :: ControllerContext
     , ?modelContext :: ModelContext
     , ?theAction    :: PostsController
     )
  => IO () 
actionPostsAction = do
    posts <- query @Post
        |> orderByDesc #createdAt
        |> fetch
    render IndexView { .. }

See also: https://ihp.digitallyinduced.com/Guide/troubleshooting.html#unbound-implicit-parameter-modelcontextmodelcontext

Noughtmare
  • 9,410
  • 1
  • 12
  • 38
  • 2
    MIght just be the monomorphism restriction. – luqui Aug 08 '21 at 21:12
  • 2
    @luqui, yes, I just tested a similar example with implicit parameters which I was able to fixed by disabling the monomorphism restriction. However, I still think adding a type signature is also a good solution. Perhaps combined with a constraint synonym if it gets too repetitive. – Noughtmare Aug 08 '21 at 23:03
  • Just tried this and it worked perfectly for me. Thank you! Excellent answer. – dharmatech Aug 09 '21 at 04:57