[RUBY] Let's make Rails-like 2 (controller edition)

Introduction

This article is a continuation of the previous one. ↓ ↓ ↓ https://qiita.com/alex0033/items/73f62ac7e5700ab2b4d6

This time, I would like to implement routing in Rails because it is a controller edition.

The directory structure you should aim for is as follows.

directory
  |- app
      |- controllers
           |- basic_pages_controller
      |- views
           |- basic_pages
               |- home.html.erb #home page
               |- next.html.erb #Next page
  |- config
       |- routes.rb
  |- srv.rb

point

Until the last time, it is in the following state.

-You can set up a server by typing ruby srv.rb in the terminal. -When you access http: // localhost: 3000, the home page is displayed.

The goals this time are as follows.

-When you access http: // localhost: 3000 (hereafter, root path), the home page is displayed. -When you access http: // localhost: 3000 / next (hereafter, next path), the next page is displayed. ・ Pass through the controller before accessing the page

Therefore, the explanation of this article is as follows.

    1. Display of next page ① Create view file (app / views / basic_pages / next.html.erb) ② Try to access from the homepage with \ tag </ em> ③ Change the setting (srv.rb)
  1. Creating a controller-like ① Reflection of logic by Servlet ② Organize files to make it look like a controller
    1. routing ① Create a routing configuration file (config / routes.rb) (2) Automatic generation of routing by metaprogramming

1. 1. Display of next page

First, let's create a next page so that it can be displayed. Describe in the following order.

① Create view file (app / views / basic_pages / next.html.erb) ② Try to access from the homepage with \ tag </ em> ③ Change the setting (srv.rb)

① Create view file (app / views / basic_pages / next.html.erb)

Let's create a view file.

erb:app/views/basic_pages/next.html.erb


<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h1>Next page</h1>
    <p>This is a next page.</p>
  </body>
</html>

② Try to access from the homepage with \ tag </ em>

The existence of the view file alone is not enough to access it. Therefore, let's try to access it from the home page using the \ tag </ em>.

erb:app/views/basic_pages/home.html.erb


<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h1>home page</h1>
    <p>Hello, World</p>
    <%= 1 + 4 %>

    <!--Link to next page-->
    <a href="../next.html.erb">to next</a>
  </body>
</html>

When you access the root path, you should see something like this: Screenshot from 2020-11-06 11-56-54.png Try touching "to next" to follow the link.

Perhaps the URL is just http: //localhost: 3000/next.html.erb.

③ Change the setting (srv.rb)

So far, we have set the path to the home page as DocumentRoot.

From here, set to `` `app / views``` and set the URL and display file individually.

srv.rb


require 'webrick'

op = {
    BindAdress: "127.0.1",
    Port: 3000,
    DocumentRoot: "."
}

WEBrick::HTTPServlet::FileHandler.add_handler("erb", WEBrick::HTTPServlet::ERBHandler)
s = WEBrick::HTTPServer.new(op)

#Below, individual settings for URL and display file
s.mount('/', WEBrick::HTTPServlet::FileHandler, 'app/views/basic_pages/home.html.erb')
s.mount('/next', WEBrick::HTTPServlet::FileHandler, 'app/views/basic_pages/next.html.erb')

s.start

You have now set the root path and next path.

However, the link to the homepage has not been set, so let's set it.

erb:app/views/basic_pages/home.html.erb


<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h1>home page</h1>
    <p>Hello, World</p>
    <%= 1 + 4 %>
    <!--Link setting to the next page-->
    <a href="/next">to next</a>
  </body>
</html>

erb:app/views/basic_pages/next.html.erb


<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h1>Next page</h1>
    <p>This is a next page.</p>

    <!--Link setting to homepage-->
    <a href="/">to home</a>
  </body>
</html>

You can now go back and forth between the home page and the next page by clicking "to next" or "to home".

Reference ↓ ↓ ↓ https://docs.ruby-lang.org/ja/latest/library/webrick.html https://docs.ruby-lang.org/ja/latest/method/WEBrick=3a=3aHTTPServer/i/mount.html

2. Creating a controller

Up to this point, you can now transition screens by setting the URL.

From here, let's make it possible to display the view after passing through the controller.

① Reflection of logic by Servlet ② Organize files to make it look like a controller

① Reflection of logic by Servlet

First, let's use a Servlet to reflect the logic before the page transition.

srb.rb


require 'webrick'
require 'erb'

include WEBrick

op = {
    BindAdress: "127.0.1",
    Port: 3000,
    DocumentRoot: "."
}

s = HTTPServer.new(op)

