rails レスポンスヘッダーをログ出力する

devise_token_authが返すレスポンスヘッダーをログに出力したくて調べた内容をメモしておく。app/controllers/application_controller.rbのafter_actionでheadersやresponseに入っていると思ったのだが期待した値はなく。controllerのaction実行後にdevise_token_authがヘッダーにセットしているのかな...

lib/HttpLogger.rb

class HttpLogger.rb
  def initialize(app)
    @app = app
  end
  def call(env)
    res = @app.call(env)

    // リエクスト
    puts "%s, %s, %s" % [env["HTTP_UID"], env["HTTP_CLIENT"], env["HTTP_ACCESS_TOKEN"]]

    // レスポンス(HTTPステータス、ヘッダー)
    puts "%s, %s" % [res[0], res[1]]

    res
  end
end

config/application.rb

・・・
require "./lib/httplogger"

module SampleAppApi
  class Application < Rails::Application                                                                                                                                                                                                      
                                                                                                                                                                                                                                              
    ・・・                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                              
    config.middleware.use ::HttpLogger
                                                                                                                                                                                                                                              
  end
end

ちなみにHttpLoggerのcallのenvには他にも以下のような情報があった

SCRIPT_NAME
QUERY_STRING
SERVER_PROTOCOL
SERVER_SOFTWARE
GATEWAY_INTERFACE
REQUEST_METHOD
REQUEST_PATH
REQUEST_URI
HTTP_VERSION
HTTP_HOST
HTTP_ACCEPT
HTTP_COOKIE
HTTP_USER_AGENT
HTTP_ACCEPT_LANGUAGE
HTTP_ACCEPT_ENCODING
HTTP_CONNECTION
SERVER_NAME
SERVER_PORT
PATH_INFO
REMOTE_ADDR

こんな力技たぶんじゃないとできないなんてありえないと思うのでもっとちゃんとしたやり方があればご教授お願いいたします。以上です

xcode カスタムURLスキームを本番と開発アプリで切替える

今回やりたかったことはカスタムURLスキームの設定。ブラウザから「myapp://」等のリンクをクリックしたときにアプリを起動させたいとかの場合に設定するものです。
アプリ開発していて、開発と本番アプリで別の名前で設定したいと思いやり方を調べたのでメモしておく。

作業のながれはざっくり以下
1. DebugとReleaseでそれぞれ別のURLスキームを定義(変数みたいなイメージ)
2. info.plistより1.で設定した変数を指定
3. DebugまたはReleaseを指定してビルド

1. TARGETS > Build Settingsの設定

1-1. TARGETS > Build Settings を選択して+ボタンで「Add User-Defined Setting」ボタンをクリック

f:id:yoppy0066:20181228130924p:plain:w300

1-2. User-Definedに「NEW_SETTING」が追加されるので名前を変更する。今回は「CUSTOM_URL_SCHEME」とする

f:id:yoppy0066:20181228131033p:plain:w300

f:id:yoppy0066:20181228131039p:plain:w300

1-3. 「CUSTOM_URL_SCHEMU」の「Debug」「Release」それぞれにURLスキームを設定する。

f:id:yoppy0066:20181228131132p:plain:w300

2. info.plistの設定

2-1. info.plistの「Information Property List」の+ボタンで項目を追加

f:id:yoppy0066:20181228131224p:plain:w300

2-2. 追加した項目を「URL Types」に変更して、「URL Identifier」の+ボタンで追加した項目を「URL Schemes」に変更して、$(CUSTOM_URL_SCHEME)を設定する

f:id:yoppy0066:20181228131246p:plain:w300

3. ビルド

3-1. キャプチャを参考に「Edit Scheme」を開く

f:id:yoppy0066:20181228131323p:plain:w300

3-3.「Build Configuration」より「Release」または「Debug」を選択

f:id:yoppy0066:20181228131339p:plain:w300

ここまで設定してビルドを行うとDebug、Releaseごとに別のURLスキームを選択できました。カスタムURLスキーム以外にアプリ名やBundleID等も切替える手順はこちらにまとめた

Xcode10 開発アプリと本番アプリで切替える - とりあえずphpとか


以上です

Xcode10 開発アプリと本番アプリで切替える

やりたいこと

・WebAPIのURLやSDKのキーの切替え
・BundleID、アプリ名の切替え

他にもやるべきことはありそうだけど自分の場合、とりあえずこれだけできれば最低限ok。
本番と開発環境だけでステージング環境とかはとりあえず考えない。

WebAPIやSDKのキーの切替え

デフォルトでマクロで「DEBUG」がtrueとなっているので条件分岐が可能

Env.swiftとか

struct Env {
#if DEBUG
  static let API_URL = "開発環境のURLとk"
  static LET API_KEY = "開発環境のキーとか"
#else
  static let API_URL = "本番環境のURLとか"
  static let API_KEY = "本番環境のキーとか"
#endif
}

・New Scheme...より本番用のスキームを追加
名前は「xxx-prod」とかにする。追加したら「Edit Scheme...」より「Run」の「Build Configuration」を「Release」に変更
これでこちらのスキームを選択してビルドすると本番用の分岐を通るようになる

アプリ名やBundleIDの切り替え

・Bundle Identifier
TARGETS > Build Settings > Product Bundle Identifier の値を変更

・アプリ名
TARGETS > Build Settings > Product Name の値を変更

以上です

migrate swift4.0 to swift4.2

swift4.0 から swift4.2 への修正内容メモしておく

UIKeyboardWillShow

UIResponder.keyboardWillShowNotification

UIKeyboardWillHide

UIResponder.keyboardWillHideNotification

