C++における文字列操作

目次


 C++を使っていて、文字列の処理についてのTipsです。 追記及び修正等を気付き次第行なっていきます。

文字列の操作


文字(列)の挿入・削除

文字列の挿入: std::vector::insert

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "Farma_11";

    str.insert(2,  "***");
    cout << str << endl; // Fa***rma_11
}

参考: vector::insert - cpprefjp C++日本語リファレンス

文字列の末尾に挿入: std::basic_string::append

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "Farma_11";

    str.append(3, '!');
    cout << str << endl; // Farma_11!!!
}

参考: basic_string::append - cpprefjp C++日本語リファレンス

文字列内の一部の削除: std::basic_string::erase

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Farma_11";

    str.erase(str.end()-1); //end()は最後の次を指す
    cout << "末尾削除:  " << str << endl; // 末尾削除:  Farma_1

    str.erase(str.begin()+3); //begin()は先頭を指す
    cout << "4文字目削除:  " << str << endl; // 4文字目削除:  Fara_1
}

参考: basic_string::erase - cpprefjp C++日本語リファレンス

文字(列)の検索・置換

特定の文字(列)の検索: std::findなど

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "Farma_11";

    cout << "最初の ma: " << str.find("ma")+1 << "文字目から" << endl;
    // 最初の ma: 4文字目から
    cout << "最後の  a: " << str.find_last_of('a')+1 << "文字目" << endl;
    // 最後の  a: 5文字目
    cout << "存在しない: " << str.find("e")+1 << endl; //string::npos
    // 存在しない: 0
}

アスキーコードの変更

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Farma_11";

    char plus = 5; // C++ではアスキーコードがchar型
    str[1] += plus;
    cout << str << endl; // Ffrma_11
}

文字(列)のカウント

文字のカウント

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Farma_11";

    int cnt = 0;
    for(unsigned int i = 0; i < str.size(); i++){
        if(str[i] == 'a') cnt++;
    }
    cout << "カウント: a " << cnt << "個" << endl; // カウント: a 2個
}

文字列のカウント

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Farma_11";

    int cnt = 0;
    string s = "ma";
    for(unsigned int i = 0; i < str.size() - s.size() + 1; i++){
        if(str.substr(i, s.size()) == s) cnt++; //添え字iからs.size()分
    }
    cout << "カウント: " << s << " " << cnt << "個" << endl; // カウント: ma 1個
}

文字列内の文字の並びを変更する

文字列内の文字の交換: std::swap

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Farma_11";

    swap(str[0], str[str.size()-1]); // size()は文字数
    cout << "先頭と末尾の交換: " << str << endl; // 先頭と末尾の交換: 1arma_1F
}

参考: swap (非メンバ関数) - cpprefjp C++日本語リファレンス

文字列の反転: std::reverse

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "Farma_11";

    reverse(str.begin(), str.end()); // イテレータを用いて範囲指定
    cout << str << endl; // 出力: 11_amraF
}

参考: reverse - cpprefjp C++日本語リファレンス

文字列内の文字のソート: std::sort

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "Farma_11";

    sort(str.begin(), str.end());
    cout << "昇順: " << str << endl; // 昇順: 11F_aamr
    sort(str.begin(), str.end(), greater<char>());
    cout << "降順: " << str << endl; // 降順: rmaa_F11
}

参考: sort - cpprefjp C++日本語リファレンス

文字列と数値の変換

文字列から整数へ変換

#include <iostream>
#include <string>
using namespace std;

int main() {
    string num = "12345";
    int n = atoi((const char*)num.c_str());
    
    num += "-5"; n += -5; //共に-5を足す
    cout << "整数へ変換: " << num << " = " << n << endl;
}

文字列から1桁ずつ整数へ変換

 一桁の数値への変換では、'[0-9]の文字' - '0'にて数値へ変換可能。

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

