免责声明:我真的花时间考虑模型和变量的名称。如果你也这样做,这个问题适合你。
我有一个Rails项目,其中包含两个模型:User
和Project
。
它们由模型ProjectsUser
连接,模型是多对多关系中的连接模型。此模型还包含给定项目中用户的role
以及tier
和departments
等其他属性。所以这是has_many :through
关系。
鉴于这种情况,自从我开始开发项目以来,这里一直困扰着我所有的铁路项目:
我应该使用ProjectsUserController
还是更好地在UserController
和ProjectController
上添加相关操作?在某些时候,我想将用户分配给项目,甚至更改给定项目中用户的角色。将这些操作留在连接控制器上或使用模型控制器是更好的做法吗?
我应该编写一个方法来获取给定项目的用户角色吗?这基本上是我应该有一个方法User#role_for(project)
。由于这种方法基本上是从projects_user
对象获取信息,因此总是让代码明确表达更有意义,因为大多数时候我会有project
和{{1 },但不是user
。这个思路是否正确,或者问题是我的代码应该比我的代码更多projects_user
?对此有什么好的警告吗?
如果不明显,我是否应该尝试将我的表重命名为非标准名称?好的,如果我有模型project_user
和{{ 1}}我应该使用User
,但事实上,根据我的经验,在现实生活中案例中命名这些模型通常更难。如果名称最终不那么明显(例如,在我的情况下,可能{@ 1}} @wonderingtomato建议)是最好的,或者在这种情况下最好回到NewsSite
接近?
一个额外的cookie,用于指向漂亮的开源Rails代码,或者通过可能有助于我的问题的书籍指示。
答案 0 :(得分:4)
我会使用特定的控制器。即使现在交互听起来很简单,您也不知道将来是否需要添加更多高级功能 我一直在几个项目中处理这种关系,并且使用连接模型的控制器总是得到回报。
您可以通过这种方式构建它,例如:
index
应该期望params[:project_id]
,以便您只能显示特定项目的用户索引。create
是您添加新用户的位置,也就是您创建新联接模型的位置。update
用于修改现有连接模型的值,例如,当您想要更新项目中用户的角色时。destroy
是您从项目中删除用户的位置,也就是删除相应联接模型的位置。show
视图中的所有内容,则可能不需要edit
和index
操作。另外,我建议选择一个不同的名字。 Rails在很大程度上依赖于命名约定,而projects_users
是您将与has_and_belongs_to_many
关联一起使用的 join_table 的默认名称。从理论上讲,你可以将它用于一个独立的模型(和has_many through:
),但它不会立即清楚,你可能会破坏某些东西。瘾,这将使任何可能在未来加入该项目的新程序员(个人经历)感到困惑。
如何调用模型project_participation
?
如果您还没有构建很多功能,并且还没有生产该表,那么现在更改它将为您节省很多麻烦。
1)我支持我之前所说的:你的 join model 是一个完整的记录,它保存状态,可以被提取,修改(由用户)并被销毁。
专用控制器是最佳选择。此外,此控制器应处理修改连接模型的所有操作,即更改其属性。
2)您可以定义User#role_for(project)
,只需记住它应该正确处理user
未参与project
的情况。
您还可以使用以下内容明确说明:
@user.project_participations.where(project_id: @project.id).first.try(:role)
# or...
ProjectParticipation.find_by(project_id: @project.id, user_id: @user.id).try(:role)
但是我会说将这个逻辑封装在一个方法中(在两个模型中的一个上)会更好。
3)您已经在为表使用非标准名称。我的意思是它是不同类型关联(has_and_belongs_to_many
)的默认名称,而不是您正在使用的关联(has_many through:
)。
问问自己:支持实际模型的表格是什么?如果是,那个模型代表现实世界中的某些东西,因此应该有一个合适的名称。另一方面,如果表格不支持模型(例如,它是一个连接表),那么您应该组合它所加入的表(模型)的名称。
答案 1 :(得分:1)
在我看来,REST并不总是直接映射到DB记录。这里的概念资源是项目与用户的关联。根据您的持久层,实现会有所不同,但RESTful API将是标准的。
Rails中的配置约定是一个很好的帮手,但它并不一定适用于100%通过堆栈的每一种情况。控制器,模型及其各自的名称之间不需要一对一的映射。特别是在应用程序级别,我希望我的路由/控制器代表API的公共视图,而不是持久性和域层的内部实现细节。
您可能有UserProjectsController
可以执行CRUD以向用户添加/删除项目关联,并且它将执行相应的记录操作,而不会过度绑定到DB实现。请注意命名,路由可能是/user/:id/projects
,因此很明显,您操纵的不是用户或项目,而是他们的关联。
答案 2 :(得分:1)
我认为考虑这种事情(事前和事后)都会导致更好的设计。
我也从模型开始,从结构上考虑应用程序。我的观点的下一步是构建用户界面,使其基于使用户更容易和有用的内容(在更重要的事情上花费更多精力)。因此,如果用户分别编辑ProjectsUser对象是有意义的,那么ProjectsUsersController就是最佳选择。更可能将连接模型对象编辑为项目的一部分(或用户,具体取决于您的应用程序的结构)将更适合用户。在这种情况下,使用嵌套表单并通过控制器(和模型)进行编辑,这是表单引用的主要模型更好。控制器实际上是为UI服务,所以关于它的决定应该取决于UI。
是的,如果它使您的代码更简单或更易读。如果您不止一次使用角色,我怀疑它会。
我实际上会将该模型命名为Member或ProjectMember(或Membership)。它定义了用户和项目之间的关系,因此它的名称应该反映出它是什么关系。在这样的名称过于笨拙或太难定义的情况下,然后回退到像ProjectUser这样的东西是合理的(但不是ProjectsUser)。但我绝对希望在可能的情况下找到一个更有意义的名字。