2010-12-19 29 views
2

我有一个模型(比如说Car),其中一个方法需要访问current_user来确定是否允许用户执行该方法所做的事情。何处放置需要知道current_user的业务逻辑? (Rails)

例如,方法可能需要做这些事情:

  1. 检查CURRENT_USER拥有此对象
  2. 检查对象状态== 1(主动)
  3. 检查相关对象存在和它的X字段不为空

我需要这个业务逻辑是在模型不是在CON troller,所以它的一个地方我的业务逻辑将是。该方法可能会从控制器以外的地方调用。

我知道有像康康,declarative_authorization等宝石,但他们似乎是我需要做的矫枉过正。而且,访问模型中的current_user不被认为是“正确的方式”。

然后,我该如何在模型中进行检查,但仍感觉“干净”?

回答

1

我遇到了“current_user”需要与模型紧密连接的情况,但我在Controller中处理了所有这些情况,并且工作得很好。以下是一些示例:

我的模型是“照片”。照片由用户所有,人们如何与照片互动显然与他们是否拥有照片密切相关。

在演出动作我需要或者现有分级用户给予加载到照片(这样他们就可以对其进行编辑),或让他们创造一个新的:

def show 
    @photo = Photo.find(params[:id]) 
    if user_signed_in?  
    if @rating = current_user.ratings.find_by_photo_id(params[:id]) 
     @rating 
     @current_user_rating = @rating.value 
    else 
     @rating = current_user.ratings.new 
     @current_user_rating = "n/a" 
    end 
    end 
end 

当人们创建照片我希望它们被自动分配给当前用户。

def new 
    @photo = Photo.new 
end 

def create 
    @photo = current_user.photos.create(params[:photo]) 
    if @photo.save 
    redirect_to user_path(current_user), :notice => t('photo.notice.created') 
    else 
    render 'new' 
    end 
end 

只有照片的拥有者可以改变他们:

def edit 
    @photo = Photo.find(params[:id]) 
    if @photo.user == current_user 
    render 'edit' 
    else 
    redirect_to user_path(current_user), :alert => t('application.error.unauthorized') 
    end 
end 

def update 
    @photo = current_user.photos.find_by_id(params[:id]) 
    @photo.update_attributes(params[:photo]) 
    if @photo.save 
    redirect_to user_path(current_user), :notice => t('photo.notice.updated') 
    else 
    render 'edit' 
    end 
end 

这种方法是基于一种“CURRENT_USER”的对象是联系在一起的会议,其中只有控制器知道的约束。所以,总之,我还没有找到一种将“current_user”集成到模型中的好方法,但我已经能够找到(我认为)非常干净的方法来将模型和控制器结合在一起,以便提供由控制器。

对于大多数问题来说,一个相当简单的解决方案,如果你的控制器开始变得混乱,将需要一大块逻辑并定义为模型中的一个方法,但需要一个参数=一个用户对象。然后,您可以从控制器向该方法提供“current_user”,然后模型处理其余部分。

祝你好运!另外,如果其他人有更好的想法,我很乐意听到他们!

+0

感谢您的回答,非常感谢。你的代码很可能会起作用,但把它放在控制器中似乎是错误的(我只看到了这一点)。我正在考虑将我的所有业务逻辑放入单个模块/类中,然后将其与需要它的模型混合。这样,我知道所有的逻辑都在一个地方(很棒),并且我不会混淆模型或控制器。你对此有何看法? – Zabba 2010-12-21 18:25:06

+0

没有理由*不*将您的所有逻辑分组在一个地方。只要你对结果感到满意,代码就能按预期工作,并且不让你想知道“代码再次在哪里?”,那么你的状态良好。然而...(请参阅下一个评论,由于字符限制) – Andrew 2010-12-21 18:41:07

+0

我使用Rails工作的越多,就越能适应Web应用程序的MVC模式中存在的那种“流”。对我而言,我希望大多数逻辑与数据库中的数据相关,因此它属于模型。处理会话和HTTP请求以从模型中获取内容的逻辑在控制器中是正确的,并且一些表示逻辑在视图中是有意义的。诀窍是,在这些边缘情况下,诸如“current_user”之类的东西看起来像是数据,但实际上并非如此,它完全与HTTP请求相关。 (下一条评论) – Andrew 2010-12-21 18:45:26

0

在控制器中处理认证。

示例:将身份验证逻辑放在父ApplicationController中。

class ApplicationController < ActionController::Base 
protect_from_forgery 

    protected 
    # Returns the currently logged in user or nil if there isn't one 
    def current_user 
     return unless session[:user_id] 
     @current_user ||= User.find_by_id(session[:user_id]) 
    end 

    # Make current_user available in templates as a helper 
    helper_method :current_user 

    # Filter method to enforce a login requirement 
    # Apply as a before_filter on any controller you want to protect 
    def authenticate 
     logged_in? ? true : access_denied 
    end 

    # Predicate method to test for a logged in user  
    def logged_in? 
     current_user.is_a? User 
    end 

    # Make logged_in? available in templates as a helper 
    helper_method :logged_in? 

    def access_denied 
     redirect_to login_path, :notice => "Please log in to continue" and return false 
    end 
end 

现在CURRENT_USER是一个访问到登录的用户,你可以在任何控制器访问它,你可以做你的授权逻辑在适当的控制器,你做的任何模型前。

你的权利,虽然。模型不关心授权或访问他们的人。

+0

这不是我所需要的 - 我的模型的业务逻辑需要在模型和业务逻辑中,我需要访问current_user。 – Zabba 2010-12-19 13:10:39

+0

你能否给我一个你想要在你的模型中做什么的例子?一般来说,模型不应该知道当前的请求,因为这项工作是在控制器中完成的。但有时你真的无法帮助它。 – danneu 2010-12-19 14:05:38

+0

感谢您的时间..我已经更新了我需要做什么样的业务逻辑的问题。 – Zabba 2010-12-19 16:35:27