Где разместить бизнес-логику, которая требует, чтобы current_user был известен? (Rails) - PullRequest
2 голосов
/ 19 декабря 2010

У меня есть модель (скажем, Car), в которой метод нуждается в доступе к current_user, чтобы определить, разрешено ли пользователю выполнять то, что делает метод.

Например, метод может захотеть сделать следующее:

  1. Убедитесь, что current_user принадлежит этому объекту
  2. Проверьте, что статус объекта == 1 (Активен)
  3. Убедитесь, что связанный объект существует и его поле X не равно NULL

Мне нужно, чтобы эта бизнес-логика была в модели , , а не в контроллере , чтобы это было одно место , где будет находиться моя бизнес-логика. Метод может быть вызван из других мест, кроме контроллера.

Я знаю, что есть драгоценные камни, такие как канкан, декларативное_авторизация и т. Д., Но они кажутся излишними для того, что мне нужно сделать. Кроме того, доступ к current_user в модели не считается «правильным способом».

Тогда, как мне сделать эту проверку в модели, но все еще чувствовать себя "чистой"?

Ответы [ 2 ]

1 голос
/ 21 декабря 2010

Я столкнулся с ситуацией, когда «current_user» должен быть тесно связан с моделью, но я обработал все это в контроллере, и он работает довольно хорошо.Вот несколько примеров:

Моя модель "Фотографии".Фотографии принадлежат пользователям, и то, как люди взаимодействуют с фотографиями, очевидно, тесно связано с тем, имеют ли они фотографию или нет.

В действии шоу мне нужно загрузить либо существующий рейтинг, который пользователь дал фотографии(чтобы они могли редактировать его) или позволить им создать новый:

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» в модель, но я смог найти (я думаю) довольно чистые способы связать модель и контроллер так, чтобы это можно было обеспечитьконтроллером.

Одним из довольно простых решений большинства проблем, если ваш контроллер начинает запутываться, было бы взять кусок логики и определить его как метод в модели, но требовать один аргумент = aпользовательский объект.Затем вы можете просто передать «current_user» этому методу с вашего контроллера, а модель обработает все остальное.

Удачи!Кроме того, если у кого-то есть идеи получше, я бы хотел их услышать!

0 голосов
/ 19 декабря 2010

Обработка аутентификации в контроллере.

Пример: помещение логики аутентификации в родительский 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 является средством доступа для вошедшего в систему пользователя, и вы можете получить к нему доступ в любом контроллере, вы можете выполнить логику авторизации в соответствующем контроллере, прежде чем делать что-либо с моделью.

Впрочем, ваше право. Моделям нет дела до авторизации или доступа к ним.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...