我全力支持瘦控制器和胖模型,而且我认为auth不应违反这一原则。
我已经使用Rails编码一年了,我来自PHP社区。对我来说,将当前用户设置为“请求长全局”是不重要的解决方案。在某些框架中,默认情况下会这样做,例如:
在Yii中,您可以通过调用Yii :: $ app-> user-> identity访问当前用户。参见http://www.yiiframework.com/doc-2.0/guide-rest-authentication.html
在Lavavel中,您也可以通过调用Auth :: user()来执行相同的操作。参见http://laravel.com/docs/4.2/security
为什么我只能从控制器传递当前用户?
假设我们正在创建一个具有多用户支持的简单博客应用程序。我们正在创建公共站点(匿名用户可以阅读博客文章并在博客上发表评论)和管理站点(用户已登录,并且可以对其数据库上的内容进行CRUD访问)。
这是“标准AR”:
class Post < ActiveRecord::Base
has_many :comments
belongs_to :author, class_name: 'User', primary_key: author_id
end
class User < ActiveRecord::Base
has_many: :posts
end
class Comment < ActiveRecord::Base
belongs_to :post
end
现在,在公共站点上:
class PostsController < ActionController::Base
def index
@posts = Post.includes(:comments).latest(10)
end
end
那很干净很简单。但是,在管理站点上,还需要更多。这是所有管理控制器的基本实现:
class Admin::BaseController < ActionController::Base
before_action: :auth, :set_current_user
after_action: :unset_current_user
private
def auth
@user = login_or_redirect
end
def set_current_user
User.current = @user
end
def unset_current_user
User.current = nil
end
end
因此,添加了登录功能,并且当前用户被保存到全局用户。现在,用户模型如下所示:
class Admin::User < User
def self.current=(user)
Thread.current[:current_user] = user
end
def self.current
Thread.current[:current_user]
end
end
User.current现在是线程安全的
让我们扩展其他模型以利用此优势:
class Admin::Post < Post
before_save: :assign_author
def default_scope
where(author: User.current)
end
def assign_author
self.author = User.current
end
end
帖子模型得到了扩展,因此感觉好像只有当前登录的用户帖子。多么酷啊!
管理员发布后控制器可能看起来像这样:
class Admin::PostsController < Admin::BaseController
def index
@posts = Post.all
end
def new
@post = Post.find_by_id(params[:id])
@post.attributes = params.require(:post).permit()
if @post.save
else
end
end
end
对于Comment模型,管理员版本可能如下所示:
class Admin::Comment < Comment
validate: :check_posts_author
private
def check_posts_author
unless post.author == User.current
errors.add(:blog, 'Blog must be yours!')
end
end
end
恕我直言:这是一种功能强大且安全的方法,可确保用户一次即可访问/修改其数据。考虑一下,如果每个查询都需要以“ current_user.posts.whatever_method(...)”开头,那么开发人员需要编写多少测试代码?很多。
如果我错了,请纠正我,但我认为:
这完全是关注点分离。即使很明显只有控制器可以处理身份验证检查,也绝不能将当前登录的用户留在控制器层。
唯一要记住的是:不要过度使用它!请记住,可能有些电子邮件工作者没有使用User.current,或者您可能是从控制台等访问应用程序的。