Я прихильник худих моделей контролерів та жирів, і я вважаю, що автор не повинен порушувати цей принцип.
Я кодую 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-доступ до свого вмісту в базі даних).
Ось "стандартні АР":
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
Для моделі коментарів версія адміністратора може виглядати так:
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
IMHO: Це потужний та безпечний спосіб переконатися, що користувачі можуть отримати доступ / змінити лише свої дані за один раз. Подумайте, скільки розробнику потрібно написати тестовий код, якщо кожен запит повинен починатися з "current_user.posts.whatever_method (...)"? Багато.
Виправте мене, якщо я помиляюся, але я думаю:
Вся справа в розділенні проблем. Навіть тоді, коли стає зрозуміло, що лише контролер повинен обробляти перевірки автентичності, ні в якому разі не зареєстрований користувач повинен залишатися на рівні контролера.
Єдине, що слід пам’ятати: НЕ зловживайте цим! Пам'ятайте, що можуть бути працівники електронної пошти, які не використовують User.current, або ви, можливо, отримуєте доступ до програми з консолі тощо ...