UIControlEvents

UIControl.Event

UIEdgeInsetsInsetRect(rect, padding)

rect.inset(by: padding)

UIViewContentMode

UIView.ContentMode

addChildViewController

addChild

UIControlContentHorizontalAlignment

UIControl.ContentHorizontalAlignment

UITextBorderStyle

UITextField.BorderStyle

bringSubview(toFront: ***)

bringSubviewToFront(***)

UIAlertControllerStyle

UIAlertController.Style.alert

UIAlertActionStyle

UIAlertAction.Style

UIKeyboardFrameEndUserInfoKey

UIResponder.keyboardFrameEndUserInfoKey

UIActivityIndicatorViewStyle

UIActivityIndicatorView.Style

UITableViewCellStyle

UITableViewCell.CellStyle

UIImagePickerControllerSourceType

UIImagePickerController.SourceType

NSNotification.Name.UITextViewTextDidChange

UITextField.textDidChangeNotification

UIDatePickerMode

UIDatePicker.Mode

UIKeyboardFrameEndUserInfoKey

UIResponder.keyboardFrameEndUserInfoKey

popupViewController.didMove(toParentViewController: self)

popupViewController.didMove(toParent: self

UIApplicationLaunchOptionsKey

UIApplication.LaunchOptionsKey

NSAttributedStringKey

NSAttributedString.Key

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any])

UIImagePickerControllerImageURL

UIImagePickerController.InfoKey.imageURL

以上です

Swift LUExpandableTableViewを使って折りたたみ可能なUITableViewを実装

こんな感じのありがちなUI。ライブラリを使わずに自前で実装する方法もけっこう書いていただいている人がいて実装することはできたのだが、テーブルのレコード数が増えると開閉したときのスクロール位置がガタガタ。

自分の実装方法に問題があるかもしれないが細かいところまで解決できずいたところにこちらのライブラリを見つけた。少し同じ問題は発生するのだが自分でやるよりは全然マシでこちらを使うことにしたので使い方をメモしておく。

https://github.com/LaurentiuUngur/LUExpandableTableView


f:id:yoppy0066:20181207220625g:plain

ViewController.swift

import UIKit
import LUExpandableTableView

class ViewController: UIViewController, LUExpandableTableViewDataSource, LUExpandableTableViewDelegate {

    var expandableTableView = LUExpandableTableView()

    override func viewDidLoad() {
	super.viewDidLoad()

        expandableTableView.frame = view.bounds
        view.addSubview(expandableTableView)

        expandableTableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
	expandableTableView.register(CustomHeader.self, forHeaderFooterViewReuseIdentifier: "CustomeHeader")

	expandableTableView.expandableTableViewDelegate = self
	expandableTableView.expandableTableViewDataSource = self
    }

    // MARK: - LUExpandableTableViewDelegate
    // セルの高さを返します
    func expandableTableView(_ expandableTableView: LUExpandableTableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
	return 50
    }

    // セクションヘッダーの高さを返します
    func expandableTableView(_ expandableTableView: LUExpandableTableView, heightForHeaderInSection section: Int) -> CGFloat {
	let header = CustomHeader()
	return header.setup(text: "セクションタイトル")
    }

    // MARK: - LUExpandableTableViewDataSource
    // セクション数を返します
    func numberOfSections(in expandableTableView: LUExpandableTableView) -> Int {
	return 100
    }

    // セル数を返します
    func expandableTableView(_ expandableTableView: LUExpandableTableView, numberOfRowsInSection section: Int) -> Int {
	return 10
    }

    // View(セル)を返します
    func expandableTableView(_ expandableTableView: LUExpandableTableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = expandableTableView.dequeueReusableCell(withIdentifier: "Cell") else {
            return UITableViewCell()
        }
        cell.textLabel?.text = "セル"
        return cell
    }

    // View(セクション)を返します
    func expandableTableView(_ expandableTableView: LUExpandableTableView, sectionHeaderOfSection section: Int) -> LUExpandableTableViewSectionHeader {
        guard let header = expandableTableView.dequeueReusableHeaderFooterView(withIdentifier: "CustomeHeader") as? CustomHeader else {
            return LUExpandableTableViewSectionHeader()
        }
        let _ = header.setup(text: "セクション")
        return header
    }
}

CustomeHeader.swift

class CustomHeader: LUExpandableTableViewSectionHeader {

    var label = UILabel()
    var button = UIButton()

    override init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override var isExpanded: Bool {
        didSet {
            self.button.setTitle(isExpanded ? "閉じる" : "開く", for: .normal)
        }
    }

    func setup(text: String) -> CGFloat {

        backgroundView = UIImageView()
        backgroundView?.backgroundColor = UIColor.init(red: 157/255, green: 204/255, blue: 224/255, alpha: 1)

        label.frame = CGRect(x: 10, y: 0, width:UIScreen.main.bounds.size.width*0.8,  height: 100)
        label.text = text
	label.font = UIFont.boldSystemFont(ofSize: 13)
        addSubview(label)

        button.frame = CGRect(x: label.frame.width, y: 0, width: UIScreen.main.bounds.size.width*0.2, height: 100)
        button.setTitle(isExpanded ? "閉じる" : "開く", for: .normal)
        button.setTitleColor(UIColor.black, for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 13)
        button.addTarget(self, action: #selector(onOpen(sender:)), for: .touchUpInside)
        addSubview(button)

        return button.frame.origin.y + button.frame.height
    }

    @objc func onOpen(sender: UIButton) {
        delegate?.expandableSectionHeader(self, shouldExpandOrCollapseAtSection: section)
    }
}

以上です