Passion make things more better

Rails, Swiftあたりの話題を中心に書いています

RailsでRoutesを分割する

config/routes.rb

class ActionDispatch::Routing::Mapper
  def draw(routes_name)
    instance_eval(File.read(Rails.root.join("config/routes/#{routes_name}.rb")))
  end
end

Rails.application.routes.draw do

  root to: 'pages#home'

  draw :common
  draw :admin

end

config/routes/xxx.rb

Rails.application.routes.draw do
  namespace :admin do
    root to: 'pages#home'
  end
end

これでapp/config/routes以下にファイルを配置していけばOK。

sorceryを使ってEmail + Passwordログインを実装

先日、sorceryを使ってFacebookログインを実装する方法を紹介しましたが、今回はその関連で、Email + Passwordのログインを実装する方法を紹介します。

初期設定

# Gemfile
gem 'sorcery'

# bundle install
~ bundle install --path vendor/bundle

# sorceryの初期ファイルのインストール
~ bundle exec rails g sorcery:install

Migration

# db/migrate/xxxxxxxxxxx_sorcery_core.rb
class SorceryCore < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email, null: false
      t.string :crypted_password
      t.string :salt

      t.timestamps
    end

    add_index :users, :email, unique: true
  end
end

Controller

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  before_action :require_login

  private
  def not_authenticated
    redirect_to sign_in_path, alert: 'ログインが必要です'
  end
end
# app/controllers/users_controller.rb
class UsersController < ApplicationController

  skip_before_action :require_login, only: [:new, :create]

  def dashboard
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      login(params[:user][:email], params[:user][:password])
      redirect_to dashboard_path, notice: 'ユーザー登録が完了しました'
    else
      render :new
    end
  end

  private
  def user_params
    params.require(:user).permit(:email, :password, :password_confirmation)
  end
end
# app/controllers/users/sessions_controller.rb
class Users::SessionsController < ApplicationController

  skip_before_action :require_login, only: [:new, :create]

  def new
    @user = User.new
  end

  def create
    if @user = login(params[:email], params[:password])
      redirect_to dashboard_path, notice: 'ログインしました'
    else
      render :new, alert: 'ログインに失敗しました'
    end
  end

  def destroy
    logout
    redirect_to sign_out_path, notice: 'ログアウトしました'
  end

end
# app/controllers/pages_controller.rb
class PagesController < ApplicationController

  skip_before_action :require_login

  def home
  end

end

View

# app/views/users/new.html.erb
<%= form_for @user, url: { action: 'new' } do |f| %>

  <div class="form-group">
    <%= f.label :email %>
    <%= f.text_field :email, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :password %>
    <%= f.password_field :password, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :password_confirmation %>
    <%= f.password_field :password_confirmation, class: 'form-control' %>
  </div>

  <%= f.submit 'この内容でユーザー登録を行う', class: 'btn btn-primary' %>

<% end %>
# app/views/users/sessions/new.html.erb
<%= form_tag sign_in_path, method: :post do %>
<div class="form-group">
  <%= label_tag :email %>
  <%= text_field_tag :email, nil, class: 'form-control' %>
</div>
<div class="form-group">
  <%= label_tag :password %>
  <%= password_field_tag :password, nil, class: 'form-control' %>
</div>
<div class="actions">
  <%= submit_tag 'ログイン', class: 'btn btn-primary' %>
</div>
<% end %>
# app/views/users/dashboard.html.erb
<h1>dashboard</h1>
# app/views/pages/home.html.erb
<h1>home</h1>

Routing

Rails.application.routes.draw do
  root to: 'pages#home'
  get 'dashboard', to: 'users#dashboard', as: 'dashboard'

  # ユーザー登録関連
  get 'sign_up', to: 'users#new', as: 'sign_up'
  post 'sign_up', to: 'users#create'
  get 'sign_in', to: 'users/sessions#new', as: 'sign_in'
  post 'sign_in', to: 'users/sessions#create'
  post 'sign_out', to: 'users/sessions#destroy', as: 'sign_out'
