rails関連の備忘録をまとめてく。
環境
$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]
$ rails -v
Rails 5.0.0.1
migrate
-add_column等のmigrate で NameError: uninitialized constant が出たとき。
- 型がintやvarcharではないか。integer、stringが正しい。
- migrationファイル名と実際の処理対象のテーブル名(model名)が違う場合。合わせる。
view
viewヘルパーのフォーマットは、options と html_options に別れてるのが曲者ですよね。。
# 例
select(object, property, choices, options = {}, html_options = {})
-form_for のオプションと、プルダウンのonChangeメソッド slimで
# GETメソッドでsubmit。
# form のidを指定。
= form_for @object, html: { method: 'GET', enforce_utf8: false, id: 'form_id' } do |f|
= select :status, :status, array, { selected: @selected_status, include_blank: 'all' }, {:onchange=> 'change_select();'}
※include_blank
は、プルダウンの先頭に空のoptionを入れるオプションだが、今回は「all」という文字列を先頭のoptionに出力している。本来prompt
でやることだが、プルダウン選択後のsubmitでロードした後になぜか prompt が効かずに非表示となったのでこの対処をとった。
-time_select を非表示にする
<%= f.time_select :flight_at_from, {}, {style: "display: none;"} %>
参考
http://apidock.com/rails/ActionView/Helpers/DateHelper/time_select
-中間モデルのcollection_select のCRUD
collection_selectの基本的な書き方。
serviceモデルとprefectureモデルの中間モデル。
<div class="field">
<%= f.label :prefecture_id %><br />
<%= collection_select :service_prefecture, :prefecture_id, Prefecture.all, :id, :name %>
</div>
参考
[Rails] has_many through (nested table)
-登録した改行をそのまま画面に表示
textarea等から複数行の文字列を入力した場合の表示。
simple_format
メソッドを使う。
<%= simple_format(text) %>
<!-- htmlエスケープしたい場合は html_escapeと合わせて。 -->
<%= simple_format(h(text)) %>
参考
Railsでタグをエスケープしつつ、改行を含む複数行のTextを表示したい - Qiita
-submit button押下時にdisableしてボタン名を変更するdata-disable-withオプション
<%= f.submit "送信する", data: { disable_with: "送信中..." } %>
参考: [Rails]submitタグにつけておきたいdisable_withオプション - Qiita
-link_toタブを使ってボタン名を改行させる
section tabを使用。
<%= link_to '#', class:"button " do %>
<section>
<p>登録!!</p>
<p class="sub-text">〜今月末まで</p>
</section>
<% end %>
参考:[Ruby on Rails] link_to の使い方 - Qiita
-date_selectで年月のみ表示する
discard_dayオプションをtrueにすると、日が非表示となる。
型はdate型で、日の値には「1」が入る。
<%= raw sprintf(
f.date_select(
:date_from,
use_month_numbers: true,
date_separator: '%s',
discard_day: true),
'年 ') + '月' %>
参考
- date_select - リファレンス - - Railsドキュメント
- Rails の date_select でつくるセレクトボックスを「年」「月」「日」で区切る - 彼女からは、おいちゃんと呼ばれています
-radio_buttonの書き方と初期値の設定
Userモデルの編集画面。
性別の初期値がmale、データが存在する場合はデータを反映する。
(sexカラムが必須の場合)
# sex :integer
class User < ApplicationRecord
enum sex: { male: 0, female: 1}
= simple_form_for(@user) do |f|
・・・
label
= f.radio_button :sex, :male, { checked: f.object.new_record? || f.object.male? }
= User.sexes_i18n[:male]
label
= f.radio_button :sex, :female
= User.sexes_i18n[:female]
ja:
enums:
user:
sex:
male: 男性
female: 女性
-HTMLタグをエスケープしつつ、連続改行も反映する
simple_format
では連続した改行がつぶされてしまう。
連続した改行も反映させるために、以下の処理を行う。
改行はmacでもwindowsでも対応できるように正規表現で。
= safe_join(news_mail_body.split(/\R/), tag(:br))
参考
- Ruby - <%= simple_format() %> で連続改行が反映されません(Railsです)|teratail
- Ruby で文字列を改行コードで区切る - valid,invalid
- Railsでタグをエスケープしつつ、改行を含む複数行のTextを表示したい - Qiita
slim
-JSとsassの記述
javascript:
function change_select(){
f = document.forms['form_name'];
f.submit();
}
sass:
.is-panel
display: inline-block
width: 30%
vertical-align: top
model
-オブジェクトの一時的な更新(保存はされない)。
コントローラ等でsaveする前に任意の変更を反映。
元のオブジェクトを画面に返す場合は reload
すること。
@object.assign_attributes(params)
@object.assign_attributes({key: 'value'})
参考
assign_attributes (ActiveRecord::AttributeAssignment) - APIdock
-nilまたは空白の場合に特定の値を返す
blank_or_value.presence || 'Value'
-オブジェクトの配列から条件にあったものを抽出する。
selectメソッド。
更新前のバリデーション等に使う。
class Group < ActiveRecord::Base
has_many :members
end
class Member < ActiveRecord::Base
belongs_to :group
end
# groupにはマネージャーが最低1人必要、とか。
group.members.select(position: :manager)
# [#Members]
参考
Rubyで条件に合う要素を抽出する方法:select, select!
- enumのi18n対応
enum_helpを使う。
# app/models/order.rb
class Order < ActiveRecord::Base
enum status: { "nopayment" => 0, "finished" => 1, "failed" => 2, "destroyed" => 3 }
end
# config/locales/ja.yml
ja:
enums:
license_holder:
status:
nopayment: 支払待ち
finished: 支払済み
failed: 支払失敗
destroyed: 削除済
# 使用方法
Order.statuses_i18n[:nopayment]
# => 支払待ち
# selectboxでの使い方
= f.select :status, Order.statuses_i18n.invert, {}, { class: 'select' }
Validation
-validationで、変更前の値をチェックする。
変更される前の値は「属性名_was」で取得する。
#Userモデルのnameカラムを「はなこ」から「たろう」へ変更。
user.name_was #たろう
#値の判定
return if user.status_was.to_sym == :unpublished
参考・ほか
Railsで変更前の値、型変換前の値、などなど
- 日付が正しいかチェックするカスタムバリデータを実装。
class DateValidator < ActiveModel::EachValidator
# 日付の値が入っているか、日付が正しいかを判定する。
def validate_each(record, attribute, value)
value.to_date
rescue
record.errors.add(attribute, options[:message] || 'が空か不正です。正しい日付を入力してください。')
end
end
validates :expires_on, date: true
参考
3.9. カスタムバリデータの作成 | 3. バリデーション(5) | TECHSCORE(テックスコア)
[Ruby] 例外処理を実装する時のrescue書き方3パターン - qiita
- validationを切り分ける
saveメソッドのcontextパラメータで切り分け。
updateにはcontextパラメータが無いので、attributesでデータを渡してからsaveメソッドを使う。
# user_controller
# password登録処理
def register_password
@user.attributes = user_params
if @user.save(context: :register_pass)
...
end
# userモデル
validates :password, presence: true, confirmation: true, on: [:register_pass]
validates :password_confirmation, presence: true, on: [:register_pass]
参考:Rails4でModelのvalidatesを切り替える - Qiita
Action Mailer
-メール送信時に条件(環境)によって処理を差し込む(Subjectに文言を追加する)。
モジュールに処理を書込み、 config/initializers
にそれを呼び出す処理を追加する。
# ElasticBeanstalk に設定した環境変数をsubjectの先頭に差し込む。
module Modulename
class EmailInterceptor
def self.delivering_email(message)
message.subject.insert(0, "[#{Rails.application.config.eb_env}]")
end
end
end
# config/initializers/mailer.rb
# 本番でない場合、差し込み処理を行う。
ActionMailer::Base.register_interceptor(Modulename::EmailInterceptor) unless Rails.application.config.rails_env == 'production'
参考:
- メールを配信直前に加工する
- Rails5: production環境でのAutoloadの廃止 - Qiita
-view のURL表示で使うhelper
xxx_path ではなく、xxx_urlを使う。
Rspec
-基本構成
RSpec.describe ObjectName, type: :model do
let(:user) { FactoryGirl.create(:user) }
describe 'hoge' do
before do
# devise でlogin
login_as(user, scope: :user)
end
context 'fuga' do
it 'is poyo' do
...
end
end
end
end
- マッチャメモ
# datetime を不等号で比較。
expect(hoge_at).to be >= Time.current
# datetimeの範囲確認。
expect(hoge_at.to_i).to be_within((Time.current - 1.minute).to_i).of(Time.current.to_i)
- login_asメソッドで
uncaught throw :warden
エラー
deviseのエラー。
createしたuserのデータが不正だった。
confirmed_atがnilだったため、値を入れてあげるとvisitできるようになった。
参考)ArgumentError: uncaught throw :warden が 出た場合 - Qiita
-Mock
- 基本系
特定のオブジェクトのメソッド(例えばAPIにリクエストするメソッド)の返り値をmock(又は任意の値)に置きかける。
mockのメソッドもmockか任意の値に置き換える。
api_mock = double('api mock')
allow(ApiObject).to receive(:method).and_return(api_mock)
allow(api_mock).to receive(:mock_method).and_return(api_mock)
allow(api_mock).to receive(:mock_method?).and_return(true)
参考
使えるRSpec入門・その3「ゼロからわかるモック(mock)を使ったテストの書き方」
- メソッドを通ったか確認
mock = double('mock')
allow(object).to receive(:method).and_return(mock)
expect(mock).to have_received(:method).once
-feature test
メモ
- visitしたページを確認
visit hoge_path
p page.html
- プルダウンの選択。
select [optionの表示名], from: [select name]
# 例
# select 'バナナ', from: 'fruits'
参考)Rspec + Capybara | の value を指定して選択状態にする - Qiita
- capybara で、hostを変更してアクセスする。
feature 'signup admin' do
given(:first_admin) { Admin.first }
before do
Capybara.default_host = 'http://admin.example.com'
Capybara.app_host = 'http://admin.example.com'
login_as(first_admin, scope: :admin)
end
# 終わったら戻すこと。
after do
ActionMailer::Base.deliveries.clear
Capybara.default_host = 'http://www.example.com'
Capybara.app_host = nil
end
参考)サブドメインを指定して、featureスペックを実行する - Qiita
gem
-devise
アカウント認証・セッション管理を行う。
-導入
rails g devise:install
を実行し、configファイルを作成。
コンソールに出てくる案内に従って設定。
rails g devise User
でUserモデルを作成。
参考:[*Rails*] deviseの使い方(rails5版) - Qiita
-複数モデルを管理していて、それぞれにviewのカスタマイズを行いたい場合。
config/initializers/devise.rb
で config.scoped_views = true
とすることで、モデルごとにviewのオーバーライドができる。
参考:https://github.com/plataformatec/devise#configuring-views
app/views/[model名]s/mailer/[メソッド名].html.erb
がメール文面となる。
が、subjectを分けるのはやや面倒そうなので、通常のaction_mailerを使うのが一番簡単な気もする。
-controller/view のカスタマイズ
# controllerの生成
$ rails g devise:controllers [model(スネークケース複数形)]
# viewの生成
$ rails g devise:views [model(スネークケース複数形)]
-devise.ja.ymlのダウンロード
I18n · plataformatec/devise Wiki から、自身のバージョンにあったものを確認。
又は以下。
devise-i18n/ja.yml at master · tigrish/devise-i18n · GitHub
# バージョンの確認
$ bundle show | grep devise
GistのRawボタンよりRawの画面に遷移し、URLをコピー、curlでダウンロード。
$ curl -s https://gist.githubusercontent.com/kaorumori/7276cec9c2d15940a3d93c6fcfab19f3/raw/a8c4f854988391dd345f04ff100441884c324f2a/devise.ja.yml -o config/locales/devise.ja.yml
-kaminari
viewに出力するオブジェクトの一覧をページングする。
- 基本形
# Controller
@objects = Object.page(params[:page]).per(10)
# view
# ページングリンクを表示。
<%= paginate @objects %>
<%# トータル件数と今表示している件数を表示。 %>
<%= page_entries_info @objects %>
# model
# 1ページあたりの表示件数を指定。デフォルトは25。
paginates_per 10
paginate
でエラーが出る場合は、 pagenate
と綴間違いしてないかチェック!!!(涙
- whenever
cronのbatchを生成するgem。
- バッチを実行する値を好きな値に設定する。
値を直に書かないといけないよう。
every '2,7,12,17,22,27,32,37,42,47,52,57 * * * *' do
command "cd /path/to/project && bundle exec rake hoge:fuga"
end
参考:ruby - whenever gem and scheduling a job every n min starting at an offset - Stack Overflow
- i18n
- 導入
デフォルトのロケールファイルをダウンロード。
curl -s https://raw.githubusercontent.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml -o config/locales/ja.yml
イニシャライザを作る。
I18n.available_locales = %i(en ja)
I18n.enforce_available_locales = true
I18n.default_locale = :ja
I18n.locale = :ja
- モデルから項目名(アトリビュート名)を参照する。
ja:
activerecord:
# モデル名
models:
user: 顧客
# モデルごとのアトリビュート名
attributes:
user:
name: 名前
address: 住所
# 全モデル共通のアトリビュート名
attributes:
created_at: 作成日時
updated_at: 更新日時
> User.model_name.human
=> "顧客"
> User.human_attribute_name(:name)
=> ”名前”
> User.human_attribute_name(:created_at)
=> "作成日時"
# 或いは、尋常に階層を書く。
> I18n.t('activerecord/attributes/user/name')
=> ”名前”
参考:あなたはいくつ知っている?Rails I18nの便利機能大全!|モデル名やモデルのアトリビュート名を取得する
-annotate
modelのファイルにschema情報を書き出してくれる。
rails g annotate:install
しておかないと、migrate時に更新されない。
# 導入
$ bundle exec annotate
# rakeファイル作成
$ bundle exec rails g annotate:install
# => create lib/tasks/auto_annotate_models.rake
-better_errors
導入
BetterErrors::Middleware.allow_ip! '0.0.0.0/0'
log
- less
コマンドに -R
オプションをつける。( -r
でもいい。)
railsのログにはデフォルトでANSIカラーのエスケープシーケンスがついているので、これを反映する。
less -R log/production.log
その他
-Object#presence メソッド
オブジェクトが存在する場合はオブジェクトを、存在しない場合は別の値を返す書き方。
name = params[:name].presence || '名無し'
参考
http://blog.livedoor.jp/sasata299/archives/51718602.html
-railsのパーシャルビューのみ抽出する
find app/views/www/ -type f -name '_*erb'
-ルーティングのパスをコンソールで確認。
pry(main)> m=Message.first
pry(main)> app.message_path(m)
=> "/messages/XXXXX"
参考:Rails でリンクパスを生成する方法色々・・とRails console で 生成される path を確認したい時 - Qiita
-datetime型のフォーマット設定
config/initializers/time_formats.rb
を作成。
Time::DATE_FORMATS[:default] = '%Y/%m/%d %H:%M'
Time::DATE_FORMATS[:datetime] = '%Y/%m/%d %H:%M'
Time::DATE_FORMATS[:date] = '%Y/%m/%d'
Time::DATE_FORMATS[:time] = '%H:%M:%S'
Date::DATE_FORMATS[:default] = '%Y/%m/%d'
> Time.now.to_s
=> "2014/03/03 15:22"
> Time.now.to_s(:date)
=> "2014/03/03"
> Time.now.to_s(:datetime)
=> "2014/03/03 15:23"
> Time.now.to_s(:time)
=> "15:23:07"