こちらに引っ越しました。
いやぁ、脳の劣化には敵いませんな。最近ではすぐにタイトルの状況に陥って嫌になります。
自分への戒めと備忘録を兼ねて、ど忘れする度にここに追記していきます。
テーブルのTRUNCATEを行う
ActiveRecord::Base.connection.execute('TRUNCATE TABLE `users`')
ActiveRecordのクエリキャッシュを使わずクエリを発行する
ActiveRecord::QueryCache.uncached
メソッドを使うと出来ます。
このメソッドはActiveRecord::Base
を継承したクラスなら普通に使えるので以下のようにできます。
User.uncached do
User.where(active: true).count
end
現在のDB名を取得する
Rails.configuration.database_configuration[Rails.env]["database"]
DB名に限らず他のDB周りの設定を取得できますね。
複数のseedファイルを作り、個別に実行できるようにする
通常はdb/seeds.rbに全テーブル用の処理を全部書くのですが、これを複数のseedファイルに分けて記述すると便利なことが有ります。
例えば、マスタ用データはmaster.rbに書いて、デモ用のデータはdemo.rbに書くなど。
そうしておくと、デモデータは残したままマスタだけ初期化するなんてことも可能で柔軟にデータのリセットが出来ます。
これを実現するには以下のようにします。
lib/tasks/multi_seed.rakeを以下の内容で作成。
namespace :db do
namespace :seed do
Dir[File.join(Rails.root, 'db', 'seeds', '*.rb')].each do |filename|
task_name = File.basename(filename, '.rb').intern
task task_name => :environment do
load(filename) if File.exist?(filename)
end
end
end
end
db/seedsディレクトリを作成し、その中にmaster.rbやdemo.rbなどを作成。
以下の様にして特定のseedを実行。(master.rbを実行する例)
rake db:seed:master
日本語localeファイルの有りか
MySQLでutf8mb4を使う
config/database.ymlを修正し、以下のようにencoding,charset,collationを設定。
default: &default
adapter: mysql2
host: localhost
username: hogehoge
password: fugafuga
encoding: utf8mb4
charset: utf8mb4
collation: utf8mb4_general_ci
pool: 5
timeout: 5000
database: pepepepe
config/initializers/ar_innodb_raw_format.rbを以下の内容で作成。
ActiveSupport.on_load :active_record do
module ActiveRecord::ConnectionAdapters
class AbstractMysqlAdapter
def create_table_with_innodb_row_format(table_name, options = {})
table_options = options.merge(:options => 'ENGINE=InnoDB ROW_FORMAT=DYNAMIC')
create_table_without_innodb_row_format(table_name, table_options) do |td|
yield td if block_given?
end
end
alias_method_chain :create_table, :innodb_row_format
end
end
end
TurboLinks無効化
-
Gemfileから
gem 'turbolinks'
を除去 -
app/views/layouts/application.html.erbから
'data-turbolinks-track' => true
を除去 -
app/assets/javascripts/application.jsから
//= require turbolinks
を除去
SMTPでメール送信する
mailcatcher使うときに設定します。
config/environments/development.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = { address: 'localhost', port: 1025 }
モデルのバリデーションエラーだけをrescueで捕捉したい
こんな感じですな。
def create
Comment.create(params[:comment])
rescue ActiveRecord::RecordInvalid
render :new
end
StrongParameterの使い方
コントローラ内で以下の様なメソッドを作ります。(例:ユーザーのパラメータをフィルタリングしたい場合)
private
def user_params
params.require(:user).permit(
:name,
:address,
{favorite_store_ids: []},
{photos_attributes: [:file, :file_cache, :filename]}
)
end
URLの後ろに#hogehogeみたいなハッシュ(フラグメント)をつける
hoge_path(@user, anchor: "hogehoge")
RESTfullなリクエストのIDにid
以外のカラムを使う
例えば、/users/1
みたいなURLじゃなくて、/users/yamada
みたいな感じのURLにしたい場合は、Userモデルにto_param
メソッドを実装する。
def to_param
name
end
↑これはname
カラムの値をIDとして使用する例。
メール送信時のURLヘルパーのオプションを動的に変更する
メールテンプレートView内でURLヘルパーを使うときのオプションは、environments/development.rbなどに
config.action_mailer.default_url_options = { host: 'example.com:3000', protocol: 'https' }
という形で設定します。
マルチテナント環境などでは、これを動的に変更したくなることが良く有ります。
その場合、適当な場所で以下のようにすると実現できます。
ActionMailer::Base.default_url_options[:host] = 'example.com'
ActionMailer::Base.default_url_options[:protocol] = 'https'
ActionMailer::Base.default_url_options[:port] = 3000
モデルの属性getterメソッドの挙動を変更する
とあるモデルにnameをという属性があるとして、それがDBに格納されている値をそのまま取得するのではなく、加工したい場合には以下の様にします。
class User < ActiveRecord::Base
def name
read_attribute(:name).upcase
end
end
これで、User.first.name
とかするとupcase
されたnameが取れます。
MySQLのTIME型カラムの値を文字列で取り出したい
(少なくとも)Rails4まではMySQLのTIME型カラムの扱いはあまり得意じゃないようです。
例えば、usersテーブルにlunch_timeというTIME型のカラムが有るとします。
usersテーブル
カラム名 | 型 | 値の例 |
---|---|---|
id | INT | 1 |
lunch_time | TIME | 10:00:00 |
そして、このテーブルにActiveRecordでレコードを以下のように保存するとします。
User.create(lunch_time: '10:00:00')
Rails4ではTIME型カラムに格納された値をActiveRecordはRubyのTime型として表現します。
User.first.lunch_time
=> 2000-01-01 10:00:00 UTC
見ての通り、勝手に2000-01-01なんて日付を付与してくれてますね。しかもタイムゾーンはUTC扱いです。
場合によってはこれはこれで便利なことも有るんですが、ここではシンプルに"10:00"という文字列で取得したいと思います。
方法としては上で紹介した、ゲッターメソッドの上書きテクを使います。
class User < ActiveRecord::Base
def lunch_time
read_attribute(:lunch_time).try(:to_s, :time)
end
end