ハイパーニートプログラマーへの道

頑張ったり頑張らなかったり

【Ruby on Rails】sorceryを使用したログインで、ユーザーネーム・emailのどちらでもログインできるようにする

Deviseでの方法はいくらでもあるのですけど、sorceryについてはなかなか見つからなかったもので。


Rails version 4.2.5
Ruby version 2.3.0-p0 (x86_64-linux)
sorcery (0.9.1)


前提:公式のこちらのチュートリアルに沿って、emailでのログインは可能になっていること。つまり途中から導入する場合ということになります。

マイグレーションファイルの編集

db/migrate/****_sorcery_core.rbにて

class SorceryCore < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email,            :null => false
      t.string :username,         :null => false # これを追加
      t.string :crypted_password
      t.string :salt

      t.timestamps
    end

    add_index :users, :email, unique: true
    add_index :users, :username, unique: true # これを追加
  end
end

emailの他に、今回はusernameというカラムを作ります。

そして、rake db:migrate:resetを行いました。もうすでにDBにユーザーを作っていたのですが、それにはusernameを設定していなかったので、リセットを行うことにしました。

設定ファイルの編集

config/initializers/sorcery.rbにて

  # --- user config ---
  config.user_config do |user|
    # -- core --
    # specify username attributes, for example: [:username, :email].
    # Default: `[:email]`
    #
    user.username_attribute_names = [:username, :email]

user.username_attribute_names:emailだけでなく、:usernameも追加します。

Strong Parametersへの追加

app/controllers/users_controller.rb

    def user_params
      params.require(:user).permit(:username, :email, :password, :password_confirmation)
    end

User modelにバリデーション追加

app/models/user.rb

  validates :email, :username, presence: true
.
.
  validates :username, uniqueness: true

:usernamepresence: trueuniqueness: trueのバリデーションをかけます。

ログインフォームの編集

ユーザーネーム用・email用のフォームを一つにまとめたい。
どうすればいいのかなあ、と思って試行錯誤したのですが、以下の方法にしました。

app/views/user_sessions/_form.html.erb
ログイン画面にてemail用のフィールドの代わりに、下記のコードに置き換えます。

  <div class="field">
    <%= label_tag :login %><br />
    <%= text_field_tag :login, nil, placeholder: 'username or email' %>
  </div>

params[:login]というのをコントローラーに渡すようにしておきます。ここにユーザーネーム、emailのどちらかが入ることになります。

f:id:noriyo_tcp:20160330204659p:plain

セッション用コントローラーの編集

app/controllers/user_sessions_contoller.rb

  def create
    # params[:login] is username or email
    if @user = login(params[:login], params[:password], params[:remember_me])
      redirect_back_or_to(:users, notice: 'Login successfully')
    else
      flash.now[:alert] = 'Login failed'
      render :new
    end
  end

デフォルトではloginメソッドの第1引数にparams[:email]を渡していましたが、ここではparams[:login]を渡します。

Processing by UserSessionsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"****", "login"=>"user1", "password"=>"[FILTERED]", "commit"=>"Login", "remember_me"=>"on"}
  User Load (1.9ms)  SELECT  "users".* FROM "users" WHERE ("users"."username" = 'user1' OR "users"."email" = 'user1')  ORDER BY "users"."id" ASC LIMIT 1

フィールドにuser1というユーザーネームでログインしたところをconsoleで見てみます。
usersテーブルのusernameemailのどちらかにuser1があるかどうか、検索してくれていますね。

Processing by UserSessionsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"****", "login"=>"test@example.com", "password"=>"[FILTERED]", "commit"=>"Login", "remember_me"=>"on"}
  User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE ("users"."username" = 'test@example.com' OR "users"."email" = 'test@example.com')  ORDER BY "users"."id" ASC LIMIT 1

今度はtest@example.comでログインしたところ。こちらでもOR検索してくれています。

その他

  • ユーザーネームも必須にしたので、ユーザー登録画面(app/views/users/_form.html.erb)に、username用のフォームを追加する。
  • ユーザーの一覧・詳細画面にもユーザーネームを表示する

ということをしました。


参考

github.com

dev.classmethod.jp

こちらの記事では、emailからユーザーネームでのログインに置き換える、ということをしています。


(追記)

うーん、記事を投稿してすぐに気がついたのですけど、もしユーザーネームのほうにふざけてuser@example.comなどと、emailと同じ形式で登録してしまうと、他のユーザーのemailとかぶってしまうことが無きにしもあらず、のような気がしました。
ユーザーネームには@, . (+も?)などは使えないようにバリデーションをかける必要があるかもです。

(さらに追記)

こう・・・かな?

app/models/user.rb

validates :username, format: { with: /\A\w+\z/ }

単語、数字、アンダースコアだけに制限すると。

【Ruby on Rails】Cloud9 + Heroku + SendGridで本番環境からメールを飛ばす

現在Udemyでこのような講座をやっていまして

www.udemy.com

開発環境はCloud9、デプロイ先はHerokuでのお話です。

Herokuでの準備

Heroku>Dashboard>左ペインManage Account>Billingでクレカ情報登録をしておきます。

f:id:noriyo_tcp:20160229222234p:plain

Cloud9のコンソールにてheroku addons:create sendgrid:starter

Herokuのダッシュボードよりアプリのページを見ると

f:id:noriyo_tcp:20160229222217p:plain

Sendgridが連携されているのがわかります。ここをクリックすると、SendGridのページへ飛びます。

「なんか問題あったらメール送るから!メルアド教えてくれ!」みたいなポップアップがでますが、もうすでにapp********@heroku.comというメルアドがフォームには入っています。とにかくボタンを押してみましたが、だめだw もう一回Gmailで登録し直しました。

SendGridでの設定

左のSettings>Credentials>New Credentialsからusername, passwordの設定。mailにチェックを入れます。

f:id:noriyo_tcp:20160229222552p:plainf:id:noriyo_tcp:20160229222555p:plainf:id:noriyo_tcp:20160229222556p:plain

Heroku用の環境変数設定

Cloud9のコンソールにて、
heroku config:set SENDGRID_USERNAME=yourusername

heroku config:set SENDGRID_PASSWORD=youruserpassword

先ほどSendGridで登録したユーザーネームとパスワードを設定します。

開発環境の環境変数設定

チュートリアルでは.zshrcに記述しているようですが、dotenv(dotenv-rails)を使います。

github.com


公式を見るとGemfileのトップに記述するようですが、まあrubyのすぐ後にしました。

source 'https://rubygems.org'
ruby "2.2.4"
gem 'dotenv-rails', :groups => [:development, :test]

bundle installしたあとは忘れずに.gitignore.envを追加。そしてプロジェクトのルートにて.envファイルを作成し、

SENDGRID_USERNAME=yourusername
SENDGRID_PASSWORD=yourpassword

と記述しておきます。

ActionMailer設定

config/environment.rb

ActionMailer::Base.smtp_settings = {
  :address        => 'smtp.sendgrid.net',
  :port           => '587',
  :authentication => :plain,
  :user_name      => ENV['SENDGRID_USERNAME'],
  :password       => ENV['SENDGRID_PASSWORD'],
  :domain         => 'heroku.com',
  :enable_starttls_auto => true
}

ruby on rails - Sendgrid via Devise: Attempt to send authentication email leads to OpenTimeout error when using Cloud 9 dev environment - Stack Overflow

ここの答えを見るとCloud9はport587をブロックするようだから、2525とか別のポートにしたほうがいいぜ!みたいなことが書いてありましたが、その通りにすると今度は本番環境にてうまくいかなくなりましたので、おとなしく587を指定しました。

config/environments/development.rb

config.action_mailer.delivery_method = :development
config.action_mailer.default_url_options = { host: 'yourappname.c9users.io/', port: $PORT, protocol: 'https' }

チュートリアルのコメント欄には下記のように

config.action_mailer.delivery_method = :development
config.action_mailer.default_url_options = { host: '$IP', port: $PORT }

host: $IPかもしくはhost: '$IP'にしろ、みたいなことが書いてありましたが、真っ赤な嘘やで

config/environments/production.rb

config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { :host => 'yourherokuappname.herokuapp.com', :protocol => 'https'}

git origin heroku masterでHerokuへプッシュしたのち、ユーザー登録画面(Deviseを使用しています)から、自分のEmailを登録してみると、メールが届きます(結構時間かかる?それでも数分くらいだったような気も)


おまけ:letter_opener_webを使用して開発環境でのメールの確認

github.com

Gemfile

gem 'letter_opener_web', '~> 1.2.0', :group => :development
# 私は何もオプション無しで``group :development``内にgem 'letter_opener_web'としました・・・
bundle install # or bundle install --without production

routes.rb

Your::Application.routes.draw do
.
.
  if Rails.env.development?
    mount LetterOpenerWeb::Engine, at: "/letter_opener"
  end
.
.
end

config/environments/development.rb

  config.action_mailer.delivery_method = :letter_opener
  config.action_mailer.default_url_options = { host: 'yourappname.c9users.io/', port: $PORT, protocol: 'https' }

ユーザー登録後、
https://yourappname.c9users.io/letter_openerにアクセスすると、認証メールが確認できます。

Day One(Classic)からDay One2へ記事をインポートしてみた

Day One2がセール中だったので購入しました。

Day One 2 Journal + Notes

Day One 2 Journal + Notes

  • Bloom Built, LLC
  • ライフスタイル
  • ¥2,400

記事執筆時点ではまだ半額ですが、そもそも4,800円とか高えよ・・・。

インポートする

まず起動します(当たり前か)

f:id:noriyo_tcp:20160210164507p:plain

右が新しいDay One2。

イメージ画面?みたいのが出てきますが、ポチポチとContinueを押していくと、この画面になります。

f:id:noriyo_tcp:20160210164637p:plain

「リマインダー作ろうぜ!」みたいなこと言われていますが、Classicのほうでも全然使っていなかったので、Continueを押して進みます。

f:id:noriyo_tcp:20160210164752p:plain

「インポートするかい?」と出るので、当然Importを押します。

確認のダイアログが出ます。インポートされた記事はClassicのほうから削除されてしまうわけではないと。

f:id:noriyo_tcp:20160210164938p:plain

これもImportを押します。するとインポートが始まり・・・

f:id:noriyo_tcp:20160210165017p:plain

インポート終了のダイアログが出ますので、OKを押します。これでインポート終了。簡単でした。

設定をする

f:id:noriyo_tcp:20160210165144p:plain

メニューバー>Viewです。タイムラインは⌘+1、カレンダーは⌘+4と。とりあえずこれだけは覚えておきます。

f:id:noriyo_tcp:20160210165327p:plain

設定画面です。メニューバーに表示させたいので、Show Menu Bar Entryを選択。そのGlobal Menu Barを使うためのショートカットはデフォルトでCtrl + Shift + Dです。
なんかリマインダーも使えるようにしないといけないらしいですな。

なので、Remindersタブにて、Enable Remindersを選択。

f:id:noriyo_tcp:20160210165626p:plain

これでメニューバーにアイコンが表示されます。

f:id:noriyo_tcp:20160210165732p:plain

ここをクリックするか、先ほどのショートカットを使用すると

f:id:noriyo_tcp:20160210165814p:plain

このように出てきて書き込めると。

Sublime Text2からSublime Text 3へ、なるべく設定をそのままで移行する

いい加減2から3へ移行しようかと。

環境:Mac OS X Yosemite(10.10.5)

  • Sublime Text3のダウンロード
  • ライセンスの設定
  • パッケージコントロールのインストール
  • 引き続き使用できるパッケージの確認
  • パッケージのインストール
  • SublimeMozcInputのインストール
  • User SettingsとKey Bindingsの移行
  • パッケージのUser Settings
  • subl helperの設定
  • その他参考リンク
続きを読む