質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.03%

railsでユーザー新規登録(devise)をしたとき1:1の関係にある他のテーブルにデータを自動作成したい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,472

zendendo

score 36

前提・実現したいこと

ruby(rails)で、銀行みたいなアプリをつくっています。
銀行のように一人の顧客が一つだけ口座を開設できるのと同じように・・・

ユーザーが新規会員登録したと同時に、
ユーザーモデルと1:1の関係にあるアカウントモデルに
レコードを自動作成をしたいのですが、よくわからず困っています。

もう少し具体的に言うとこんな感じです。

ユーザーがdeviseでメールアドレスとパスワードを入力して会員登録を済ませます。
そして会員登録が成功したとき、自動的にアカウントが作成されます。
このとき、ユーザーは何も入力せずにアカウントテーブルに、
「user_id(ユーザーと紐づく為の外部キー)」
「アカウント番号(他のアカウント番号と被らないランダムな11桁の番号)」
「残高(デフォルトで0.00)」
という内容がつくられるようにしたいと考えています。

この場合、どんな実装をすればいいのか教えて頂ければ幸いです。

試しに書いたソースコード

model部分だけ書いてみました。

class User < ApplicationRecord
  has_one :account
  before_create :build_default_account
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  private
  def build_default_account
      build_account
      true
  end
end
class Account < ApplicationRecord
    belongs_to :user
    validates :user_id, presence:true



    def load_defaults
        #もしDBに保存されていない(新規登録)ならば、口座番号をランダムに作成する
        #もしDBに保存されていない(新規登録)ならば、残高を0にする。
        if self.new_record?
            self.account_number = SecurRandom.uuid
            self.balance = 0.00
        end
    end


end

補足情報(言語/FW/ツール等のバージョンなど)

Rails 5.1.3
ruby 2.4.1
devise (4.3.0)

アドバイスを参考に変更したファイル内容を追記(成功)

以下には、アドバイスを参考にコードを修正し、最終的に成功したコード内容を追記しておきます。

model.user.rbを編集。

class User < ApplicationRecord
  has_one :account

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end


model/account.rbを編集。

class Account < ApplicationRecord
    belongs_to :user
end


app/controllersにhoges_controller.rbを作成して編集。

class HogesController < ApplicationController


  def index
    @account = Account.all
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    @user.build_account #Userの子要素であるアカウントを関連付ける
    # インカムアカウントテーブルのaccount_numberのカラムに代入する
    @user.account.account_number = SecureRandom.random_number(1000000000000)
    @user.account.balance = 0
    @user.save
    redirect_to '/hoges/index'
  end

  private
    def user_params
      params.require(:user).permit(:password, :email)
    end

    def account_params
      params.require(:account).permit(:account_number, :balance)
    end
end


/app/views/hogeにindex.html.erbを作成して編集。

<p>index.html.erb</p>
<p>作成画面</p>

<%= form_for(@user) do |f| %>

<div class= "field">
  <%= f.label :email %>
  <%= f.email_field :email %>
  <%= f.label :password %>
  <%= f.password_field :password %>
  <%= f.submit "会員登録" %>
<% end %>
</div>


routes.rbに追記する。

Rails.Application.routes.draw do
・・・
  get 'hoges/index'
  get 'hoges/new'
  post 'users' => 'hoges#create'
・・・
end
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

前提条件として以下を上げます。

1.View側にはAccountの値を持たせず、controller側に値を書く
2.Deviseを利用ということでしたが、新規登録画面(hoge.html.erb)を別に作っているものとする

model/user.rb

class User < ApplicationRecord
  has_one :account

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end

model/account.rb

class Account < ApplicationRecord
    belongs_to :user
end

controller/hoge_controller.rb

class hogesController < ApplicationController
  def index
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    @user.build_account # Userの子要素であるAccountを関連付ける
    @user.account.account_number = ランダム数字を入れる # Accountテーブルのaccount_numberのカラムに代入する
    @user.account.balance = 0.00初期金額
    @user.save
  end

  private
    def user_params
      params.require(:user).permit(:password,
                                   :email)
    end
end

model側に書かれていますが、Controller側に書くようにしてください。

