И снова руби, после выходных

May 10, 2012

После таких длинных праздников тяжело снова браться за работу, все эти буквы, цифры, кнопки. Однажды, после отпуска, я забыл пароль на рабочий компьютер. В другой раз забыл пин-код на входной двери, причем посреди рабочей недели. На моей первой работе, чтобы попасть в офис, необходимо было ввести пароль из четырех цифр. Рука настолько привыкла к этому действия, что случайно задумавшить, а какой же у нас код, я не смог вспомнить ни одной цифры. Пришлось ждать коллег и потом сдаваться секретарям. Отдых - это тоже серьезный труд. За праздники не появилось ничего новенького из практики, поэтому расскажу про несколько фишек, которые я припас уже давно.

Массив и Хэш

В руби 1.9 ошибка при обращении по сломанному индексу к массиву стала более невнятной:

irb(main):001:0> RUBY_VERSION
=> "1.8.7"
irb(main):002:0> [1, 2, 3][:key]
TypeError: Symbol as array index
irb(main):001:0> RUBY_VERSION
=> "1.9.3"
irb(main):002:0> [1, 2, 3][:key]
TypeError: can't convert Symbol into Integer

Если вы случайно передадите масcив в функцию, которая принимает хэш, то поймаете ошибку TypeError: can't convert Symbol into Integer. Я один раз довольно долго искал проблему, так как вызов метода и работа с аргументом были окружены дополнительным кодом и я грешил на другую конструкцию.

Функция "притвориться"

Во всех сайтах с бэкэндом в модель администратора мы обычно добавляем булевские флажки с правами доступа. Примерно так:

# model
class User < ActiveRecord::Base
  has_fields do
    string :username

    boolean :acl_seo
    boolean :acl_posts
    boolean :acl_orders
    # ...
  end

  # ...
end

# controller
class PostsController < ApplicationController
  layout 'admin'
  before_filter :authenticate_user
  before_filter { raise AccessDenied unless current_user.acl_posts? }
  # ...
end

# view
<% if current_user.acl_posts? %>
  <%= link_to "Posts", posts_path %>
<% end %>

Эта простая и надежная схема верно служит нам уже довольно долго. Мы создаем суперюзеров, чтобы скрыть настройки от клиента, о которых ему не следуют беспокоится. Клиенты часто просят создать аккаунты с ограниченными правами (в душе мы все параноики и к тому же любим ущемить чьи-нибудь интересы :-)). Недавно я придумал добавить ещу одну функцию "притвориться другим пользователем". Теперь суперюзер может выбрать из комбобокса любой аккаунт и залогиниться им. Схематически это реализовано так:

class ApplicationController < ActionController::Base
  # ...
  def owner_user
    @owner_user ||= User.find_by_id(session[:owner_user_id])
  end
end

class AdminController < ApplicationController
  # ...

  def pretend
    user = User.where('id <> ?', current_user.id).find(params[:user_id])
    session[:owner_user_id] = current_user.id
    sign_in user
    redirect_to :back
  end

  def stop_pretend
    if owner_user
      sign_in owner_user
      session[:owner_user_id] = nil
    end
    redirect_to :back
  end
end

Эта маленькая хитрость позволяет решить сразу же 2 проблемы: всегда можно под любым аккаунтом посмотреть не осталось ли чего-нибудь лишнего, и можно зайти под клиентом, который говорит, что у него "все сломалось" и убедиться, что это действительно так.

Всегда запоминать меня

Коллега прислал ссылку на статью Always remember me, о том что пора отказаться от галочки "запомнить меня". В принципе я согласен с этой статьей и сам не долюбливаю эту галочку. Даже если сломался интернет и вы не сможете нажать ссылку "выйти", то всегда можно очистить куки или пользоваться режимом приватного просмотра. В рейлс 3.2 реализовать логин без экспирации очень легко:

cookies.signed.permanent[:user_id] = current_user.id
# Для чтения permanent указывать не обязательно, а signed - обязательно
cookies.signed[:user_id] # => 123

Мы новые проекты делаем без галочки в бэкэнде, проверяем концепцию.

Хорошей рабочей недели!

comments powered by Disqus