Rails与组织/用户相同的顶级URL路由:domain.com/user和domain.com/organization的工作方式相同

时间:2015-11-20 22:53:20

标签: ruby-on-rails ember.js

我正在努力使顶级路由以这种方式从我的Rails API工作到Ember.js客户端(例如,类似于GitHub的工作方式):

点击www.example.com/username会给你一个用户的页面。这可能会点击api.example.com/users/:username端点或其他某个端点。

点击www.example.com/organization_name会给你一个组织的页面。这可能会点击api.example.com/organizations/:organization_name端点或其他某个端点。

获取随机网址时,客户端显然不知道它正在处理哪种类型的模型。它只会将其视为www.example.com/random_string,其中random_string可以是usernameorganization_name

我不太确定如何处理这种情况。目前还不清楚客户端或服务器的责任在哪里。我可以想象也许某种多态性在这里工作,但不能连接点。

修改

看起来这似乎可以在Rails端通过为/:slug设置一个包罗万象的路由,然后使用slug首先查询User,然后查询{{ 1}}。

更重要的问题是,通过使用现有的控制器操作进行渲染,还是让HTTP通过重定向处理它来处理这些请求是否有意义。 Organization会很好地处理HTTP重定向吗?在另一种情况下,它是否能够在此端点上正确切换类型?

3 个答案:

答案 0 :(得分:3)

  

看起来这似乎可以在Rails端通过为/:slug设置一个catch-all路由,然后使用slug首先查询User,然后查询一个Organization。

这是唯一可行的方法。您需要在 config / routes.rb 文件的最后添加此catch-all路由。我建议您将此路由与控制器中的代理方法相关联,该方法将确定UserOrganization记录是否与slug相对应。

UserOrganization具有相同的slug时,您必须考虑应用操作(有些会优先考虑其中一个,有些会给访客提供2个选择);以及当没有记录对应slug时要采取的行动(有些会显示404,有些会路由到列表页面)。这些选择将帮助您确定代理方法的更好设计。

这里主要的是设计这个代理方法。

1- HTTP重定向

您的代理方法会将redirect_to回复给 / users /:slug / organizations /:slug ,具体取决于& #39;来自slug

  • 优势:编写和维护简单快捷。
  • 缺点:由于HTTP重定向导致应用程序响应缓慢,以及在第二次请求期间需要重新访问数据库。

2- Ajax响应

与HTTP重定向类似,但在AJAX中完成。您的代理方法会显示一个包含JavaScript代码的页面,该代码可以获取 / users /:slug / organizations /:slug 的内容并显示它通过AJAX。

此外,可以使用history.pushState

通过JavaScript更改网址
  • 优势:比上面快一点
  • 缺点:但更难编写,需要JavaScript代码和js视图,并且在第二次请求期间仍需要重新访问数据库

3-服务器端代理

您的代理方法将执行与您的端点方法相同的代码。这意味着如果发现slugUser记录相对应,代理方法将与UserController#show相同。 (同样适用于Organization

这意味着代理方法必须调用UserController#show所有的前/后过滤器,并呈现相同的视图。

如果你选择这个DRY解决方案,请非常谨慎。或者您可能最终难以维护您的应用程序。

没有一种方法可以做到这一点,这完全取决于您的应用程序架构。例如,如果您的show方法只是获取记录并呈现视图,并且没有控制器帮助方法,那么它的简单和安全。另一方面,如果你有过滤器和控制器助手方法比它变得有点棘手。在这种情况下,您可能需要依赖控制器问题。

  • 优势:最快的解决方案
  • 缺点:编写起来可能非常复杂,并且根据您将来代码库的演变,您最终可能会处于锁定状态,您将不得不放弃此设计。

答案 1 :(得分:3)

创建模型

为路径创建新模型,它将属于用户或组织。给它一个唯一的字符串,让它决定它属于谁:

在模型上:

has_one :route_name
before_create :create_route

def create_route
    self.create_route_name(path: self.path) #change this to what ever the user wants
end

关于组织和用户:

RouteName.find_by(name: "blah_blah").owner

然后你可以这样做:

eval()

答案 2 :(得分:2)

单表继承

假设我们有一个用户和一个组织,我们可以执行以下操作:

class User < ActiveRecord::Base; end
class Organization < User; end

(您需要用户表上的类型字段,用户和组织将共享)

他们将共享数据库字段,而Organization类将继承用户拥有的所有内容(包括默认范围和验证)。如果您的模型相似,这是非常有用的,因为您可以保持一切干燥(您不必定义任何额外的东西)。

Organization.create(name: "thisisanorganization") #=> true (assume that name is unique)
User.create(name: "penne12") #=> true (assume that name is unique)
User.find_by(name: "thisisanorganization") #=> Organization
User.find_by(name: "penne12") #=> User
Organization.find_by(name: "thisisanorganization") #=> Organization
Organization.find_by(name: "penne12")

您可能还会发现为用户和组织创建父类很有用,因此用户可以使用独特的方法和方法。来自组织的验证(组织不需要密码,组织属于许多所有者(类:用户),组织必须有项目,用户有电子邮件等)

Docs