※参考
https://qiita.com/seimiyajun/items/cd398f741ac108cf11f8

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/03 11:01

    undefined method `build_default_account`
    そんなメソッドは存在していないって言ってますね。
    どこかスペルミスをしているようです。確認をお願いいたします。

    キャンセル

  • 2017/11/03 11:16 編集

    2017/11/03 10:22のアドバイスを試す前に、
    今一度、今回の質問で作成や変更をしたファイルを確認・再記入して
    ユーザー登録と実行してみたところ、
    うまくいったみたいです!

    データベースの中身を確認も
    ユーザーテーブルにはメールアドレスとパスワードが、
    アカウントテーブルには口座番号とuser_idと残高が
    作成されていました!

    ここまで助けて下さりありがとうございました!

    キャンセル

  • 2017/11/03 13:57

    はーい。良かったです。

    今回使った機能はアソシエーションというものです。
    https://qiita.com/To_BB/items/47d2c7b1bc3513025d7b
    https://qiita.com/seimiyajun/items/cd398f741ac108cf11f8

    また、View側でリレーションを使う方法や、has_manyにした時も
    記述が変わってきます。

    まずは書籍で何ができるのかを把握することもいいかもです。
    https://www.amazon.co.jp/Ruby-Rails-5アプリケーションプログラミング-山田-祥寛/dp/4774188832/ref=sr_1_1?ie=UTF8&qid=1509684888&sr=8-1&keywords=ruby+on+rails
    RoRは初心者向けではないので、大変かと思いますが頑張ってください。

    キャンセル

+1

以下のやり方でも解決することができます。
1.モデルの関連付けを行う
user(ユーザー)モデルは、basic_income_account(口座)モデルを一つ保有している1:1の関係にある。

#deviseで管理しているuserのモデル
class User < ApplicationRecord
  has_one :basic_income_account
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

end
class BasicIncomeAccount < ApplicationRecord
    #BasicIncomeAccountはuserから1:1の関係で所有されている
    belongs_to :user
end


2.deviseのコントローラを作成し編集(カスタマイズ)する
以下のコマンドでdeviseのコントローラを作成する。
rails g devise:controllers users

すると、app/controllers/usersに
deviseのコントローラファイルが作成されます。
この中には、いくつかのコントローラファイルがあるのですが、新規登録を司っている
registrations_controller.rbを編集します。
書き加える部分は、def createの部分。
1:1で親モデルが子モデルにデータをつくる(has_one)関係の場合、
resource.build_basic_income_account
変数.build_小文字単数形でかくモデル名
とすれば、いい。
あとは、
「変数.小文字単数系でかくモデル名.カラム名 = 記録したい値の処理」
という形で、子モデルに記録したいものを書いていき、
最後に、
変数.save
と書けばいい。

 class Users::RegistrationsController < Devise::RegistrationsController
  # before_action :configure_sign_up_params, only: [:create]
  # before_action :configure_account_update_params, only: [:update]
  # GET /resource/sign_up
   def new
     super
   end
  # POST /resource
   def create
     super
     #Userの子要素であるbasic_income_accountを関連付ける
     resource.build_basic_income_account
     #同時につくられるBI口座の登録内容
     require 'securerandom'
     n = 12
     resource.basic_income_account.account_number = format("%0#{n}d", SecureRandom.random_number(10**n))
     resource.basic_income_account.balance = 0
     resource.save
   end
  # GET /resource/edit
  # def edit
  #   super
  # end
  # PUT /resource
  # def update
  #   super
  # end
  # DELETE /resource
  # def destroy
  #   super
  # end
  # GET /resource/cancel
  # Forces the session data which is usually expired after sign
  # in to be expired now. This is useful if the user wants to
  # cancel oauth signing in/up in the middle of the process,
  # removing all OAuth session data.
  # def cancel
  #   super
  # end
  # protected
  # If you have extra params to permit, append them to the sanitizer.
  # def configure_sign_up_params
  #   devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
  # end
  # If you have extra params to permit, append them to the sanitizer.
  # def configure_account_update_params
  #   devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
  # end
  # The path used after sign up.
  # def after_sign_up_path_for(resource)
  #   super(resource)
  # end
  # The path used after sign up for inactive accounts.
  # def after_inactive_sign_up_path_for(resource)
  #   super(resource)
  # end
end

3.編集したdeviseのコントローラが使えるようにルーティング設定を行う

  devise_for :users, :controllers => {
    :registrations => 'users/registrations'
  }


これで、さっきカスタマイズしたdeviseのコントローラ(registrations_controller.rb)を読み取ってくれます。
以上の設定をすることで、deviseで新規会員登録をしたと同時に、
1:1の関係にあるBasicIncomeAccount(口座)モデルにもレコードを作成保存することができます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる
  • トップ
  • Rubyに関する質問
  • railsでユーザー新規登録(devise)をしたとき1:1の関係にある他のテーブルにデータを自動作成したい