end

参考

sorceryでFacebookログインを実装する

個人的に最近deviceではなくsorceryを使うことが多くなりました。deviceと比較してsorceryの良い点として、必要な機能だけを使えるという所です。

今回はsorceryを使ってFacebookログインを実装する方法を紹介します。

初期設定

# Gemfile
gem 'sorcery'

# bundle install
~ bundle install --path vendor/bundle

# sorceryの初期ファイルのインストール
~ bundle exec rails g sorcery:install

# Facebookログインを実装するためのファイル等インストール
~ bundle exec rails g sorcery:install external --only-submodules

# Authentication Model作成
~ bundle exec rails g model Authentication --migration=false

設定ファイル

# config/routes.rb
post 'logout', to: 'users/sessions#destroy', as: 'logout'
get 'oauth/callback', to: 'oauth#callback'
get 'oauth/:provider', to: 'oauth#oauth', as: 'auth_at_provider'
# config/initializers/sorcery.rbの該当部分に以下を追記

Rails.application.config.sorcery.configure do |config|

  config.external_providers = [:facebook]

  config.facebook.key = Settings.facebook[:key]
  config.facebook.secret = Settings.facebook[:secret]
  config.facebook.callback_url = Settings.facebook[:callback_url]
  config.facebook.display = "page"
  # 以下3つは取得したい項目と合わせて変更する
  config.facebook.user_info_mapping = { email: "email", name: "name", gender: "gender" }
  config.facebook.user_info_path = "me?fields=email,name,gender"
  config.facebook.access_permissions = ["public_profile", "email"]
  
  
  config.user_config do |user|
    user.authentications_class = Authentication
  end

end

Migration

# db/migrate/xxxxxxxxxxx_sorcery_core.rb
class SorceryCore < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email, null: false
      
      t.timestamps
    end

    add_index :users, :email, unique: true
  end
end
# db/migrate/xxxxxxxxxxx_sorcery_external.rb
class SorceryExternal < ActiveRecord::Migration
  def change
    create_table :authentications do |t|
      t.integer :user_id, null: false
      t.string :provider, null: false
      t.string :uid, null: false

      t.timestamps
    end

    add_index :authentications, [:provider, :uid], unique: true, name: 'ui_authentications_01'
  end
end

Model

# app/model/user.rb
class User < ApplicationRecord
  authenticates_with_sorcery! do |config|
    config.authentications_class = Authentication
  end

  has_many :authentications, dependent: :destroy
  accepts_nested_attributes_for :authentications

  validates :email, presence: true, uniqueness: true
end
# app/model/authentication.rb
class Authentication < ApplicationRecord
  belongs_to :user

  validates :user_id, presence: true
  validates :provider, uniqueness: { scope: :uid }
end

Controller

# app/controllers/app_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  before_action :require_login
  # もしログインを必要としない場合は以下を該当のControllerに記述する
  # skip_before_action :require_login

  private
  def not_authenticated
    redirect_to login_path, alert: "ログインが必要です"
  end
end
# app/controllers/users/sessions_controller.rb
class Users::SessionsController < ApplicationController
  def destroy
    logout
    redirect_to root_path, notice: 'ログアウトしました'
  end
end
# app/controllers/oauth_controller.rb
class OauthController < ApplicationController
  skip_before_action :require_login

  def oauth
    login_at(params[:provider])
  end

  def callback
    provider = params[:provider]
    if @user = login_from(provider)
      redirect_to root_path, notice: 'ログインに成功しました'
    else
      begin
        @user = create_from(provider)
        reset_session
        auto_login(@user)

        redirect_to root_path, notice: 'ログインに成功しました'
      rescue
        redirect_to root_path, alert: 'ログインに失敗しました'
      end
    end
  end

  private
  def auth_params
    params.permit(:code, :provider)
  end
end

View

# ログイン配置したいところに以下のコードを記述
<%= link_to 'Login with Facebook', auth_at_provider_path(provider: :facebook) %>

