Following the previous section, we will together find a solution for the relationship between App Server, Web Server and Rails ^^
What is a rack?
Rack is the answer to the previous question. Rack can be understood as a common convention (a protocol) for App Server to communicate with Ruby Web Framework (such as Rails, Sinatra or Padrino) and vice versa.
For example, the App server (Puma) receives a request from the Web Server (Nginx) – the above Blog problem, for example. Puma will pass that request to Rack and Rack will communicate with Web Framework (Rails). Rails will handle the problem in Ruby and respond (in a different way).
Basically a life cycle then looks like this
Request HTTP -> Web Server (Nginx) -> App Server (Puma) -> Rack -> Ruby Web Framework (Rails)
The end result will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 | env = { 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/blog', 'HTTP_HOST' => 'viblo.asia, # ... } status, headers, body = app.call(env) status # => 200 headers # => { 'Content-Type' => 'text/plain' } body # => ['Blog'] |
Before diving into Rails, let’s try to build a simple Rack application
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token comment"># app.rb</span> <span class="token keyword">class</span> <span class="token class-name">Blog</span> <span class="token keyword">def</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">if</span> env <span class="token punctuation">[</span> <span class="token string">'PATH_INFO'</span> <span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">'/blog'</span> <span class="token punctuation">[</span> <span class="token number">200</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">'Content-Type'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'text/plain'</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string">'Blog'</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token keyword">else</span> <span class="token punctuation">[</span> <span class="token number">404</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">'Content-Type'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'text/plain'</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string">'Not Found'</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">end</span> |
This can be understood as one of the simplest Rack applications we can build. It doesn’t have a class or anything else involved, it’s simply a class that declares the call
method. It will check the request env
from env
, if it matches the path /blog
, it will respond to the simple text Blog
, otherwise it will have to return 404 and Not Found
text
Okay, now that we have written our application, how do we use it? How do we connect everything? Recall that Rack is just a protocol that web servers can implement, so we’ll need to connect our application to a Rack-aware web server.
Luckily, in Ruby we have a library called Gem
. It’s Rack
gem – a library of all utilities to make and use Rack. Configuration call to the class
above will be as follows
1 2 3 4 5 6 | # config.ru require_relative 'app' run HelloWorld.new |
This is basically a Ruby file with some additional DSL configuration. Here, we require building and using a version of the Blog
application and passing it to the rackup
server using DSL run
With that, we can run the rackup
command from the directory of the config.ru
file and it will attach the server to port 9292 by default. If we visit http://localhost:9292/blog
, we will see “Blog” and if we navigate to http://localhost:9292/xxx
, we will see the “Not Found” error.
Now we modify a bit to specify the path to root /
to /blog
as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token comment"># app.rb</span> <span class="token keyword">class</span> <span class="token class-name">Blog</span> <span class="token keyword">def</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">if</span> env <span class="token punctuation">[</span> <span class="token string">'PATH_INFO'</span> <span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">'/'</span> <span class="token punctuation">[</span> <span class="token number">301</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">'Location'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'/blog'</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token keyword">elsif</span> env <span class="token punctuation">[</span> <span class="token string">'PATH_INFO'</span> <span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">'/blog'</span> <span class="token punctuation">[</span> <span class="token number">200</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">'Content-Type'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'text/plain'</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string">'Blog'</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token keyword">else</span> <span class="token punctuation">[</span> <span class="token number">404</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">'Content-Type'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'text/plain'</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string">'Not Found'</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">end</span> |
Try it again … of course it works fine, but not good. If we add a lot of paths here, then if
. elsif
. else
forever and ever ???
Redirect
is a basic task so we need to rewrite it better to use it for multiple places in our application. So we’ll find ways to rewrite it in a module
and reuse it everywhere.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <span class="token keyword">class</span> <span class="token class-name">Redirect</span> <span class="token keyword">def</span> <span class="token function">initialize</span> <span class="token punctuation">(</span> app <span class="token punctuation">,</span> from <span class="token punctuation">:</span> <span class="token punctuation">,</span> to <span class="token punctuation">:</span> <span class="token punctuation">)</span> <span class="token variable">@app</span> <span class="token operator">=</span> app <span class="token variable">@from</span> <span class="token operator">=</span> from <span class="token variable">@to</span> <span class="token operator">=</span> to <span class="token keyword">end</span> <span class="token keyword">def</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">if</span> env <span class="token punctuation">[</span> <span class="token string">"PATH_INFO"</span> <span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token variable">@from</span> <span class="token punctuation">[</span> <span class="token number">301</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"Location"</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">@to</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token keyword">else</span> <span class="token variable">@app</span> <span class="token punctuation">.</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">class</span> <span class="token class-name">Blog</span> <span class="token keyword">def</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">if</span> env <span class="token punctuation">[</span> <span class="token string">"PATH_INFO"</span> <span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">'/blog'</span> <span class="token punctuation">[</span> <span class="token number">200</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"Content-Type"</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">"text/plain"</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string">"Blog"</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token keyword">else</span> <span class="token punctuation">[</span> <span class="token number">404</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">"Content-Type"</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">"text/plain"</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string">"Not Found!"</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">end</span> |
In the above writing, we basically keep the same logic as the Blog class
. However, we will add a Redirect class
to handle general requests. If the request matches the path it will give the redirect response and finish. If not, it will authorize the next application we have written.
Next we change config.ru
as follows
1 2 3 4 5 6 7 8 | require_relative <span class="token string">'app'</span> run <span class="token constant">Redirect</span> <span class="token punctuation">.</span> <span class="token keyword">new</span> <span class="token punctuation">(</span> <span class="token constant">Blog</span> <span class="token punctuation">.</span> <span class="token keyword">new</span> <span class="token punctuation">,</span> from <span class="token punctuation">:</span> <span class="token string">'/'</span> <span class="token punctuation">,</span> to <span class="token punctuation">:</span> <span class="token string">'/blog'</span> <span class="token punctuation">)</span> |
We build an instance of the Blog
application and pass it to the Redirect
application. In this way, we have deployed an intermediary called the Rack middleware
. However, the middleware is not part of Rack’s technique – it is only part of the app we wrote above (Redirect). It just “happens to” call another Rack application as part of the #call
method, and the web server doesn’t need to know this.
The pattern
middleware is so popular that config.ru
has a dedicated DSL
keyword for it
1 2 3 4 5 6 | require_relative <span class="token string">'app'</span> use <span class="token constant">Redirect</span> <span class="token punctuation">,</span> from <span class="token punctuation">:</span> <span class="token string">'/'</span> <span class="token punctuation">,</span> to <span class="token punctuation">:</span> <span class="token string">'/blog'</span> run <span class="token constant">Blog</span> <span class="token punctuation">.</span> <span class="token keyword">new</span> |
middleware pattern
really “strong”. We don’t need to write any more code here, simply add some config
middleware from the rack
gem:
1 2 3 4 5 6 7 8 9 10 11 | require_relative 'app' use Rack::Deflater use Rack::Head use Rack::ConditionalGet use Rack::ETag use Redirect, from: '/', to: '/blog' run Blog.new |
This is how we build a Redirect application
Rails Rack
We are finally ready with Rails.
Of course, Rails will deploy Rack already. If you look at your Rails application, it will come with a config.ru file that looks like this:
1 2 3 4 | require_relative <span class="token string">'config/environment'</span> run <span class="token constant">Rails</span> <span class="token punctuation">.</span> application |
Although config.ru
is derived from rackup
, it is also understood by some other servers and web services such as Heroku, so Rails may include it by default.
As we learned at the beginning of the article, we have to transfer a Rack
application for the run
keyword, so Rails.application
must be a Rack
application that responds to #call
. We will try a bit with the rails console
1 2 3 | 2.5.1 :001 > env = Rack::MockRequest.env_for('http://localhost:3000/blog') => {"rack.version"=>[1, 3], "rack.input"=>#<StringIO:0x0000000005c96a58>, "rack.errors"=>#<StringIO:0x0000000005c96b20>, "rack.multithread"=>true, "rack.multiprocess"=>true, "rack.run_once"=>false, "REQUEST_METHOD"=>"GET", "SERVER_NAME"=>"localhost", "SERVER_PORT"=>"3000", "QUERY_STRING"=>"", "PATH_INFO"=>"/blog", "rack.url_scheme"=>"http", "HTTPS"=>"off", "SCRIPT_NAME"=>"", "CONTENT_LENGTH"=>"0"} |
Instead of rewriting an env
hash manually, we can use Rack::MockRequest.env_for
– a method from rack
gem.
One thing that stands out from the config.ru
file in our Rails application is that it doesn’t have any user statements. Does Rails use any middleware? Is not! In fact, there is a handy command that you can run to see all the middleware in your application using the familiar config.ru
syntax:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | $ bin/rails middleware use Rack::Sendfile use ActionDispatch::Executor use ActiveSupport::Cache::Strategy::LocalCache::Middleware use Rack::Runtime use Rack::MethodOverride use ActionDispatch::RequestId use ActionDispatch::RemoteIp use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::DebugExceptions use ActionDispatch::Callbacks use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ContentSecurityPolicy::Middleware use Rack::Head use Rack::ConditionalGet use Rack::ETag use Rack::TempfileReaper run Blorgh::Application.routes |
We can see that Rails has implemented many of its functions in intermediary software, such as cookie handling. This is great, because if we are deploying an API server, we can remove these unnecessary middleware. But how?
Recall that using statement is only a convenience in building your application in config.ru
, the web server only “sees” the most external application. Rails has a different convenience for managing middleware in config/application.rb
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <span class="token comment"># config/application.rb</span> require_relative <span class="token string">'boot'</span> <span class="token keyword">require</span> <span class="token string">'rails/all'</span> <span class="token constant">Bundler</span> <span class="token punctuation">.</span> <span class="token keyword">require</span> <span class="token punctuation">(</span> <span class="token operator">*</span> <span class="token constant">Rails</span> <span class="token punctuation">.</span> groups <span class="token punctuation">)</span> <span class="token keyword">module</span> <span class="token constant">Blorgh</span> <span class="token keyword">class</span> <span class="token class-name">Application</span> <span class="token operator"><</span> <span class="token constant">Rails</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">Application</span> <span class="token comment"># Disable cookies</span> config <span class="token punctuation">.</span> middleware <span class="token punctuation">.</span> delete <span class="token constant">ActionDispatch</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">Cookies</span> config <span class="token punctuation">.</span> middleware <span class="token punctuation">.</span> delete <span class="token constant">ActionDispatch</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">Session</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">CookieStore</span> config <span class="token punctuation">.</span> middleware <span class="token punctuation">.</span> delete <span class="token constant">ActionDispatch</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">Flash</span> <span class="token comment"># Add your own middleware</span> config <span class="token punctuation">.</span> middleware <span class="token punctuation">.</span> use <span class="token constant">CaptchaEverywhere</span> <span class="token keyword">end</span> <span class="token keyword">end</span> |
Final …
So we looked at middleware, but where are our “apps”? The answer is from the output of the bin/rails middleware
, and we need to know how to use and run this middleware for our application. And Blorgh:Application.routes
was born.
The Rack application looks at the URL requets, matches a series of routing rules required to find the appropriate controller
or action
called. Rails gives you a place to declare these things, it’s written in config.routes.rb
.
1 2 3 4 5 6 | <span class="token comment"># config/routes.rb</span> <span class="token constant">Rails</span> <span class="token punctuation">.</span> application <span class="token punctuation">.</span> routes <span class="token punctuation">.</span> draw <span class="token keyword">do</span> resources <span class="token symbol">:blogs</span> <span class="token keyword">end</span> |
DSL
resources look familiar to Rails application developers. It is a concise syntax
to define a series of routes at once. Fully written, it will include the following 7 routes
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token comment"># config/routes.rb</span> <span class="token constant">Rails</span> <span class="token punctuation">.</span> application <span class="token punctuation">.</span> routes <span class="token punctuation">.</span> draw <span class="token keyword">do</span> <span class="token comment"># resources :blogs becomes...</span> get <span class="token string">'/blogs'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'blogs#index'</span> get <span class="token string">'/blogs/new'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'blogs#new'</span> post <span class="token string">'/blogs'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'blogs#create'</span> get <span class="token string">'/blogs/:id'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'blogs#show'</span> get <span class="token string">'/blogs/:id/edit'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'blogs#edit'</span> put <span class="token string">'/blogs/:id'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'blogs#update'</span> delete <span class="token string">'/blogs/:id'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token string">'blogs#destroy'</span> <span class="token keyword">end</span> |
For example, when you make a GET request to /blogs
, it will call the BlogsController#index
, if you make a PUT
request to /blogs/:id
, it will go to BlogsController#update
.
So … what are the blogs#index
series? It is simply an abbreviation for the action
index in BlogsController
. If you learn the code
of Rails, you will find that it will eventually expand to BlogsController.action(:index)
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <span class="token keyword">class</span> <span class="token class-name">ActionController</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">Base</span> <span class="token keyword">def</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> <span class="token function">action</span> <span class="token punctuation">(</span> name <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token punctuation">{</span> request <span class="token operator">=</span> <span class="token constant">ActionDispatch</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">Request</span> <span class="token punctuation">.</span> <span class="token keyword">new</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> response <span class="token operator">=</span> <span class="token constant">ActionDispatch</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">Response</span> <span class="token punctuation">.</span> <span class="token keyword">new</span> <span class="token punctuation">(</span> request <span class="token punctuation">)</span> controller <span class="token operator">=</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> <span class="token keyword">new</span> <span class="token punctuation">(</span> request <span class="token punctuation">,</span> response <span class="token punctuation">)</span> controller <span class="token punctuation">.</span> <span class="token function">process_action</span> <span class="token punctuation">(</span> name <span class="token punctuation">)</span> response <span class="token punctuation">.</span> to_a <span class="token punctuation">}</span> <span class="token keyword">end</span> attr_reader <span class="token symbol">:request</span> <span class="token punctuation">,</span> <span class="token symbol">:response</span> <span class="token punctuation">,</span> <span class="token symbol">:params</span> <span class="token keyword">def</span> <span class="token function">initialize</span> <span class="token punctuation">(</span> request <span class="token punctuation">,</span> response <span class="token punctuation">)</span> <span class="token variable">@request</span> <span class="token operator">=</span> request <span class="token variable">@response</span> <span class="token operator">=</span> response <span class="token variable">@params</span> <span class="token operator">=</span> request <span class="token punctuation">.</span> params <span class="token keyword">end</span> <span class="token keyword">def</span> <span class="token function">process_action</span> <span class="token punctuation">(</span> name <span class="token punctuation">)</span> event <span class="token operator">=</span> <span class="token string">'process_action.action_controller'</span> payload <span class="token operator">=</span> <span class="token punctuation">{</span> controller <span class="token punctuation">:</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> name <span class="token punctuation">,</span> action <span class="token punctuation">:</span> action_name <span class="token punctuation">,</span> <span class="token comment"># ...</span> <span class="token punctuation">}</span> <span class="token constant">ActiveSupport</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">Notifications</span> <span class="token punctuation">.</span> <span class="token function">instrument</span> <span class="token punctuation">(</span> event <span class="token punctuation">,</span> payload <span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> name <span class="token punctuation">)</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">end</span> |
Finally, putting everything together, you can imagine the routing application is a rack application that looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <span class="token keyword">class</span> <span class="token class-name">BlorghRoutes</span> <span class="token keyword">def</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> verb <span class="token operator">=</span> env <span class="token punctuation">[</span> <span class="token string">'REQUEST_METHOD'</span> <span class="token punctuation">]</span> path <span class="token operator">=</span> env <span class="token punctuation">[</span> <span class="token string">'PATH_INFO'</span> <span class="token punctuation">]</span> <span class="token keyword">if</span> verb <span class="token operator">==</span> <span class="token string">'GET'</span> <span class="token operator">&&</span> path <span class="token operator">==</span> <span class="token string">'/blogs'</span> <span class="token constant">BlogsController</span> <span class="token punctuation">.</span> <span class="token function">action</span> <span class="token punctuation">(</span> <span class="token symbol">:index</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">elsif</span> verb <span class="token operator">==</span> <span class="token string">'GET'</span> <span class="token operator">&&</span> path <span class="token operator">==</span> <span class="token string">'/blogs/new'</span> <span class="token constant">BlogsController</span> <span class="token punctuation">.</span> <span class="token function">action</span> <span class="token punctuation">(</span> <span class="token symbol">:new</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">elsif</span> verb <span class="token operator">==</span> <span class="token string">'POST'</span> <span class="token operator">&&</span> path <span class="token operator">==</span> <span class="token string">'/blogs'</span> <span class="token constant">BlogsController</span> <span class="token punctuation">.</span> <span class="token function">action</span> <span class="token punctuation">(</span> <span class="token symbol">:create</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">elsif</span> verb <span class="token operator">==</span> <span class="token string">'GET'</span> <span class="token operator">&&</span> path <span class="token operator">=</span> <span class="token operator">~</span> <span class="token regex">%r(/blogs/.+)</span> <span class="token constant">BlogsController</span> <span class="token punctuation">.</span> <span class="token function">action</span> <span class="token punctuation">(</span> <span class="token symbol">:show</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">elsif</span> verb <span class="token operator">==</span> <span class="token string">'GET'</span> <span class="token operator">&&</span> path <span class="token operator">=</span> <span class="token operator">~</span> <span class="token regex">%r(/blogs/.+/edit)</span> <span class="token constant">BlogsController</span> <span class="token punctuation">.</span> <span class="token function">action</span> <span class="token punctuation">(</span> <span class="token symbol">:edit</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">elsif</span> verb <span class="token operator">==</span> <span class="token string">'PUT'</span> <span class="token operator">&&</span> path <span class="token operator">=</span> <span class="token operator">~</span> <span class="token regex">%r(/blogs)</span> <span class="token constant">BlogsController</span> <span class="token punctuation">.</span> <span class="token function">action</span> <span class="token punctuation">(</span> <span class="token symbol">:update</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">elsif</span> verb <span class="token operator">==</span> <span class="token string">'DELETE'</span> <span class="token operator">&&</span> path <span class="token operator">=</span> <span class="token regex">%r(/blogs/.+)</span> <span class="token constant">BlogsController</span> <span class="token punctuation">.</span> <span class="token function">action</span> <span class="token punctuation">(</span> <span class="token symbol">:destroy</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">call</span> <span class="token punctuation">(</span> env <span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">[</span> <span class="token number">404</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string">'Content-Type'</span> <span class="token punctuation">:</span> <span class="token string">'text-plain'</span> <span class="token punctuation">,</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token string">'Not Found!'</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">end</span> |
It matches the given request path and http verbs against the rules defined in your config routes
and authorizes the appropriate Rack application on the controller
. The good thing is you don’t have to write everything on by hand. Thanks Rails!
summary
In this article, I have basically introduced the life cycle of a request in the Rails application, from the receipt of the end-user request in the browser, to the way that the request is sent to handle in the Rails controller
.
thank you for watching
The article was translated and referenced from: