我正在构建一个允许用户属于许多“组织”的Rails 5.2 SaaS应用程序。用户只能看到当前活动组织的内容。
我开始使用子域名的路径,但经过一些研究后decided to avoid them for now。
我的新方法(向用户明确说明他们正在使用的组织,支持共享链接,浏览器历史记录等)是将组织名称嵌入路径中。例如:
https://app.example.com/foo/posts # Posts for org "foo"
https://app.example.com/foo/posts/7 # Post for org "foo"
https://app.example.com/bar/posts # Posts for org "bar"
https://app.example.com/settings # General account settings
https://app.example.com/signin # Sign in
我的问题是如何使用Rails路由执行此操作?我试过使用动态范围:
scope ':org' do
resources :posts
end
导致错误如:
No route matches {:action=>"show", :controller=>"posts", :org=>#<Organization id: 1, name: "My Organization", ...}, missing required keys: [:id]
代码:
# layouts/application.html.erb
<%= link_to post, post, class: 'dropdown-item' %>
有关如何配置路由以支持此用例的任何建议吗?
答案 0 :(得分:2)
使用资源宏:
Rails.application.routes.draw do
resources :posts, except: [:new, :create]
resources :organizations, path: '/', only: [] do
resources :posts, module: :organizations, only: [:new, :index, :create]
end
end
$ rails routes:
Prefix Verb URI Pattern Controller#Action
posts GET /posts(.:format) posts#index
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
organization_posts GET /:organization_id/posts(.:format) organizations/posts#index
POST /:organization_id/posts(.:format) organizations/posts#create
new_organization_post GET /:organization_id/posts/new(.:format) organizations/posts#new
通过使用module:
选项,您可以为嵌套上下文设置单独的控制器:
# app/controllers/organizations/posts_controller.rb
class Organizations::PostsController < ApplicationController
before_action :set_organization!
# Index for posts belonging to a specific organization
# GET /:organization_id/posts
def index
@posts = @organization.posts
end
# GET /:organization_id/posts/new
def new
@post = @organization.posts.new
end
# POST /:organization_id/posts
def create
@post = Post.new(post_params)
if @post.save
redirect_to @post, notice: 'Post was successfully created.'
else
render :new
end
end
private
def set_organization!
@organization = Organization.includes(:posts)
.find_by!(name: params[:organization_id])
end
def post_params
params.require(:post).permit(:title)
end
end
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# Index for posts belonging to all organizations
# GET /posts
def index
@posts = Post.all
end
# GET /posts/1
def show
end
# GET /posts/1/edit
def edit
end
# PATCH/PUT /posts/1
def update
if @post.update(post_params)
redirect_to @post, notice: 'Post was successfully updated.'
else
render :edit
end
end
# DELETE /posts/1
def destroy
@post.destroy
redirect_to posts_url, notice: 'Post was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
@post = Post.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def post_params
params.require(:post).permit(:title)
end
end
但是在创建以动态段开头的路由时应该注意 - 路由按照定义的顺序具有优先级,以动态段开头的路由将是“贪婪”并且如果它们不是,则吞下其他路由首先定义。