如何在 Rails 中定义包含动态组织名称的路由
How to define routes that include a dynamic organization name in Rails
我正在构建一个 Rails 5.2 SaaS 应用程序,它允许用户属于许多 "organizations"。用户将只能看到他们当前活跃的组织的内容。
我开始使用子域,但经过更多研究后 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' %>
关于如何配置路由以支持此用例的任何建议?
使用资源宏:
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
但是,在创建以动态段开头的路由时应注意 - 路由按其定义的顺序具有优先级,以动态段开头的路由将 "greedy" 并吞并其他路由如果没有先定义它们。
我正在构建一个 Rails 5.2 SaaS 应用程序,它允许用户属于许多 "organizations"。用户将只能看到他们当前活跃的组织的内容。
我开始使用子域,但经过更多研究后 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' %>
关于如何配置路由以支持此用例的任何建议?
使用资源宏:
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
但是,在创建以动态段开头的路由时应注意 - 路由按其定义的顺序具有优先级,以动态段开头的路由将 "greedy" 并吞并其他路由如果没有先定义它们。