DEV Community

Joseph Mancuso for Masonite

Posted on • Edited on

Masonite Coding Tip: Abstracting Recurring Controller Code

Introduction

If you are not familiar with Masonite then you should checkout the GitHub repo.

When developing with Masonite you may notice, if you are not consciously avoiding it, that you have some duplication in your controller logic. In this tutorial we will walk through how to abstract your code a bit inside your controller to make it really clean.

Controller Constructor

If you are not aware of it yet, probably because you skipped over that section in the documentation, you can put anything you need to in a controller constructor. For example if we have code like this:

from app.League import League

class Controller:

    def show(self, Request):
        return Request.redirect_to('settings.plans')

    def store(self, Request):
        league = League.find(Request.param('id'))
        league.name = Request.input('name')
        league.save()

        return Request.redirect_to('settings.plans')
Enter fullscreen mode Exit fullscreen mode

We can abstract the Request object out and into the controller constructor like so:

from app.League import League

class Controller:

    def __init__(self, Request):
        self.request = Request

    def show(self):
        return self.request.redirect_to('settings.plans')

    def store(self):
        league = League.find(self.request.param('id'))
        league.name = self.request.input('name')
        league.save()

        return self.request.redirect_to('settings.plans')
Enter fullscreen mode Exit fullscreen mode

You might find this a bit more of a cleaner approach and a bit more DRY since we only are worrying about a single line for our Request object.

Repetitive Model Finding

After a while you will realize that you have some code that looks like this:

from app.League import League

class LeagueController:

    def __init__(self, Request, View):
        self.request = Request
        self.view = View

    def show(self):
        league = League.find(self.request.param('id'))

        return self.view('league/show', {'league': league})

    def store(self):
        league = League.find(self.request.param('id'))
        league.name = self.request.input('name')
        league.save() 
        return self.request \
            .redirect_to('league.show', {'league': league})

    def delete(self):
        league = League.find(self.request.param('id'))
        league.delete() 
        return self.request \
            .redirect_to('discover')
Enter fullscreen mode Exit fullscreen mode

Notice here that every single method has the same exact code for fetching the league by id and is using it in different ways. We can simply get around this by throwing that in the constructor as well:

from app.League import League

class LeagueController:

    def __init__(self, Request, View):
        self.request = Request
        self.view = View
        self.league = League.find(self.request.param('id'))

    def show(self):
        return self.view('league/show', {'league': self.league})

    def store(self):
        self.league.name = self.request.input('name')
        self.league.save() 
        return self.request \
            .redirect_to('league.show', {'league': self.league})

    def delete(self):
        self.league.delete() 
        return self.request \
            .redirect_to('discover')
Enter fullscreen mode Exit fullscreen mode

This actually cleans the code up quite a bit and it makes sense that if all the logic is going to be working with a single league then to have the constructor set it on the controller.


If you want to explore Masonite a bit more be sure to click that link and give a star or join the Slack channel.

Top comments (0)