bootstrap datepickerで土日の色を変えるよ!
気がついたら、また前回更新から一ヶ月の時が過ぎてしまっていました…
この一ヶ月間は転職したり引っ越ししたりとかなりバタバターっとしていて割と人生的に変換期に入ってきている感があります…!
今回はbootstrap datepickerについて書いていきたいと思いますー!
ちょっと開発をしていてカレンダーから日付入力したいなーと考えた時にお手軽に実装できると噂のbootstrap datepickerを導入しました。
それで土日だけ色を違う色にしたいなーと思ったりして色々調べたものの日本語記事であまり情報がなかったので今回の題材にしようかなーと思いました。
(今回もRails開発の中での導入なのでGemを使って導入していたりしますがご愛嬌ということで…)
bootstrap datepickerを導入するよ!
1. Gemfileに追記
gem 'bootstrap-datepicker-rails'
2. bundle install
3. application.jsに追記
//= require bootstrap-datepicker/core //= require bootstrap-datepicker/locales/bootstrap-datepicker.ja.js
とりあえず言語は日本語だけで良いのこんな感じ
4. application.cssに追記
*= require_self *= require bootstrap-datepicker3 *= require_tree .
これで一通り準備は完了!
bootstrap datepicker使ってみるよ!
javascript
$(document).ready(function(){ $('.datepicker').datepicker(); });
HTML
<div class="input-group"> <!-- erbの書き方なので注意 --> <%= f.text_field :input_date, class: "form-control datepicker" %> </div>
とりあえずちょいちょいっとこんな感じで書くと下のような感じになります!
とはいえかなり質素感が半端ないですね…
せめて土日だけでもわかりやすくなってほしい…
土日に色をつけるよ!
ということで土日に色をつけましょう!
まずはjavascriptを改良
javascript
$(document).ready(function(){ $('.datepicker').datepicker({ beforeShowDay: function(date) { var myDate = new Object(); if (date.getDay() == 0) { myDate.enabled = true; myDate.classes = 'class-sunday'; myDate.tooltip = '日曜日'; } else if (date.getDay() == 6) { myDate.enabled = true; myDate.classes = 'class-saturday'; myDate.tooltip = '土曜日'; } else { myDate.enabled = true; myDate.classes = 'class-weekday'; myDate.tooltip = '平日'; } return myDate; } }); });
beforeShowDay
を設定することで日付表示の前に処理を行ってくれる。
ここの感じだとobjectにenabled
, classes
, tooltip
を設定できるとのこと。
今回大事なのはclasses
です!
これを使うことで色を変えたい曜日を判別します。
まずカレンダーに表示される日にちは1日単位でtd要素と成っているということを念頭に置いておいてください。
一日ごとにbeforeShowDayをみて処理を行います。
そこでif (date.getDay() == 0)
みたいな感じで日にちと謎の数字を判定しています!
この謎の数字は日〜土
を表していて0〜6
で表現されます。
なので0だったら日曜日の処理、6だったら土曜日の処理、それ以外は平日の処理をやってね!ということになります。
で次に設定する内容についてです。
enable
とtooltip
は本質じゃないので割愛で…
大事なのはclasses
でこれに設定した値は一日単位で生成されるtd要素のclassとして追加
されます。
そしてclassが追記されることでスタイルを当てることができるようになります!
.class-sunday { color: red !important; } .class-saturday { color: blue !important; }
これをcssで記入してやることで
こんな感じで土日に色がつきちょっとおしゃれな感じになりました!
おまけ
入力フォームをちょっとおしゃれにする
<div class="input-group"> <%= f.text_field :input_date, id: "date-area", class: "form-control datepicker" %> <label for="date-area" class="input-group-btn"> <span class="btn btn-success"><i class="fa fa-calendar"></i></span> </label> </div>
bootstrapと合わせることでちょっとおしゃれなdatepickerの入力フォームができてしまいます!
bootstrap datepickerというだけありbootstrapとの親和性は高いですね!
さて今回はbootstrap datepickerについて書きました。
探してた時は藁にもすがる思いでしたがわかってみると意外となんてことないコードでした。
こういう微妙にハメられる系を見つけ次第どんどん記事にしていこうと思います(また次は一ヶ月後かなあ…笑)
【Rails】Ajaxでセレクトボックスの内容を動的に変更する
こんばんは!1週に一回記事更新しますわ〜とか言っておきながら1ヶ月ぶりの更新です…笑
今回の内容は2つのセレクトボックスがあった時に片方のセレクトボックスが変更されたら、もう片方のセレクトボックスで選択できる内容が動的に変更されると言った内容です!
概要だけだと何言ってるかわけわからないと思うので例を挙げると、県と市区町村が選択できるセレクトボックスがそれぞれ存在する時に、県を選択したら市区町村のセレクトボックスの方が選択された県に存在する市区町村が選択肢になるようなイメージです。
どう作ればいいかわからない状態から作ったのでかなり時間がかかったので備忘録がてら書いときます
想定
とりあえずテーブル構造はこんな感じ
prefecturesとcitesとマスタテーブルとしていて存在していて、そんでprofilesに住んでいる県と市区町村が登録されるみたいな想定
ビュー
new.html.erb
<%= form_for(@profile) do |f| %> <% if @profile.errors.any? %> <div id="error_explanation"> <ul> <% @profile.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %> <div class="prefecture-area"> <%= label :prefecture_id %><br> <%= collection_select :profile, :prefecture_id, Prefecture.all, :id, :name %> </div> <div class="city-area"> <%= render partial: 'select_city', locals: {prefecture_id: Prefecture.first.id} %> </div> <% end %>
_select_city.html.erb
<%= label :profile, :city_id %><br> <%= collection_select :profile, :city_id, Prefecture.where(prefecture_id: prefecture_id), :id, :city_name %>
動的にセレクトボックスを入れ替えるcity_idの方はselect_city
という名前でパーシャル化。
パーシャル化することでAjaxで返ってくる結果をレンダリングしやすくしとく。
コントローラ
class ProfilesController < ApplicationController def new @profile = Profile.new end # Ajax処理を行う処理 def get_cities render partial: 'select_city', locals: {prefecture_id: params[:prefecture_id]} end end
セレクトボックスを動的に変える処理をget_cities
というアクションで受け取る。
Ajaxでこのアクションを呼ぶ。
ルーティングは以下の感じで
Rails.application.routes.draw do resources :profiles, only: :new do collection do get 'get_cities' # /profiles/get_cities end end end
モデル
今回の記事の本質からは外れるので割愛します。
だいたいテーブル構造で想像してください。
Coffee Script
セレクトボックスを動的に変えるのはAjaxを使って実現するためcoffeeやjavascriptが肝になる。
ここがいまいちわかっていなかったので色々詰まっていた…
$(document).on 'change', '#profile_prefecture_id', -> $.ajax( type: 'GET' url: '/profiles/get_cities' data: { prefecture_id: $(this).val() } ).done (data) -> $('.city-area').html(data)
$(document).on 'change', '#profile_prefecture_id'
この処理でprefecture_idのセレクトボックスが変更されたことを検知する。
profile_prefecture_id
はcorrection_selectで自動生成されるid。correction_selectというよりForm系のヘルパーで生成される。
$.ajax( type: 'GET' url: '/profiles/get_cities' data: { prefecture_id: $(this).val() }
ここでAjaxの通信を開始している。type
にメソッド、url
に呼び出すアクションのパス、data
にコントローラに渡す値を設定する。
今回のdata
はセレクトボックスで選択された値をparams
にprefecture_id
として乗せる。
done(data)
でアクションの結果を受け取る。今回のアクションはprofiles
コントローラのget_cities
アクションでget_cities
の中身はrender partial: 'select_city', locals: {prefecture_id: prefecture_id}
なので_select_city.html.erb
をレンダリングした結果を受け取る。
アクションの処理結果はdata
に格納されている。
ここのdata
は$.ajax
でコントローラに渡したdata
とは別もんな気がするので注意。
$('.city-area').html(data)
でレンダリングされたHTMLソースを<div class="city-area">
内に差し込むことでセレクトボックスを入れ替える。
ここまでやることでセレクトボックスの入れ替えが実現できました!
いざ記事にしてみると大して難しいことはやっていないのだけど、初めて実装する機能などはやはり難易度が高いように感じてしまう…。
こうやって色々試して、ブログなんかで知識を蓄積して慣れていくしかないですかね…。
うわぁ、がんばろう
【Rails】enumをI18n対応させるenum_helpが便利すぎた
Railsでの開発を通して色々なgemを教えてもらったりして常に目から鱗状態という最近の事情です。
その中でenum_help
というenum
をI18n化するgemが個人的に簡単かつ便利だなーと思ったのでご紹介です!
まずenumとは何者か
enum
は0を男性, 1を女性
のように数字を何かしらの値と紐付けているようなデータの管理をしている場合に非常に有効なものです。
例えばUserモデルで性別をgenderで管理している場合に男性を0, 女性を1としていると想定
class User < ActiveRecord::Base enum gender: { male: 0, female: 1 } end
このように書くと
# genderに0を設定している場合 user.gender => "male" # genderに1を設定している場合 user.gender => "female"
こんな感じでgender
を数字ではなく、文字列で扱うことができるようになって直感的になるし、色々と便利ヘルパーが付加されるので、こんな感じのデータ構造を取っている際は積極的に設定するべき!(ただRails4.1から導入された機能っぽい)
enumをI18n対応させたい!
user.gender
と書いて"male"や"female"とでるのは素敵だけど、日本語で"男性", "女性"と表示させたいと日本人の僕的には思うわけですよ…
ただ素の状態のenum
をI18n化するのは若干面倒くさそう…
そこででてくるのがenum_help
という便利gemです!!
使い方も簡単でenum_help
を導入してlocalesを設定するだけ!
enum_helpを導入しよう!
1. まずは例のごとくGemfile
に導入するgemを追記する
gem 'enum_help'
2. bundle install
3. localファイルに追記
config/locales/ja.yml
ja: enums: user: gender: male: 男性 female: 女性
4. あとは呼び出すだけ!
呼び出すときはenumを設定している属性を呼び出す際に◯◯_i18n
とするだけ!
# genderに0を設定している場合 user.gender_i18n => "男性" # genderに1を設定している場合 user.gender_i18n => "女性"
これでenumのI18n化は完了なんです!
本当にgem入れて、locales設定するだけでenumのI18n化ができちゃうので簡単ですね!
おまけ
enum_help
を設定すると便利ヘルパーが付与される
# 設定しているenumをハッシュで展開 user.genders_i18n.invert => {"男性"=>"male", "女性"=>"female"}
ビューでselect_boxを設定する際などに重宝します!
もっといろんなgemとか覚えて、効率的にRails開発をできるように精進したい今日この頃。
RSpecの基本的な部分を勉強してみた
ブログだいぶサボってました…。
いよいよまずいと思ったので久々に更新です。
今回はRSpecについてだらっと書きます。
Ruby on RailsでWebアプリを作る営みをしているのですが、テストをかなりおざなりにしていた+テストの書き方がイマイチわからない状態というブログ更新を滞ったよりもまずい状況だったので勉強しました。
ざっくり学んだことをもはや個人的なメモとしてだらだら書いていきます。
がっつり理解できているわけではないので内容的に曖昧なところもあるので悪しからずです…。
RSpecとはなんぞや?
Rubyのテストフレームワークの一つで、テストを書くのに特化したDSLとかいうやつみたいです。
RSpecを使うために
- rspec --initで.rspecとspecディレクトリが作成される
- テストを記述したファイルはspecフォルダに格納
- xxxx_spec.rbみたいなファイル名にする
- テスト実行はrspecコマンドを使用する
- -fdオプションをつけるとテスト毎の成否が見れるようになる
RSpecの基本的な書き方
RSpec.describe "テスト名(クラス名とか)" do before do end it "テストケース(メソッドとか)" do end it "テストケース" end
beforeメソッド
- テスト実施前の初期処理を書く(インスタンス生成とか)
- beforeで生成した変数は変数の前に@をつけてインスタンス変数のように宣言する必要あり
- beforeの引数には:exampleと:contextがある
- :exampleは各exampleの前に実行される(引数省略で:exampleとなる)
- :contextはdescribeの中の最初の一回目に実行される
example
- it 〜 endのこと(1テストケースを指す?)
- itはexample / specifyと書くことも可能
- テストケースのところに書く文と文脈があうようなものを適宜選択する
- ブロックを記載しないとpending(棚上げ)となる
describe / context
- テスト対象を指定する(exampleのグループ化ができる)
- describeもdescribeの中で入れ子にできる
- トップレベルのdescribeはクラス名を書く
- describeと同様に使うことができる
- describeが物、contextが状況という使い分けをする
matcher
期待する振る舞いを指定する記号を指す
matcher一覧
- eq(x):xと等しいか
- not_eq(x):xと等しくないか
- be [true/false]:trueかfalseか
- be < x:xより小さいか
- be_between(x, y).inclusive:数値がxとyの範囲内か(xとyも範囲に含む)
- respond_to(:{メソッド名}):そのメソッドが存在しているか
- Rubyの特徴を生かした書き方
- 例として結果がintegerかどうか調べるテスト を書く
expect(obj.add(2,3).integer?).to be true
上記の書き方を
expect(obj.add(2,3)).to be_integer
と書くことができる
- 例として結果がintegerかどうか調べるテスト を書く
subject
RSpec.describe Sample do it { sample = Sample.new expect(sample.add(2, 3)).to eq(5) } end
これを
RSpec.describe Sample do it { expect(subject.add(2, 3)).to eq(5) } end
にできる。
しかし、このままだとテストケースが長くなった時にsubject
ってなんだっけとなってしまうので以下のように書く。
RSpec.describe Sample do subject(:sample) { Sample.new } it { expect(sample.add(2, 3)).to eq(5) } end
subject
にシンボルを渡して{}内でnewしてやるとsample
をインスタンスとして使えるようになる。
before
を使えば良いじゃないかという話もあるがbefore
だとexample内でインスタンス変数を使う必要が出るためsubject
の方がスッキリする。(好みの問題的な側面もあるらしいが…)
method stub
メソッドをまだ実装していないけどテストに使用したいよーという場合に使う。
ex)Userモデルから名前を取得するnameメソッドを使いたいけどまだできてないよーっていう場合
RSpec.describe Sample do it { #test doubleの呼び出し #doubleの引数はなくても良いが失敗した時などに便利なので書いておく user = double('user') #nameメソッドが呼び出されたら強制的にtanakaを返すようにする allow(user).to receive(:name).and_return('tanaka') sample = Sample.new expect(sample.add(5, user.name)).to eq('5 by tanaka') } end
message expectation
呼ばれなかったらテストが失敗する。
ある処理の前に確実にある処理が走っていることを保証したい場合に使用する。
ex)ログの処理を書いていなけどログを書く処理が各区実に呼ばれたかテストしたいよーっていう場合
RSpec.describe Sample do it { #ロガーのtest doubleを作成する logger = double('logger') #loggerのlogメソッドが呼ばれていることを確認する expect(logger).to receive(:log) #sampleクラスでloggerインスタンスを使用する想定 sample = Sample.new(logger) expect(sample.add(5, user.name)).to eq('5 by tanaka') } end
あー、久々に記事書きましたー。
文章書くのは訓練しないとどんどん書けなくなりますね…
これからは週に最低1記事を目標にブログ頑張ります!
ドットインストールで快適に学習するために『Dotinstall Pane』を使ってみた
プログラミング初心者の強い味方といえば『ドットインストール - 3分動画でマスターする初心者向けプログラミング学習サイト』がありますね。
動画を見ながらプログラミングを学習するサイトで、学べる内容が豊富でどれから手をつければいいのかしら?となるうれしい悲鳴が上げられる感じのサービスです。
学習の方法としては動画でやっていることを写経して、実行してを繰り返す感じ。
ただ写経して、実行のためにブラウザを立ち上げて〜という動作を繰り返すのは割とだるい印象。
ただ最近ドットインストールのメルマガで『dotinstall-pane』なるものを知り、取り入れてみたところ結構便利だったので紹介していこうかと思った次第。
Atomをインストールする
まず『dotinstall-pane』はテキストエディタ『Atom』のプラグインなので『Atom』を導入する。
自分はMacを使用しているのでMacのインストール方法を記載する。
- 公式サイトにアクセスする。http://atom.io/
- 公式サイトにある『Download For Mac』ボタンをクリックする。
- ダウンロードしたファイルを解凍する。
- 解凍したファイルをアプリケーションフォルダに配置する。
これでインストールは完了!
windowsの場合は以下のサイトが参考になります。
Windows - テキストエディタ「Atom」のインストール - 開発メモ - Webkaru
また『Atom』はデフォルト英語なので、日本語化したい場合は以下を参考にすると良さげ。
Atom の日本語化パッケージ "Japanese Menu" を作りました - syonx
『Dotinstall Pane』を導入する
『Atom』のインストールが完了したら本題の『dotinstall-pane』を導入する。
※日本語化を行っているので操作項目がデフォルトの状態とは若干異なります。
まずAtomを起動し、ツールバーの『Atom > 環境設定』を選択する。
環境設定画面に遷移したら、サイドバーから『インストール』をクリックする
その後パッケージの検索バーに『dotinstall』と入力しエンターを押すことで検索をかける。
検索をかけると『dotinstall-pane』が出てくるので『install』ボタンをクリックしてインストールする。
これで『Dotinstall Pane』の導入完了です!
『Dotinstall Pane』を使用する
さて導入が終わったらいよいよ使ってみる!
使用方法はすごく簡単で
Macなら『Option + Shift + D』
Windowsなら『Alt + Shift + D』
上記のキーをエディタ画面で押すだけ!!
するとエディタの横にドットインストールの画面が出てきちゃいます!
これで動画みながら学習が効率よくできるようになります!
さらに便利にするために
公式ブログ『http://blog.dotinstall.com/post/139045656660/dotinstallpane』にもありますが、『atom-html-preview』を導入すると学習効率がかなり上がります。
『atom-html-preview』ってなんぞやとなりますが、これはエディタ上でショートカットキーを押すことでブラウザでの見え方を簡単に確認できるプラグインです。
導入方法は『Dotinstall Pane』と同様にツールバーの『Atom > 環境設定』と進み、サイドバーで『インストール』を選択する。
その後検索バーに『atom-html-preview』と検索して、『install』ボタンをクリックしてインストールします。
[
使用方法はエディタでHTMLを記述して、
(このソースはjQuery入門第6回授業のものになります)
エディタにフォーカスを当てつつ、ショートカットキー『Ctrl-Shift-H』を入力するだけ!
するとピョロっと右側にブラウザでの見え方が表示されます!
この二つのプラグインを導入することで学習効率がすごい上がった気がします!
特にHTML,CSS,javascript系の学習効率が跳ね上がります。
プログラミングに興味がある人はこれを導入して学習を始めるのもありっぽいかも。
jQueryでアコーディオンパネルを作る
最近javascriptを使えないと世の中的にやばいんじゃないかと思いjQueryを勉強し始めました…。
勉強してる中でアコーディオンパネルを作ったわけなんですが、想像以上に簡単に実装できちゃう感じを知り若干感動したのでブログ化です。
(これで感動しているあたり素人感丸出しなのは内緒。)
今更こんなん記事にします?っていう指摘は言わないであげてください。笑
アコーディオンパネルってなんや
アコーディオンパネルはクリックするとクリックした項目の下に文字なんかがスライドで出てきて、もう一回クリックするとスライドしてもとに戻るやつです。
説明下手すぎてイメージつかないですね。
つまりこんな感じのやつです。
初期表示
でこれの一番上の項目をクリックすると
こんな感じでクリックするとヌルッと出てくるやつです。
もう一回同じ項目をクリックすると初期表示の状態に戻ります
とりあえず作ってみよう
ということでまずはHTMLとCSSを作ります。
HTML
<ul id="accordion mdl-list"> <li class="accordion-item mdl-list__item"> <h3 class="question">職業はなんですか?</h3> <span>+</span> <div class="answer"> <p>システムエンジニアです。いわゆるSEです。</p> </div> </li> <li class="accordion-item"> <h3 class="question mdl-list__item">なんのスポーツが好きですか?</h3> <span>+</span> <div class="answer"> <p>野球</p> </div> </li> <li class="accordion-item mdl-list__item"> <h3 class="question">携帯は何使ってますか?</h3> <span>+</span> <div class="answer"> <p>iPhone</p> </div> </li> </ul>
初期に表示されている箇所がh3要素、出たり隠れたりする箇所が<div class="answer">~</div>
の部分になります。
CSS
ul { list-style: none; } .accordion-item { position: relative; width: 400px; border-bottom:1px solid #ccc; cursor: pointer; margin-top: 5px; } .accordion-item:hover { background-color: #E6E6E6; } .question { font-size: 18px; margin: 0; padding: 0; } .accordion-item span { position: absolute; top: 5px; right: 5px; color: #B3B3B3; font-size: 20px; } .answer { display: none; font-size: 12px; }
初期表示の状態では出たり隠れたりする部分をdisplay: none;
で画面に表示されないようにしておきます。
javascriptを書くッッ
さてアコーディオンパネルを実現するためのjavascriptを書きます。
とはいってもjQueryを使うとすごくさっくりした記述で処理が書けちゃいます!
$(function() { $('.accordion-item').click(function(){ //出隠れする部分を変数に格納しておく var $answer = $(this).children('.answer'); //hasClassメソッドで出隠れする部分にopenが存在するか確認 if ($answer.hasClass('open')) { //出隠れ部分が出ている場合の処理 //<div class="answer open">からopenを消す $answer.removeClass('open'); //出ている部分をスライドアップして隠す $answer.slideUp(); //横っちょにある開閉ボタンを+に変える $(this).children('span').text('+'); } else { //出隠れ部分が隠れている場合の処理 //<div class="answer">にopenを追加する $answer.addClass('open'); //出す部分をスライドダウンして表示させる $answer.slideDown(); //横っちょにある開閉ボタンを-に変える $(this).children('span').text('-'); } }); });
<div class="answer">
にopenを追加することで開いたり、隠したりする感じ。
openを追加することでCSSに記載しているdisplay: none;
が無効になったり、有効になったりするイメージかしら。
とはいえたった10行前後で良く見るあのアコーディオンパネルさんを実現できるのはちょっと感動。
Ruby on Railsを極めつつ、javascriptも極めていきたいっすなあ。
とはRailsさんはcoffeescriptだからまた勉強が必要やが…。
そのうちcoffeescript備忘録つくろ
Railsで関連モデルを同時に更新したい(has_oneで関連させていたモデルをbuild_associationで安直に生成しようとしたら痛い目をみた話)
Railsで関連モデルを同時に更新するようなコードを書こうとして、思いの外ハマって抜けられなくなったので備忘録。
関連モデルを同時に更新したい状況
例えばメールアドレスやパスワードのような認証情報と、生年月日や趣味のようなプロフィール情報を分けて管理したい場合など結構ありがちだと思います。 以下のような関連を持つモデルのようなイメージ。
とりあえず書いてみる
ひとまず自分の思うがままにコードを書いていく。
まずモデルから。
app/models/user.rb
class User < ActiveRecord::Base has_one :profile, dependent: :destroy accepts_nested_attributes_for :profile end
app/models/profile.rb
class Profile < ActiveRecord::Base belongs_to :user end
親モデルのUserにaccepts_nested_attributes_for
を設定することで親モデルから子モデルを作成したり、保存したりできるようにする。
次にコントローラ。
app/controllers/users_controller.rb
class UsersController < ApplicationController before_action :set_user, only: [:show, :edit, :update, :destroy] def index @users = User.all end def show end def new @user = User.new end def edit @user.build_profile end def create @user = User.new(user_params) @user.save redirect_to :users end def update @user.update(user_params) redirect_to :users end def destroy @user.destroy redirect_to :users end private def set_user @user = User.find(params[:id]) end def user_params params.require(:user).permit(:email, :password, profile_attributes: [:birthday, :hobby]) end end
viewでfields_for
を使うのでprofile_attributes
をストロングパラメータに記入しておく。
(fields_for
は[引数に与えた名前]_attributes
というname属性になるためらしい)
仕様としてプロフィール情報を入れるのはユーザ情報編集時のみとするため、登録しているUserモデルからProfileモデルを生成できるようにedit
に@user.build_profile
と何気なく記入。
親から子を生成するときはとりあえずbuildっしょとかいう素人考えでbuild_profileを記入したが 、後にどツボへの道へと誘うことになるとはこの段階では知る由もなかった…。
とりあえず次にビュー。
app/views/_form.html.erb
<%= form_for(@user) do |f| %> <% if @user.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2> <ul> <% @user.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= f.label :email %><br> <%= f.text_field :email %> </div> <div class="field"> <%= f.label :password %><br> <%= f.password_field :password %> </div> <% unless current_page?(new_user_path) %> <%= f.fields_for :profile, @user.profile do |pf| %> <div class="field"> <%= pf.label :birthday %><br> <%= pf.date_field :birthday %> </div> <div class="field"> <%= pf.label :hobby %><br> <%= pf.text_field :hobby %> </div> <% end %> <% end %> <div class="actions"> <%= f.submit %> </div> <% end %>
プロフィール情報はnewのタイミングでは表示させないようにcurrent_page?
を設定。
fields_for
のタグを<%= %>
ではなく<% %>
で記入してプロフィール情報入力欄出ない問題にも軽くハマっているのは内緒の話。
これでとりあえず一通り完成!
てことで動作確認
ユーザを登録
次にプロフィール情報を入力するために編集
いい感じにプロフィール情報を入力できるようになっている。
とりあえずプロフィール情報を入力。
登録できたか確認
いい感じに登録できている。
しかし、問題が起きる…
登録までできて、「いやー、ひと仕事終わったよ」と清々しい気分でいましたが、再び編集画面を表示した際に違和感を覚える。
あれ…?プロフィール情報が表示されてなくね…?
いやいや、まさかそんなはずは…と思い、再びshowしてみるとProfileモデルなんて存在してねーけど…と怒られる。
DBも確認してみたが、profilesテーブルがまっさらになっている…
>> Profile.all Profile Load (0.5ms) SELECT "profiles".* FROM "profiles" => #<ActiveRecord::Relation []>
さっきまで存在していたプロフィール情報がどこか遠い国に旅立ってしまっている…
登録し直したり、デバッグしてみたりで原因を探ること小一時間。
問題点があらわになる。
@user.build_profile
を実行した後にレコードが消えている…!!!!!
サーバログを見てみると
Started GET "/users/8/edit" for ::1 at 2016-02-07 12:12:38 +0900 Processing by UsersController#edit as HTML Parameters: {"id"=>"8"} User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 8]] Profile Load (0.2ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."user_id" = $1 LIMIT 1 [["user_id", 8]] (0.1ms) BEGIN SQL (0.2ms) DELETE FROM "profiles" WHERE "profiles"."id" = $1 [["id", 7]] (2.0ms) COMMIT Rendered users/_form.html.erb (3.0ms) Rendered users/edit.html.erb within layouts/application (4.2ms) Completed 200 OK in 38ms (Views: 20.1ms | ActiveRecord: 2.7ms)
なんかDELETEが走っちゃってますけど!!!!
どうもbuild_profile
でProfileモデルを生成の際は一旦存在するレコードを消してから生成みたいなことが起きているっぽい。
ということでbuild_profile
を使わないように修正。
def edit @user.profile = Profile.new if @user.profile.blank? end
てな感じで無事プロフィール情報を登録してから編集画面にいっても情報が消えなくなりました。
とりあえず関連モデルを生成するならbuildじゃね?という安易な考えを悔い改めようと思いましたまる