int main() {
    string num = "12345";
    
    char number[10];
    int sum = 0;
    strcpy(number, num.c_str());
    for(unsigned int i = 0; i < num.size(); i++){
        sum += number[i] - '0';
    }
    cout << "1〜5の和: " << sum << endl;
}

HRI2017: "Marionette: Enabling On-Road Wizard-of-Oz Autonomous Driving Studies"

本記事・論文について


 本記事では以下の論文の概略を示しつつ、論文読解のための知識をまとめる。

論文: Wang, Peter, et al. "Marionette: Enabling On-Road Wizard-of-Oz Autonomous Driving Studies." Proceedings of the 2017 ACM/IEEE International Conference on Human-Robot Interaction. ACM, 2017.
HRI2017: Regular Session #5 - HRI2017

HRI(International Conference on Human-Robot Interaction): 人間とロボットの相互作用に関する研究成果を発表する国際会議

論文の内容


論文の概要

 本研究において、オンロード模擬自律走行研究のための相互作用研究システムMarionetteを開発した。 Marionetteは以下のような利点がある。

  • 低コスト、ポータブル、かつ多目的であるという特徴がある。
  • 部分的自律運転の錯覚を促進し、オンロード研究のための車両運転の安全性を維持する。
  • 運転手と部分的自律車両間のオンロードでの相互作用をシミュレートする研究のためのプラットフォームとして役立つ。

f:id:farma_11:20180106203252p:plain
Marionette インターフェース(当該論文から引用)

自律運転シミュレーション

 既存研究では、完全自動運転のシミュレーションが可能であるとされる。 しかし、自動運転におけるレベル2・3のシミュレーションには、ドライバーと車両間の相互作用部分が必要となる。

 単に多くの自動化をすることで解決するわけではなく、自動化分野の主な課題の多くは人間と機械の相互作用の部分にある。 特に自律運転技術に関して、運転者と部分的自動化機能の相互作用が十分に理解されていないという問題がある。

 実験室における運転シミュレータの研究と、路上実験の双方が重要である。

研究デザイン

研究デザインの概要

 路上実験で、自動運転レベル2・3の将来の自律運転シナリオにおける運転者の行動を理解する必要がある。 そのため、実験参加者に自動運転に対する経験を与えるためのWizard-of-Ozプロトコルを設計している。

 研究では、実際に運転するための運転席に取り付けられたハンドルと、助手席に取り付けられた偽ハンドルの2つを用意する。 助手席のハンドルを操作すると、運転席のハンドルへ伝わる。

Marionetteシステムの概要

 Marionetteは低コストで簡単に複製できるオンロード研究のための、自律運転シミュレートインタフェースシステム。

 Wizardは参加者の存在を容認し、参加者の制御操作をWizardが任意で取捨選択する。 また、参加者の車両制御の情報を制御、調整するソフトウェア構築をしている。 さらに、研究者の数を増やすため、安価であり設置の容易性を重視した部品の利用している。

 実装に関する詳細な事項は、当該論文を参照ください。

システムに対する評価実験

評価実験の概要

 システムのユースケースとして、以下のものがある。

  • Wizardによる通常とは逸脱した運転(不正な運転:車線を蛇行等)に対して、被験者がどう反応するかについての路上実験
  • 被験者がどのようにハンドルをオーバライド*1 できるかの実験

 具体的には、以下の手順で実験を行なっている。

  1. 被験者をWIzard Operatorが見えないように車に誘導する。
  2. 被験者には、レベル3の自律走行車両と同様の機能を備えた自律運転システムで運転することを指示する。
  3. 自律運転システムが「不正な運転をした時」「自律運転が停止した時」に、被験者が運転をオーバライドする。
  4. 実験後の被験者への質問と運転のビデオ映像から分析を行う。

