Rails:向模型添加方法以根据 current_user 执行检查?
我有一个看起来像这样的模型:
class Comment < ActiveRecord::Base
...
#allow editing comment if it is moderated and the user passed-in
#is the one that owns the comment
def can_edit?(user)
moderated? and user.Type == User and user.id == self.user_id
end
...
end
在视图中调用:
<%= link_to 'Show Comment', @comment if @comment.can_show?(current_user) %>
我需要在许多不同的模型中编写许多这样的方法 - 进行验证检查以查看是否允许 current_user 在模型上做某事。
但感觉很麻烦——尤其是需要检查传入的 user
确实是 User
类型的对象。
做这种事情的干净、最佳实践的方法是什么?我走在正确的轨道上吗? (即我应该将此类方法添加到模型或其他地方)
注意
我使用范围查询来获取评论和其他模型,但在某些情况下我无法确定查询范围,因此我必须使用
can_xxxx?
方法
我正在使用限定范围的查询来获取评论和其他模型,但在某些情况下 我现在的做法算是“胖模特”吗?
I have a model that looks something like this:
class Comment < ActiveRecord::Base
...
#allow editing comment if it is moderated and the user passed-in
#is the one that owns the comment
def can_edit?(user)
moderated? and user.Type == User and user.id == self.user_id
end
...
end
And a call in a view:
<%= link_to 'Show Comment', @comment if @comment.can_show?(current_user) %>
I need to write many such methods in many different models - sort of validation checks to see if current_user is allowed to
do something on a model.
But it feels cumbersome - especially the need to check that the passed-in user
is indeed a object of type User
.
What's a clean, best-practice way to do this sort of thing? Am I on the right track? (i.e. should I be adding such methods to a model or somewhere else)
Note
I am using scoped queries to get the comments and other models, but in some cases I cannot scope the query so I have to use the
can_xxxx?
methods
Ps. Is what I'm doing considered a "fat model"?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
创建一个包含所有授权方法的
模块
,并将该模块包含
到所有需要授权的类中。将名为
authorization.rb
的文件添加到app/models
目录。将名为
authorization.rb
的文件添加到config/initializers
目录。现在
Comment
和Post
模型将拥有所有授权方法。其他方法是使用当前的named_scope。
Post
控制器操作我喜欢这种方法,因为它使用相同的逻辑来访问对象数组或单个对象。
您可以将named_scope添加到模块中以避免重复定义:
确保按照前面的建议将模块包含在所需的类中。
Create a
module
containing all the authorization methods andinclude
the module to all the classes requiring authorization.Add a file called
authorization.rb
toapp/models
directory.Add a file called
authorization.rb
toconfig/initializers
directory.Now
Comment
andPost
models will have all the authorization methods.Other approach is to use your current named_scope.
Post
controller actionsI like this approach as it uses the same logic for accessing an array of objects or a single object.
You can add the named_scope to the module to avoid repeated definitions:
Make sure to include the module in required classes as suggested earlier.
我不认为你所做的事情一定是错误的。不过,我看到了三种简化方法:
1)跟踪 self.user 以及 self.user_id。然后您可以说:
注意,这可能会增加数据库查找时间和/或内存占用的开销。
2)使用#is_a?为了检查祖先而不仅仅是类平等:
3)如果传入非用户是错误的,您可能想在发生这种情况时引发错误:
至于问题2,我还没有听说过术语“胖模型”。是否在任何地方特别提到过?
I don't think what you're doing is necessarily wrong. I see three ways to simplify, though:
1) track self.user as well as self.user_id. Then you can say:
Note, this might add overhead either with DB lookup times and/or memory footprint.
2) Use #is_a? in order to check ancestry and not just class equality:
3) If passing in a non-user is wrong, you might want to raise an error when this happens:
As for Q2, I haven't heard the terminology "fat model." Is it referenced anywhere in particular?
回复:胖模型和瘦控制器
这是将逻辑推入模型而不是将其放在控制器(或更糟糕的是视图)中的想法。
一个很大的好处是帮助测试;还将更多逻辑放置在模型中而不是控制器中的重点。请记住,控制器与多个模型一起使用并不罕见。
将逻辑放入模型而不是控制器中通常意味着业务规则被纳入模型中——这正是它们所属的位置。
一个可能的缺点是,控制器可用但模型中不可用的任何信息都需要显式传递到模型的方法中或使用模型的实例变量“设置”。
您需要将当前用户传递到模型的示例说明了这个问题。
但总的来说,我和其他许多人发现,胖模特的效果往往比不胖模特的效果更好。
Re: fat model and skinny controller
This is the idea of pushing logic into the model rather than having it in the controller (or worse, the view).
A big benefit is to help with testing; also the focus of placing more logic in the model rather than in the controller. Remember that it is not uncommon to have controllers work with multiple models.
Putting the logic into a model rather than a controller often means that the business rules are being baked into the model--which is exactly where they belong.
A possible downside is that any information available to the controller that is not available in the model needs to be explicitly passed into the model's methods or "set" using a model's instance variables.
Your example of needing to pass the current user into the model illustrates the issue.
Overall though, I and many others have found that fat models tend to work out better than not.