LoginSignup
12

More than 5 years have passed since last update.

【ど忘れ御免】Ruby(とかRails)でアレってどうやるんだっけ?

Last updated at Posted at 2015-09-20

いやぁ、脳の劣化には敵いませんな。最近ではすぐにタイトルの状況に陥って嫌になります。
自分への戒めと備忘録を兼ねて、ど忘れする度にここに追記していきます。

ファイルへ文字列を出力するワンライナー

File.write('hoge.txt', 'aheahe')

引数の順番すぐ忘れます。

今のファイルから絶対パスを取得

base.rbというファイルに書かれたスクリプト内で、同じフォルダ内のhoge.txtの絶対パスを取得するには以下のようにします。

File.expand_path('../hoge.txt', __FILE__)

親クラス内のメソッドから子クラス内で定義された定数を参照

以下の様なクラスがあった場合

class Parent
  NAME = 'parent'
  def name
    NAME
  end
end

class Child < Parent
  NAME = 'child'
end

rubyではChild.new.nameを実行すると、期待に反してparentが返ります。
何故こうなるかは例によって忘れましたが、期待通りにchildが欲しければ、Parent#nameを以下の様に修正します。

def name
  self.class.const_get(:NAME)
end

いやぁ、脳の劣化には敵いませんな。最近ではすぐにタイトルの状況に陥って嫌になります。
自分への戒めと備忘録を兼ねて、ど忘れする度にここに追記していきます。

テーブルの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.rbdemo.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

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
12