評価実験の結果と考察

 被験者は、このデバイスが自走車へのナビゲーション入力として使用できることをすぐに認識することができた。 自動運転開始後5-10分経過した段階で、心配そうな身振り手振りが大きく減ることが判った。

 また、被験者から得たフィードバックから以下のことがわかった。

  • Marionette上の多くの入力モードがシステムへの意図の伝達に有用
  • Marionetteには車両情報を示す計器類がない

 今後の展望としては、ハードウェア面では特にシステム上の制約を解消することが挙げられる。 また、ソフトウェア面としてコードのオープンソース化や、他の研究者が使えるようにプラットフォーム化することも挙げられた。

論文読解の参考となる知識


WOZ(Wizard-of-Oz)法*2

 システムに扮した人間(Wizard)がシステムの代わりをする対話シミュレーション手法。 音声対話システムの領域や、HCI(Human-Computer Interaction)の領域などで、開発中の効果的なシミュレーション手法として用いられている。

 人間同士の対話ではあるものの、ユーザは実際にシステムを相手にしていると思いながら対話を行うため、実際のシステムに近い状態での対話データとなる。 Wizardが未開発の部分を補完することで、開発中にシミュレーションが可能となる。 設計・開発者は実験結果を踏まえて実際のシステムを開発する必要がある。

 名前は、オズの魔法使い(The Wonderful Wizard of Oz)から由来している。 オズの魔法使いにおけるドロシーがユーザであり、願いを叶えてくれるはずのオズの魔法使いがWizardに対応している。

自動運転レベルの分類

 2016年9月にNHTSA(米運輸省道路交通安全局)*3の発表に伴い、 自動運転レベルが以下に示すSAE J3016(2016)*4のように見直されている。

  • レベル5: 完全運転自動化(Full Driving Automation)
    システムが全ての運転タスクを実施する。

  • レベル4: 高度運転自動化(High Driving Automation)
    限定領域内で、システムが全ての運転タスクを実施する。

  • レベル3: 条件付き運転自動化(Conditioned Driving Automation)
    限定領域内で、システムが全ての運転タスクを実施する。作動継続が困難な場合は運転者が適切に対応する必要がある。

  • レベル2: 部分的運転自動化(Partial Driving Automation)
    前後・左右方向の両方の 車両制御に係る運転タスク(DDT)のサブタスクを実施する運転支援システムが搭載されている。

  • レベル1: 運転者支援(Driver Assistance)
    前後・左右方向のいずれかの 車両制御に係る運転タスク(DDT)のサブタスクを実施する運転支援システムが搭載されている。

  • レベル0: 運転自動化なし(No Driving Automation)
    人間の運転者が全ての運転タスクを実行する。

 ただし、当該論文ではレベル4までの旧分類に従って執筆されている模様。 SAE J3016(2016)のレベル5・4が、旧分類ではレベル4として分類されている。

論文を読んだ感想


Many of the key challenges to automation lie in the area of human-machine interaction. [...] these questions [...] cannot be resolved simply with more automation. (自動化の重要な課題の多くは、人と機械の間の相互作用の領域にある。(中略) これらの問題は単純により自動化することによって解決することはできない。)

 人工知能が盛んに議論されている中、問題解決のために何でも自動化すべきというわけでないことを改めて感じた。 人と機械が共存しながら、人の生活を豊かにする機械であるために、その相互作用について知る必要がある。

*1:オーバライド: 伝わった操作を別の操作上書きすること

*2:Fraser, Norman M., and G. Nigel Gilbert. "Simulating speech systems." Computer Speech & Language 5.1 (1991): 81-99.

*3:NHTSA : The National Highway Traffic Safety Administration

*4:SAE : Society of Automoitve Engineers, inc., アメリカ自動車技術会

ABC013 C – 節制

問題の概要


abc013.contest.atcoder.jp

  N \ (1 \leq H \leq 5 \times 10^{5})日の間、初期値  H \ (1 \leq H \leq 10^{9})満腹度を 0以下にさせないために、以下のような食事のいずれかを選ぶ。

