8
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

railsのdeviseを使ってUserモデルに一対一のリレーションシップでユーザー情報を紐付ける

Last updated at Posted at 2018-07-12

今回やりたかったこと

認証情報とユーザー情報を切り分けたかった。
セキュリティー上の観点とユーザー情報が増えれば増えるほど処理が重くなるかなーッと思って今回は以下の内容で対応。(あんまり意味ないのかなー)
ユーザー認証は「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
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 %>

参考にさせていただいた記事

deviseで作成したUserモデルでhas_oneなリレーションを組む

8
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?