ここまでで Devise のユーザ認証をユーザ名で行えるようになりました。次にアカウントに対して、自己紹介やアバターを追加できるようにします。
User モデルに全部追加していってもよいのですが、ユーザ一覧的なものを別途表示したかったりうするときに認証用のモデルである User をいじるのもいかがなものかということで、別途 Profile モデルを定義して、自己紹介やアバター、ニックネーム等の情報はそちらにまとめたいと思います。
まずは、Profile モデルをユーザ作成時に生成するところまで。
1. Profile モデルの定義
2. User モデルと Profile モデルの 1対1 関連付け
3. ユーザ登録時に Profile を作成してデフォルトの情報を入力して User に紐付け
Profile モデルの定義
まずは Profile モデルを定義します。名前とアバター、自己紹介を定義しておきます。アバターについては後で Carrierwave を使って画像の管理ができるように定義しておきます。
1 2 3 4 5 6 7 |
$ bundle exec rails g model profile name:string avatar:string description:text user_id:integer invoke active_record create db/migrate/20190916030632_create_profiles.rb create app/models/profile.rb invoke test_unit create test/models/profile_test.rb create test/fixtures/profiles.yml |
User モデルと Profile モデルの 1対1関連付け
これもいつもの通り、User モデルと Profile モデルで has_one と blongs_to を定義しておきます。
1 2 3 4 5 6 7 8 |
class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable has_one :profile end |
1 2 3 |
class Profile < ApplicationRecord belongs_to :user end |
ユーザ登録時に Profile を作成して User に紐付け
次にユーザ登録時に Profile 情報を生成して User に紐付けるようにします。すでに User に関連する Devise の controller は作成しているので、これを編集します。
ユーザ作成は、app/controller/users/registrations_controller.rb で定義されています。ユーザの作成は create メソッドで行われているため、ここを書き換えます。ここでは、初期値として Profile の name に、User の username を設定するようにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Users::RegistrationsController < Devise::RegistrationsController before_action :configure_sign_up_params, only: [:create] before_action :configure_account_update_params, only: [:update] def create super resource.build_profile resource.profile.name = resource.username resource.save end protected def configure_sign_up_params devise_parameter_sanitizer.permit(:sign_up, keys: [:username, :email]) end def configure_account_update_params devise_parameter_sanitizer.permit(:account_update, keys: [:username, :email]) end end |
動作確認
新規ユーザ作成時に Profile を作成して紐付けるようにしたので、一度 DB を初期化して動作確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
$ bundle exec rails db:drop Dropped database 'db/development.sqlite3' Database 'db/test.sqlite3' does not exist $ bundle exec rails db:create Created database 'db/development.sqlite3' Created database 'db/test.sqlite3' $ bundle exec rails db:migrate == 20190910074106 DeviseCreateUsers: migrating ================================ -- create_table(:users) -> 0.0008s -- add_index(:users, :email, {:unique=>true}) -> 0.0008s -- add_index(:users, :reset_password_token, {:unique=>true}) -> 0.0009s == 20190910074106 DeviseCreateUsers: migrated (0.0027s) ======================= == 20190913052202 AddUsernameToUser: migrating ================================ -- add_column(:users, :username, :string, {:unique=>true, :null=>false, :default=>""}) -> 0.0006s == 20190913052202 AddUsernameToUser: migrated (0.0007s) ======================= == 20190916030632 CreateProfiles: migrating =================================== -- create_table(:profiles) -> 0.0007s == 20190916030632 CreateProfiles: migrated (0.0008s) ========================== $ bundle exec rails s |
サインインで新規ユーザを登録したあと一度 rails サーバをとめて、コマンドラインでいろいろ確認します。
1 2 3 4 5 6 7 8 9 10 |
$ bundle exec rails c Loading development environment (Rails 5.2.3) irb(main):001:0> user = User.first User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]] => #<User id: 1, email: "kayama.hiroshi@example.com", created_at: "2019-09-17 03:30:14", updated_at: "2019-09-17 03:30:14", username: "kayama.hiroshi"> irb(main):002:0> user.profile Profile Load (0.1ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."user_id" = ? LIMIT ? [["user_id", 1], ["LIMIT", 1]] => #<Profile id: 1, name: "kayama.hiroshi", avatar: nil, description: nil, user_id: 1, created_at: "2019-09-17 03:30:14", updated_at: "2019-09-17 03:30:14"> irb(main):003:0> user.profile.name => "kayama.hiroshi" |
ユーザ登録時に Profile が作成され、意図したとおりに User の username が Profile の name として設定されていることが確認できました。