内容 食費 満腹度の変動
普通の食事  A \ (1 \leq A \leq 10^{6})  +B \ (1 \leq B \leq 10^{6})
質素な食事  C \ (1 \leq C < A)  +D \ (1 \leq D < B)
食事抜き  0  -E \ (1 \leq E \leq 10^{6})

 以上の条件を満たす必要最低限の食費はいくらかを求める。 また、満腹度には上限がない上、 Nの値の範囲で以下のように部分点が設定されている。

範囲  N \leq 10  N, H, B, D \leq 50  N \leq 1000  N \leq 5 \times 10^{6}
点数 10 40 100 101

問題の考察


 普通の食事の日数を X日、質素な食事の日数を Y日とする。

 この時、満腹度には上限がないため、最初の X + Y日に全ての食事を済ますと考える。 この方法では、満腹度が途中で 0になる状態を考えずに、食費の最小値を求めることができる。

f:id:farma_11:20180109090500p:plain
食事の計画

解答例


[100点解法]  (X, Y) に対する全探索

 各  (X, Y) に対して、以下の不等式が成り立つかどうかを確認する。

 H + BX + DY - (N - X - Y)E > 0 \ \cdots \ (1)

 しかし、この解放では O(n^{2})であるため、 N \leq 5 \times 10^{6}のテストケースでは時間が足りない。

[満点解法]  Xのみの全探索

 式 (1) を以下のように式変形すると Xのみの探索で済むため、 O(n) で求めれる。

 Y > \frac{(N - X)E - H - BX}{D + E} \ \cdots \ (2)

 また、 Xの値が大きいとき、 Yの値が負の値をとることがあるため、注意が必要となる。

[満点解法] 尺取り法を用いた解法

 この解法では、式 (1) をそのまま用いる。  (X, Y)の探索を、以下のように尺取り法を用いることで、 O(n)で探索することを可能とした。

  1. 最初に、普通の食事だけで乗り切る場合の最低回数を求める。これを Xとする。
  2. 式(1)を満たさなくなるまで、 Xを減少させる。
  3. 式(1)を満たすまで、質素な食事の回数 Yを増加させる。
  4. 操作2, 3ができなくなるまで繰り返す。

 以上のソースコードは以下のGithub上にて参照可能です。 github.com

その他の解説サイト

deviseによるFacebook / Twitter 認証 -Rails奮闘記②-

本記事の紹介


 本記事は、私がRuby on Rail(Rails, RoR)を用いたWebアプリケーションを作る過程を示したものです。 Railsの勉強も兼ねているため、間違いなどもあった場合はご指摘いただけると大変嬉しいです!

 Devise を用いた基本的なユーザ認証の作成までは、過去記事を参照。

farma-11.hatenablog.com

deviseによるOAuth 認証


Dotenvによる環境変数の管理

 Gem: Dotenvを導入することでGitのリポジトリには含めずに外部APIの情報を環境変数として扱う。

1. Dotenvをインストール

# Gemfile
gem 'dotenv-rails', require: 'dotenv/rails-now'
$ bundle install --path vendor/bundle

2. .envファイルを作成

# .env
FB_APP_ID="[FacebookのアプリID]"
FB_APP_SECRET="[Facebookのapp secret]"
TW_APP_KEY="[TwitterのAPI key]"
TW_APP_SECRET="[TwitterのAPI secret]"

3. コンソールを起動して、呼び出せるか確認

$ bundle exec rails c
Running via Spring preloader in process 11075
Loading development environment (Rails 5.1.4)
irb(main):001:0> Dotenv.load
=> {"FB_APP_ID"=>"[FacebookのアプリID]", "FB_APP_SECRET"=>"[Facebookのapp secret]", "TW_APP_KEY"=>"[TwitterのAPI key]", "TW_APP_SECRET"=>"[TwitterのAPI secret]"}
irb(main):002:0> quit

4. .gitignore.envを追加

/.env

Facebook / Twitter 認証の実装

5. Gemfileの編集

# Gemfile
gem 'omniauth-facebook'
gem 'omniauth-twitter'

6. インストール

$ bundle install --path vendor/bundle

7. OAuthで取得するproviderとuidを保持するために、Userモデルにカラムを追加

