dhruvrajvanshi / Moonshine

Web framework for Crystal language [DEPRECATED in favour of kemal]

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Trouble understanding controllers

mrtryhard opened this issue · comments

Hi,
I started (finally) to write my website with Moonshine, and I have little trouble understanding how the controllers work. Note that I am coming from a C# ASP MVC 4 background and I have absolutely , therefore I am used to something that looks like:

HomeController < BaseController
# index is returned by "/Home" and "/Home/index" 
def index  
end
#. . . 

I tried several things such as binding like this :

@router = {
            "GET /Home" =>
                ->(req : Request) { index() },
            "GET /Home/index" =>
                ->(req : Request) { index() }
        } of String => (Request -> Response)

But it didn't work. Any help would be greatly appreciated !

Thanks

you have to override the call method of the controller too
Like this

    def call(req : Moonshine::Request)      
        @router.each do |route, block|
            if Route.new(route.split(" ")[0],
                route.split(" ")[1]).match? req
                return block.call(req)
            end
        end
        return Moonshine::Response.new(404, "unhandled route on controller")
    end

This is because, by default, a Controller object responds to http verb methods (get, post, etc).
I will sort out this controller mess as soon as possible.
In the mean time, check examples/restful.cr for a better way to do controllers (It doesn't involve the controller class).

Okay, now I'm at home, so I got real code with me.

HomeController:

class HomeController < Moonshine::Controller
    def initialize()
        @viewcount = 0
        @router = {
            "GET /Home" => 
                ->(req : Request) { index() },
            "GET /Home/index" =>
                ->(req : Request) { index() }
        } of String => (Request -> Response)
    end

    def call(req : Request)      
        @router.each do |route, block|
            if Route.new(route.split(" ")[0],
                route.split(" ")[1]).match? req
                return block.call(req)
            end
        end
        return Response.new(404, "unhandled route on controller")
    end

    def index() 
      ok("test")
    end

    # Override individual HTTP methods
    def get(req)
        @viewcount += 1
        ok("This page has been visited #{@viewcount} times.")
    end
end

Then I have my app.cr :

app = Moonshine::App.new

app.controller([
        "/",
        "/Home"
    ] of String, HomeController.new)
app.run

When I do access "localhost:8000/" it returns "test"
When I do access "localhost:8000/Home" => page not found
When I do access "localhost:8000/Home/index" => page not found

Perhaps I am missing something ?

Thanks

With the help of the restful example, I've got something working:
app.cr

home_cont = HomeController.new
routes = {
  "GET /home" =>
    ->(req : Request) { 
      home_cont.index 
    },
  "GET /home/index" =>
    ->(req : Request) { 
      home_cont.index 
    },
  "GET /" =>
    ->(req : Request) { 
      home_cont.index 
    }
} of String => Request -> Response

app.add_router(routes)

app.run

HomeController:

class HomeController < Moonshine::Controller
    def initialize()
        @viewcount = 0
    end

    def index() 
      ok("test")
    end
end

It gives the exact result I am wishing for. Now, if it's the way to accomplish it, I don't know, but for now, it works for my mini web app :^)

Thanks !

P.S. I'm open to do it any way you feel is better

Use this pattern for defining controllers

class HomeController < Moonshine::Controller
  actions :index # Do this for each controller method
  @router = { # Routing logic
              "GET /home"       => "index",
              "GET /home/index" => "index",
              "GET /"           => "index",
            }

  def initialize
    @viewcount = 0
  end

  def index(req) # Make sure this takes a request argument
    ok("test")
  end
end

app = App.new
app.controller(HomeController.new)

I think it's readable enough. Can I close this now?

Sure, it is more than readable, understandable, and easy.