参考

Sidekiqの導入

前提

  • redisが必要です

初期設定

やることは以下の2つ。

  • Gemfileの編集
  • 設定ファイルの作成

Gemfile

Gemfileにsidekiqを記述 & bundle install。

# Gemfile
gem 'sidekiq'
gem 'redis-namespace'

~ bundle install --path vendor/bundle

設定ファイルの作成

config/initializers/sidekiq.rbを以下の内容で作成。 host, portに関してはconfigで設定し、そこから呼んでいます。

Sidekiq.configure_server do |config|
  config.redis = { url: "redis://#{Settings.redis[:host]}:#{Settings.redis[:port]}", namespace: 'sidekiq' }
end
Sidekiq.configure_client do |config|
  config.redis = { url: "redis://#{Settings.redis[:host]}:#{Settings.redis[:port]}", namespace: 'sidekiq' }
end

Workerの作成

app/workers以下にworker用のファイルを作成します。 以下は例でメールを送信するworkerとして、email_worker.rb作成しています。

class EmailWorker
  include Sidekiq::Worker

  def perform(user_id)
    user = User.find_by(id: user_id)
    # ActionMailerを呼び出す処理なりを書く
  end
end

呼び出し方

上で作ったEmailWorkerを呼び出すには以下のようにします。 これで実行のキューに入ります。

EmailWorker.perform_async(1)

エンジニアがSketchを使い始める時にやったアレコレ

僕がSketchを使うにあたり初めにやったことをまとめました。

基礎知識のインプット

使い方を知らないと元も子もないので、まずは基礎知識のインプットを行いました。 とりあえず以下のリンクを読んで、ざっくりと把握しました。

UIデザインの作成ツール!誰でも分かるSketchの使い方【初心者向け】

これで抑えた点は、ざっくりと以下のような項目になります。

  • とりあえず何か置きたいときは、左上の「Insert」を押せばいいらしい
    • 押すといろいろ出てくるので、見ればわかるかと
  • artboardを使えば、デバイスに応じた画面サイズの枠を作れるらしい
  • 図形の操作(色塗ったりとか)は右側でいろいろやるらしい
    • 項目がそこまで多くないので、結構直感的に使える
    • スライスの設定も右側の下の方でできる
  • マスクは図形を置いて右クリックして「Mask」選択でできる
  • 「File」-> 「New From Template」でよくある系のベーステンプレが現れる
    • コピーして使いたいところに貼り付ける感じで使うのかな
  • ちゃんとショートカットがある
    • これは使い慣れてきたら覚えればいいかくらいに捉えました

プラグイン

「こういうことできないのかなぁ..」と考えていて、あれこれ調べていたら、どうやらプラグインなるものがあるらしい...(そりゃそうだろ)。

プラグインの管理

プラグインの管理どうやるのが良いのだろうか、と探していたらSketch Toolboxを使うのがよくあるパターンらしい。

コマンドでやったほうがいいよ、みたいに書いている人もいましたが、僕はSketch Toolboxを使いました。

使い方は開けばわかると思います笑。installの時はsearchのところに対象のプラグインをいれて、表示された物のinstallボタンを押すだけです。

とりあえず入れたプラグイン4つ

エンジニア視点でとりあえずこんなのあったらなぁ、というのを入れました。

Content Generator for Sketch

仮画像を当てるのに使えるプラグイン

Sketch Measure

フォントサイズとか余白をかき出してくれるプラグイン

Sketch Palettes

配色をパレット化して保存できるプラグイン

Sketch Use FontAwesome

エンジニアなら使ってる人多いですよね!FontAwesomeのアイコンをそのまま使えるプラグインです。 そんなアイコン一個一個作れないよ、という人が多いと思うので。

最後に

あくまでエンジニアの人がSketchを使い始めるときの初めの一歩くらいの感覚で読んでいただけると。 僕の場合、Sketchはワイヤーを作る時に使うことが多いので、これで事足りてしまいます。誰かのお役に立てると幸いです。