在哪里放置需要知道current_user的业务逻辑? (导轨)

时间:2010-12-19 12:46:32

标签: ruby-on-rails-3

我有一个模型(比如说Car),其中一个方法需要访问current_user来确定是否允许用户执行该方法所做的事情。

例如,方法可能希望执行以下操作:

  1. 检查current_user是否拥有此对象
  2. 检查对象状态== 1(有效)
  3. 检查相关对象是否存在且X字段不是NULL
  4. 我需要将此业务逻辑放在模型中,不在控制器中,这样它就是一个地方我的业务逻辑将会。可以从控制器以外的位置调用该方法。

    我知道有像cancan,declarative_authorization等宝石,但它们似乎对我需要做的事情有些过分。而且,访问模型中的current_user不被视为“正确的方法”。

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

2 个答案:

答案 0 :(得分:1)

我遇到过“current_user”需要与模型紧密连接的情况,但是我在Controller中处理了它并且它运行良好。以下是一些例子:

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

在show动作中,我需要加载用户为照片添加的现有评级(以便他们可以编辑它)或允许他们创建一个新评级:

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”,模型将处理其余部分。

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

答案 1 :(得分:0)

在控制器中处理身份验证。

示例:将auth逻辑放在父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是登录用户的访问者,您可以在任何控制器中访问它,您可以在对模型执行任何操作之前在适当的控制器中执行授权逻辑。

你的权利。模型不关心授权或访问它们的人。