今回やりたかったこと
認証情報とユーザー情報を切り分けたかった。
セキュリティー上の観点とユーザー情報が増えれば増えるほど処理が重くなるかなーッと思って今回は以下の内容で対応。(あんまり意味ないのかなー)
ユーザー認証は「devise」
ユーザー情報は別テーブルの「userinfo」に格納する
#前提条件
各種バージョン
- ruby 2.5.1
- Rails 5.2.0
$ bundle install
「devise」を記述済みで上記コマンドを実行済み
認証の設定
/app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# CSRF保護をオンにする以下の1行を有効にします。
protect_from_forgery with: :exception
# ログイン済ユーザーのみにアクセスを許可する
before_action :configure_permitted_paramaters, if: :devise_controller?
private
def configure_permitted_paramaters
#devise_parameter_sanitizer = 許可するパラメータを追加(railsのバージョンによって書き方が異なるので注意)
devise_parameter_sanitizer.permit(:sign_up, keys: [:userinfo_attributes => [:user_id, :name, :body]])
devise_parameter_sanitizer.permit(:account_update, keys: [:userinfo_attributes => [:user_id, :name, :body]])
end
end
- 【Rails】Deviseでのstrong parameters指定はdevise_parameter_sanitizer.forではなくdevise_parameter_sanitizer.permitを使うようになったらしい
- Rails+Deviseでユーザー名でサインインできるようにする
app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
#
# 省略
#
#以下を追記
protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up) do |params|
params.permit(:email, :password, :password_confirmation, :current_password,
userinfo_attributes: [:user_id,:name, :body])
end
end
# If you have extra params to permit, append them to the sanitizer.
def configure_account_update_params
devise_parameter_sanitizer.permit(:account_update) do |params|
params.permit(:email, :password, :password_confirmation, :current_password,
userinfo_attributes: [:user_id, :name, :body])
end
end
end
/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, :confirmable
#has_one = 関連付け inverse_of = 双方の関連付け
has_one :userinfo, dependent: :destroy, inverse_of: :user
accepts_nested_attributes_for :userinfo, update_only: true
end
Active Record の関連付け (アソシエーション)
[ActiveRecordのコールバックの順序・コールバック内のロールバック処理について]
(https://blog.toshimaru.net/active-record-callbacks/)
userとuserinfoのリレーションを作成
/db/migrate/xxxxxxx_create_userinfos.rb
class CreateUserinfos < ActiveRecord::Migration[5.2]
def change
create_table :userinfos do |t|
t.references :user, null: false
t.string :name
t.text :body
t.timestamps
end
end
end
マイグレートを実行
$ rails db:migrate
userモデルとの関連付け
/app/models/userinfo.rb
class Userinfo < ApplicationRecord
belongs_to :user, inverse_of: :userinfo, optional: true
end
各view側の設定
rails:/app/views/users/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 class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %>
<% if @minimum_password_length %>
<em>(<%= @minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<%= f.fields_for :userinfo, resource.build_userinfo || Userinfo.new do |info| %>
<%= info.label :name %>
<%= info.text_field :name%>
<% end %>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "users/shared/links" %>
rails:/app/views/users/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 class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, autocomplete: "off" %>
<% if @minimum_password_length %>
<br />
<em><%= @minimum_password_length %> characters minimum</em>
<% end %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "off" %>
</div>
<%= f.fields_for :userinfo do |info| %>
<%= info.label :name %>
<%= info.text_field :name%>
<% end %>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
<%= link_to "Back", :back %>