#Servlet
class HomeServlet < HTTPServlet::AbstractServlet
    def do_GET(req, res)
        #Start of logic
        @home_string = "pass homeServlet"
        #Logic end
        erb = ERB.new File.open('app/views/basic_pages/home.html.erb').read
        res.body = erb.result(binding)
    end
end

class NextServlet < HTTPServlet::AbstractServlet
    def do_GET(req, res)
        #Start of logic
        @next_string = "pass nextServlet"
        #Logic end
        erb = ERB.new File.open('app/views/basic_pages/next.html.erb').read
        res.body = erb.result(binding)
    end
end

s.mount('/', HomeServlet)
s.mount('/next', NextServlet)
trap(:INT){ s.shutdown }
s.start

This should reflect the value of the instance variable.

app/views/basic_pages_controller.rb


<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h1>home page</h1>
    <p>Hello, World</p>
    <p><%= 1 + 4 %></p>
    <a href="/next">to next</a>
    <p><%= @home_string %></p>
    <p><%= @next_string %></p>
  </body>
</html>

If you set up a server and access the home page, you can see the display of the character string "pass home Servlet" stored in the instance variable.

Reference ↓ ↓ ↓ http://unageanu.hatenablog.com/entry/20080720/1216539411 https://magazine.rubyist.net/articles/0017/0017-BundledLibraries.html

② Organize files to make it look like a controller

As it is, the logic corresponding to the controller is written in srv.rb, and the outlook is bad.

Therefore, let's organize by creating new directories and files.

app/controllers/basic_apges_cotroller.rb


require 'erb'

def render_result(path)
    erb = ERB.new File.open("app/views/#{path}.html.erb").read
    erb.result(binding)
end

module BasicPagesController
    class HomeServlet < HTTPServlet::AbstractServlet
        def do_GET(req, res)
            @home_string = "pass homeServlet"
            res.body = render_result 'basic_pages/home'
        end
    end

    class NextServlet < HTTPServlet::AbstractServlet
        def do_GET(req, res)
            @next_string = "pass nextServlet"
            res.body = render_result 'basic_pages/next'
        end
    end
end

srv.rb


require 'webrick'
include WEBrick

op = {
    BindAdress: "127.0.1",
    Port: 3000,
    DocumentRoot: "."
}

s = HTTPServer.new(op)

#Logic for displaying the home page and next page
require './app/controllers/basic_pages_controller.rb'
include BasicPagesController
s.mount('/', HomeServlet)
s.mount('/next', NextServlet)

trap(:INT){ s.shutdown }
s.start

With this, it was quite refreshing.

3. 3. routing

At this point, we have implemented page display through the controller.

However, if nothing is done, srv.rb will be manually updated every time a new page is created.

Then, it is difficult to understand what kind of page there is, so use the routing file (config / routes.rb) to organize it.

Follow the steps below to implement it.

① Create a routing configuration file (config / routes.rb) (2) Automatic generation of routing by metaprogramming

① Create a routing configuration file (config / routes.rb)

config/routes.rb


class Routes
    def initialize
        @routes = Array.new
    end

    def make_routes
        #The route is described below
        get "/", "basic_pages", "home"
        get "/next", "basic_pages", "next"

        #The return value is listed below(Returns a list of route information)
        return @routes
    end

    def get(url, controller_name, action)
        @routes.push({ url: url, controller_name: controller_name, action: action }) 
    end
end

In srv.rb, create an instance so that you can generate and get a list of routes with make_routes.

(2) Automatic generation of routing by metaprogramming

Based on config / routes.rb, you need to write the code to set the actual routing in srv.rb.

srv.rb


require 'webrick'
include WEBrick

op = {
    BindAdress: "127.0.1",
    Port: 3000,
    DocumentRoot: "."
}

s = HTTPServer.new(op)

#Extension of String class
class String
    def to_camel()
        self.split("_").map{ |w| w[0] = w[0].upcase; w }.join
    end
end

#Get routing information
require './config/routes.rb'
r = Routes.new
routes = r.make_routes

#Automatically generate routing with metaprogramming
routes.each do |route|
    require "./app/controllers/#{route[:controller_name]}_controller.rb"
    include eval("#{route[:controller_name].to_camel}Controller")

    s.mount route[:url], eval("#{route[:action].to_camel}Servlet")
end

trap(:INT){ s.shutdown }
s.start

This completes the routing.

Summary

This time it is a controller edition, so I implemented page transition through the controller.

It seems that there is still a long way to go to make it look like rails, but I would like to implement it little by little.