четверг, 23 июля 2015 г.

Изучаем Devise 2: Аутентификация по номеру телефна

Это не обязательно должен быть номер телефона, это может быть username или еще что-нибудь. Но в дальнейшем планируется сделать подтверждение по номеру телефона с помощью SMS, по-этому здесь выбран именно номер телефона.

1) Вначале добавим колонку phone_number в таблицу users с помощью миграции:
rails g migration AddPhoneNumberToUsers phone_number:string:uniq:index
rake db:migrate
2) Внесем следующие изменения в модель (класс User):
  • Добавим опцию authentication_keys: [:login] в вызов метода devise:
      devise :database_authenticatable, :registerable,
             :recoverable, :rememberable, :trackable,
             :validatable, :confirmable,
             authentication_keys: [:login]
  • Добавим поле login:
      def login=(login)
        @login = login
      end
    
      def login
        @login || self.phone_number || self.email
      end
    
  • Перегрузим метод отвечающий за поиск модели в базе данных:
      def self.find_for_database_authentication(warden_conditions)
        conditions = warden_conditions.dup
        if login = conditions.delete(:login)
          where(conditions.to_h).where(["lower(phone_number) = :value OR lower(email) = :value", { value: login.downcase }]).first
        else
          where(conditions.to_h).first
        end
      end
3) Добавим следующий код в контроллер ApplicationController:
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected
  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:phone_number, :email, :password, :password_confirmation) }
    devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :phone_number, :email, :password, :remember_me) }
    devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:phone_number, :email, :password, :password_confirmation, :current_password) }
  end
Этот код указыает Devise какие поля формы следует сохранить в моделе. Для понимания этот код был бы аналогичен такому коду в контроллере SessionsController:
def sign_in
  permit_params = params.required(:user).permit(:phone_number,
    :email, :password, :password_confirmation)
  @user.attributes=permit_params
end
5) Далее нужно внести изменения в представления. По-умолчанию представления берутся из gem'а. Приведенная ниже команда генерирует представляения в вашем проекте. Они перегружают представления из gem'а:
rails generate devise:views
В форму регистрации (представление views/devise/registrations/new.html.erb) добавляем поле phone_number. Также вы можете добавить поле phone_number в представление редактирования данных пользователя views/devise/registrations/edit.html.erb. В форме аутентификации(представление views/devise/sessions/new.html.erb) заменяем поле email на поле login.

6) Не уверен обязательно ли это, но в config/initializers/devise.rb нужно желательно указать:
config.authentication_keys = [ :login ]
7) Перезапускаем сервер, пробуем.

воскресенье, 19 июля 2015 г.

Ruby on Rails: Настройка отправки сообщений через GMail

В конфигурационном файле config/environments/development.rb прописать следующие настройки:
  config.action_mailer.delivery_method :smtp
  config.action_mailer.smtp_settings = {
    openssl_verify_mode: 'none',
    tls: false,
    enable_starttls_auto: true,
    address: 'smtp.gmail.com',
    domain: 'gmail.com',
    port: 587,
    authentication: 'login',
    user_name: 'login@gmail.com',
    password: 'password'
  }
Перезапустить сервер. Если при попытке отправить сообщение возникнет ошибка:
Net::SMTPAuthenticationError in Devise::RegistrationsController#create
534-5.7.14 <https://accounts.google.com/ContinueSignIn?sarp=1&scc=1&plt=...
def check_auth_response(res)
  unless res.success?
    raise SMTPAuthenticationError, res.message
  end
end
то необходимо изменить натройки безопасности аккаунта гугл. Как, написано здесь.

HTML: Перенос длинных слов

Оригинальный текст можно прочесть здесь.
Я нагуглил следующие способы решения проблемы с длинными словами, которые ломают верстку:
1) http://slopjong.de/2013/06/18/how-to-word-wrap-text-in-html/
div { 
    white-space: pre-wrap;      /* CSS3 */
    white-space: -moz-pre-wrap; /* Firefox */
    white-space: -pre-wrap;
    word-wrap: break-word; 
}
2) Использовать специальные символы для разделения длинных слов на более короткие. Вот эти символы: &shy; &#8203; <wbr>
Пример спользования в Ruby on Rails https://gist.github.com/fiftin/004b70ac0fc0a72738f8.
Каждый из этих сиволов имеет свои недостатки:
  • &#8203;  - представляют собой невидимый пробел который разделяет слово на отдельные слова. По-этому при двойном щелчке мыши по слову, выделяется не полностью слово, а только его часть
  • &shy; &#8203; - копируются вместе с тектом хоть и невидимы для пользователя. Проблема может возникнуть, если пользовтель пытается использовать скопированный текст (содержащий один из этих символов) для поиска.
  • <wbr> - не имеет описанных выше недостатков, но он не поддерживается Internet Explorer'ом.
3) Если ширина div'ки с тектом фиксирована, то достаточно использовать для нее такой стиль:
div {
    width: 100px;
    word-wrap: break-word;
}

среда, 15 июля 2015 г.

Изучаем Devise 1: Настройка подтверждения

Установка Devise описана здесь и здесь.

После установки мы хотим добавить подтверждение учетной записи по email. Для этого служит модуль confirmable.

Настройка подтверждения

 Devise сгенерировал нам такой класс модели:
class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
 
end
В ней перечислены задействованные модули, confirmable среди них нет. Добавляем:
class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :confirmable
end
Теперь нужно добавил необходимые поля в таблицу users. Для этого создадим миграцию:
rails g migration add_confirmable_to_users
 Пишем код миграции:
class AddConfirmableToUsers < ActiveRecord::Migration
  def change
    add_column :users, :confirmation_token, :string
    add_column :users, :confirmed_at, :datetime
    add_column :users, :confirmation_sent_at, :datetime
    # add_column :users, :unconfirmed_email, :string # Only if using reconfirmable
    add_index :users, :confirmation_token, unique: true
    # User.reset_column_information # Need for some types of updates, but not for update_all.
    # To avoid a short time window between running the migration and updating all existing
    # users as confirmed, do the following
  end

  def down
    remove_columns :users, :confirmation_token, :confirmed_at, :confirmation_sent_at
    # remove_columns :users, :unconfirmed_email # Only if using reconfirmable
  end

end
Применяем миграцию:
rake db:migrate
Также нам нужно добавить миграцию для добавления поля unconfirmed_email:
class AddUnconfirmedEmailToUsers < ActiveRecord::Migration
  def change
    add_column :users, :unconfirmed_email, :string
  end
end

Всё. Ссылка на исходники примера.