$ rails g migration add_columns_to_users provider uid
$ rake db:migrate

8. Deviseにて取得したプロバイダの各キーを設定
 Dotenvにて管理されている各キーをENV['HOSTNAME']のように利用できる。

# config/initializers/devise.rb
# (省略)
  # ==> OmniAuth
  # Add a new OmniAuth provider. Check the wiki for more information on setting
  # up on your models and hooks.
  # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
  config.omniauth :facebook, ENV['FB_APP_ID'], ENV['FB_APP_SECRET']
  config.omniauth :twitter, ENV['TW_APP_KEY'], ENV['TW_APP_SECRET']
# (省略)

9. Userモデルにモジュールを追加

# app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable
  # (省略)
}

10. Userモデルにfindメソッドを実装

# app/models/user.rb
class User < ApplicationRecord
  # (省略)
  def self.find_for_oauth(auth)
    user = User.where(uid: auth.uid, provider: auth.provider).first

    unless user
      user = User.create(
        uid:      auth.uid,
        provider: auth.provider,
        email:    User.dummy_email(auth),
        password: Devise.friendly_token[0, 20]
      )
    end

    user
  end

  private

  def self.dummy_email(auth)
    "#{auth.uid}-#{auth.provider}@example.com"
  end
end

11. ディレクトリを作成

$ mkdir app/controllers/users

12. Userコントローラにコールバック処理を実装

# app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    callback_from :facebook
  end

  def twitter
    callback_from :twitter
  end

  private

  def callback_from(provider)
    provider = provider.to_s

    @user = User.find_for_oauth(request.env['omniauth.auth'])

    if @user.persisted?
      flash[:notice] = I18n.t('devise.omniauth_callbacks.success', kind: provider.capitalize)
      sign_in_and_redirect @user, event: :authentication
    else
      session["devise.#{provider}_data"] = request.env['omniauth.auth']
      redirect_to new_user_registration_url
    end
  end
end

13. ルーティング処理

# config/routes.rb
Rails.application.routes.draw do
  devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }

  # (省略)
end

まとめ


 本記事は、以下の記事を参考にまとめました。

deviseを用いたユーザ認証作成 -Rails奮闘記①-

本記事の概要


 本記事は、私がRuby on Rail(Rails, RoR)を用いたWebアプリケーションを作る過程を示したものです。 Railsの勉強も兼ねているため、間違いなどもあった場合はご指摘いただけると大変嬉しいです!

Devise を用いた基本的なユーザ認証の作成まで


Railsプロジェクトを作成する

1. Githubの準備

$ git clone https://github.com/[Githubのユーザ名]/[プロジェクト名].git
$ cd [プロジェクト名]

2. Gemfileという雛形ファイルが作成

$ bundle init

3. Gemfileに書き込む

gem "rails","5.1.4"

4. ルートディレクトリ下のvendor/bundleディレクトリにインストール

$ bundle install --path vendor/bundle

5. Rails プロジェクトを作成する

$ bundle exec rails new .

deviseの初期設定

6. deviseをインストール

# Gemfile
gem 'devise'
$ bundle install --path vendor/bundle

7. deviseの設定ファイルを生成
 config/initializers/devise.rbconfig/locales/devise.en.yml ができる

$ rails g devise:install
$ bundle exec rails g devise:install
Running via Spring preloader in process 84346
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

8. deviseのメール送信時のホスト名を指定

# config/environments/development.rb
Rails.application.configure do
  ...
  # mailer setting
  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end

9. 実際のControllerやViewを作成  ここでは、Homeコントローラーと、indexページとshowページを追加した。

$ rails g controller Home index show

10. ログアウト時などのリダイレクト先として、root_urlの指定する

# config/routes.rb
Rails.application.routes.draw do
  root to: "home#index"
end

11. エラーメッセージ(flashメッセージ)の表示領域の設定

