In phoenix framework with pipeline we can enable specify middlewares for some route, for example:
defmodule HelloPhoenix.Router do
use HelloPhoenix.Web, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", HelloPhoenix do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
end
scope "/api", HelloPhoenix do
pipe_through :api
end
end
if request from /api, will only trigger plug :accepts, ["json"] middleware
if request from /, will trigger session, flash, ...etc middlewares
how to achieve this on rails, If I am using grape for build api and rails for build web page and enable difference middleware for each other?
Unlike Phoenix applications, you cannot (easily) change what middleware is used for a request within Rails. The best way to get this kind of behaviour in a Rails application would be to make the controllers for a particular route inherit from a common base controller, and then define the behaviour for these particular controllers in that base controller.
Using the above example of the /api routes going through different "middleware", you can have a controller like this:
module API
class BaseController < ActionController::API
# things unique to API routes go here
end
end
Inside this controller, you could write some before_action callbacks that ensure things like:
Then you can inherit from this controller for all API controllers:
module API
class PostsController < API::BaseController
end
end
With your regular controllers you can do all the regular things:
class ApplicationController < ActionController::Base
# things unique to non-api routes go here
end
And then:
class PostsController < ApplicationController
end
You could of course segment it more; maybe you might have another route like /accounts/1/posts where you have to be authenticated as the user of that account to see the posts. You can take the same approach:
module Accounts
class BaseController < ActionController::Base
# find account, check if the user is authenticated, etc.
end
end
And:
module Accounts
class PostsController < Accounts::BaseController
end
end
So in summary: Rails doesn't let you do this on a routing level (easily), but you can accomplish the same thing at the controller level.
The solution I was looking for was something more in this direction:
application.rb:
# after Bundler.require(...)
require_relative '../lib/engines/website/lib/website'
lib/engines/website/lib/website.rb:
require_relative "website/engine"
module Website; end
lib/engines/website/lib/website/engine.rb:
module Website
class Engine < ::Rails::Engine
middleware.use ActionDispatch::Cookies
middleware.use ActionDispatch::Session::CookieStore
middleware.use ActionDispatch::Flash
end
end
config/routes.rb:
mount Website::Engine => "/website"
And everything for the website goes in the typical directory structure under the engine directory:
lib
engines
website
app
assets
...
controllers
...
views
...
config
routes.rb
lib
website
website.rb
Reference: Build 2 middleware stacks in Rails app
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With