<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html> 
  <!--(省略)-->
 <body>
  <p class="notice"><%= notice %></p>
  <p class="alert"><%= alert %></p>

  <%= yield %>

 </body> 
</html>

12. deviseのモデルを作成

$ rails g devise User
      invoke  active_record
      create    db/migrate/[yyyymmddhhmmss]_devise_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      insert    app/models/user.rb
       route  devise_for :users

13. マイグレートを実施  マイグレーションとは、SQLを書くことなくRubyでデータベース内にテーブルを作成すること。

$ rake db:migrate

14. Homeのshow画面へのアクセス制限を追加
 ステップ13までは、ログインしていない状態でshow画面 | http://localhost:3000/home/showにアクセス可能となってしまっている。

# app/controllers/home_controller.rb
class HomeController < ApplicationController
  # ユーザがログインしていないと"show"にアクセスできない
  before_action :authenticate_user!, only: :show

  def index
  end
  # (省略)
end

usernameで認証できるようにする

15. テーブルにusernameを追加

$ rails g migration add_username_to_users username:string

16. indexの追加と一意制約を追加

# db/migrate/[yyyymmddhhmmss]_add_username_to_users.rb
class AddUsernameToUsers < ActiveRecord::Migration[5.1]
  def change
    add_column :users, :username, :string
    add_index :users, :username, unique: true
  end
end

17. マイグレートを実施

$ rake db:migrate

18. 認証キーをusername

# config/initializers/devise.rb

# (省略)
# ==> Configuration for any authentication mechanism
  # Configure which keys are used when authenticating a user. The default is
  # just :email. You can configure it to use [:username, :subdomain], so for
  # authenticating a user, both parameters are required. Remember that those
  # parameters are used only when authenticating and not when retrieving from
  # session. If you need permissions, you should implement that in a before filter.
  # You can also supply a hash where the value is a boolean determining whether
  # or not authentication should be aborted when the value is not present.
  # config.authentication_keys = [:email]
  config.authentication_keys = [:username]
# (省略)

19. UserモデルにValidateを追加
 usernameには、以下のバリデーションを追加した。

  • usernameが大文字小文字の区別をせずにuniqueであること
  • 文字数が4 - 20文字であること
  • usernameは半角英数字であること
# app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  # usernameのバリデーション
  validates :username,
    uniqueness: { case_sensitive: :false },
    length: { minimum: 4, maximum: 20 },
    format: { with: /\A[a-z0-9]+\z/, message: "ユーザー名は半角英数字です"}
end

20. ログイン画面のemailをusernameの入力フィールドに変更

<!-- app/views/devise/sessions/new.html.erb -->
<h2>Log in</h2>

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
  <div class="field">
    <%= f.label :username %><br />
    <%= f.text_field :username, autofocus: true %>
  </div>

  <!--(省略)-->
<% end %>

<%= render "devise/shared/links" %>

21. サインアップ画面もusernameの入力フィールドに対応

<!-- app/views/devise/registrations/new.html.erb -->
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

  <div>
    <%= f.label :username %><br />
    <%= f.text_field :username, autofocus: true %>
  </div>

  <!--(省略)-->
<% end %>

<%= render "devise/shared/links" %>

22. プロフィール変更画面もusernameの入力フィールドに対応

<!-- app/views/devise/registrations/edit.html.erb -->
<h2>Edit <%= resource_name.to_s.humanize %></h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  <%= devise_error_messages! %>

  <div>
    <%= f.label :username %><br />
    <%= f.text_field :username, autofocus: true %>
  </div>

  <!--(省略)-->
<% end %>

23. app/controllers/application_controller.rbの追記 Publifyでユーザー登録するとCan't be blankエラーの対応

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  # deviceのコントローラーのときに、下記のメソッドを呼ぶ
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    added_attrs = [:username, :email, :password, :password_confirmation, :remember_me]
    devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
    devise_parameter_sanitizer.permit :account_update, keys: added_attrs
  end
end

まとめ


 本記事は、以下の記事を参考にまとめました。