記事一覧表示

Rails チュートリアル読んでみた(その4)

概要

前回の続きで、Rails チュートリアル(第12~14章)を読んだ時に取ったメモです。

第12章  パスワードの再設定


- rails generate controller コントローラ名 アクション名 ... --no-test-framework : コントローラの単体テストを作らないでコントローラを作成するコマンド




- モデルオブジェクト.errors.add(:カラム名, :blank) : モデルオブジェクトの特定のカラムにバリデーションエラー(今回は空だった時のエラー)を設定するメソッド




- response.body : リクエスト先のHTML本文を返すメソッド。テストで使用




- メイラーが作成するメール内容を構造的に取得する方法(主にテストで使用)
  • メールオブジェクト.subject : メールのタイトル取得。
  • メールオブジェクト.to : メールの宛先を取得。
  • メールオブジェクト.from : メールの送信元を取得。
  • メールオブジェクト.body.encoded : メールの本文を取得。





第13章  ユーザーのマイクロポスト


- % rails generate model モデル名 カラム名:データ型 ... モデル2名:references : モデル2とblongs_to関係を持つモデルを作成する為のコマンド




- default_scope -> { order(カラム名: :desc) } : モデル内に記述。テーブルのレコードの初期の並び順を特定のカラムの値の降順に変更する




- htmlの <ul> タグと <ol> タグはどちらもリストを作成するが、前者は順序無し、後者は順序付きでそれぞれリストを作成する




- test用テーブルのレコード(fixtures)にbelongs_to関係を紐付けるには test/fixtures/テーブル名.yml に以下のように記述。
シンボル名:
  カラム名:カラム2名: 値
     ︙
  belongs_to関係にあるテーブルAの単数形: 紐付けたいテーブルAのfixturesのシンボル名




- <%= render ‘パーシャルまでのpath’, パーシャル内での変数名: 渡す変数 %> : パーシャルに渡す変数の名前をパーシャル内で新しい変数名に変更する為の書き方




- request.referrer : 現在のリクエストのひとつ前のリクエストのURLを返すメソッド




- 画像の管理を行うアップローダCarrierWave の導入方法
  1. carrierwave , mini_magic , fog と言う3つのgemをbundleインストール。この時 fog gemは本番環境 :production グループのみにインストール1
  2. % rails generate uploader アップローダー名(キャメルケース) コマンドでアップローダapp/uploaders/アップローダー名(スネークケース)_uploader.rb を作成。
  3. 画像データを保存するモデルAに picture というstring型のカラムを作成。
  4. モデルAの pictureアップローダーを紐付けるために app/models/モデルA.rbmount_uploader :picture, アップローダー名(キャメルケース)Uploader を記述。
  5. railsサーバーを再起動。具体的には % spring stop コマンド実行後に rails console を実行。

 <%= form_forのイテレータ.file_field :picture %> : フォームの file_field タグに picture を渡す事で画像投稿フォームを作成。
 <%= image_tag モデルAのレコードオブジェクト.picture.url if モデルAのレコードオブジェクト.picture? %> : image_tagpicture.url を渡す事で画像を表示。 picture? メソッドは、レコードオブジェクトの picture カラムに画像データがあるかどうかを判定するメソッドであり、アップローダーに付随して作られる。
 picture.size : アップロードされたファイルのバイト数を返すメソッド。


- アップローダCarrierWave にアップロード出来るファイルの形式を制限する方法

 app/uploaders/アップローダー名(スネークケース)_uploader.rb に書かれている以下の部分をコメントアウトする。

class PictureUploader < CarrierWave::Uploader::Base
   ︙
  def extension_whitelist
    %w(jpg jpeg gif png)
  end
   ︙
end

 次に、画像投稿フォーム(form_forのfile_fieldタグ)にacceptオプションで受け付けるファイル形式のMIMEタイプを記述する。例えば、受け付けるファイル形式がjpeg、gif、pngだった場合は、以下のようになる。

<%= form_forのイテレータ.file_field :picture, accept: ‘image/jpeg,image/gif,image/png’ %>




- validate :validationメソッド名 : オリジナルのvalidationをモデル内で宣言する方法。モデル内でvalidationメソッドを作り、そのメソッド内でカラム判定を行い、条件に合わない値が入った時、 errors.add(:カラム名, “エラーメッセージ”) のようにエラーメッセージを作成する事が出来る




- アップローダCarrierWave にアップロードされた大きい画像を自動リサイズする方法
  1. 開発環境に ImageMagick をインストール。LinuxOSの場合は % sudo yum install -y ImageMagick で。
  2. app/uploaders/アップローダー名_uploader.rb に以下を書き込む。
class PictureUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  process resize_to_limit: [400, 400]
    ︙
end

 MiniMagickImageMagick ツールを Ruby で操作するためのgem。上のプログラムはアップロードされた画像サイズの横か縦が400pxを超えた時に、適当なサイズにリサイズしてくれる物である。他の操作方法はこことかここを参照。


- アップローダCarrierWave のリサイズ機能をテストの時は無効に設定する方法

 config/initializers/skip_image_resizing.rb に以下のように記述。もっと詳しく知りたい場合はドキュメント参照。

if Rails.env.test?
  CarrierWave.configure do |config|
    config.enable_processing = false
  end
end




- 本番環境(heroku)でのアップロード画像の保存先をAWSのS3(クラウドストレージ)にする方法2

 1. app/uploaders/アップローダー名(スネークケース)_uploader.rb のアップロード画像の保存形式 strage :file を本番環境で fog を使用するために以下のように書き換える3

class PictureUploader < CarrierWave::Uploader::Base
   ︙
  if Rails.env.production?
    storage :fog
  else
    storage :file
  end
   ︙
end

 2. AWSのS3にIAMユーザを設定。
 3. config/initializers/carrier_wave.rb に以下を記述4

if Rails.env.production?
  CarrierWave.configure do |config|
    config.fog_credentials = {
      # Amazon S3用の設定
      :provider              => 'AWS',
      :region                => ‘S3REGION’,
      :aws_access_key_id     => ‘IAMユーザのACCESS_KEY’,
      :aws_secret_access_key => ‘IAMユーザのSECRET_KEY’
    }
    config.fog_directory     =  ‘S3バケット名’
  end
end

 4. git heroku master を更新。





第14章  ユーザーをフォローする


- テーブルAがテーブルB(関係付け)を介してテーブルAのレコードを取得するリレーション関係の作成

f:id:ooutimatuki:20181031204640p:plain
 上図のように、テーブルAのレコード同士がある関係性(テーブルBの関係性a関係性b)で結びついている時、そのリレーションモデルは、以下のように作成する。

 1. app/models/モデルA.rb に以下の内容を書く。上図の赤矢印の関係を構築。

  has_many :シンボル名, class_name:  “モデルB”,
                                  foreign_key: “関係性a_id",
                                  dependent:   :destroy

 2. app/models/モデルB.rb に以下の内容を書く。上図の青矢印の関係を構築。

  belongs_to :関係性a, class_name: “モデルA”
  belongs_to :関係性b, class_name: “モデルA

 3. app/models/モデルA.rb に以下の内容を書き加える5。上図の赤矢印の結果からの青矢印の関係を構築。

  has_many :シンボル2名, through: :シンボル名, source: :関係性b
  • テーブルAのレコードオブジェクト.シンボル名 : テーブルBのレコードの内、レコードオブジェクトの id関係性a_id が一致するレコード群を取得。
  • テーブルAのレコードオブジェクト.シンボル名.build(関係性b_id: テーブルAのidの値) : レコードオブジェクトのidと紐付いたテーブルBのレコードオブジェクトを作成。まだ、テーブルには追加していない。
  • テーブルBのレコードオブジェクト.関係性a or 関係性b : テーブルAのレコードの内、レコードオブジェクトの 関係性a or 関係性b_idid が一致するレコードを取得。
  • テーブルAのレコードオブジェクト.シンボル2名 : テーブルAのレコードの内、レコードオブジェクトの id とテーブルBの関係bを持つ全てのレコード群(青矢印の先の全てのレコード)を取得。配列なので、include?メソッドなどが使用可能。
  • テーブルAのレコードオブジェクト.シンボル2名 << テーブルAの別のレコードオブジェクト : テーブルBに新しいレコードを保存。実際にテーブルに反映済み。



- resources (RESTfulリソース)に新たにリソース・id付きリソースを割り当てる方法( config/routes.rb に以下を追加)
  • リソース( コントローラ名/アクション名 )の場合
  resources :コントローラ名 do
    collection do
      get or post :アクション名
    end
  end
  • id付きリソース( コントローラ名/id/アクション名 )の場合
  resources :コントローラ名 do
    member do
      get or post :アクション名
    end
  end




- テストで取ってきたページコードは文字列なので assert_select ページ上のタグ, text: レコードのカラム値(string型以外)assert_match レコードのカラム値(string型以外), response.body などは型が違うのでエラーになる。テーブルから取ってきた値の後ろには to_s メソッドを必ず付けるべし




- form_for の処理をAjaxを使った非同期処理に変える(コントローラの処理をページの遷移無しに別プロセスにやらせる)方法

 1. form_forremote: true タグを追加6
 2. 対応するアクションに以下のコードを最後に追加。

  def アクション名
   ︙
    処理内容
   ︙
    respond_to do |format|
      format.html { redirect_to 元のページ }
      format.js
    end
  end

 3. config/application.rb に以下のコードを追加し、ブラウザ上でJavaScriptが無効になっていた場合に対応する。

   ︙
module Railsアプリ名
  class Application < Rails::Application
   ︙
    config.action_view.embed_authenticity_token_in_remote_forms = true
  end
end

 4. app/view/コントローラ名/対応するアクション名.js.erb にアクション処理後にページ内で書き換えたいコードをJavaScriptで書く。書き方は以下。

$(“書き換えたいHTML要素をCSSの文法で指定”).html("<%= アクション処理後のコードを記述 %>");




- escape_javascript(エスケープするコード) : 与えられたコードをjavascriptの文法でエスケープする(コード内の特殊文字を普通の文字として扱う)為のerbメソッド。このメソッドを使う理由はここを参照。




- テスト上で、Ajaxの非同期処理に対してリクエストを作成する時は post リクエストパス ..., xhr: true のように、xhr (XmlHttpRequest) オプションをtrueに設定する




- モデル名.where(“カラム名 = #{変数}”) と書いた場合、変数の値に不正なSQLコードを書かれると、アプリ内でその実行を防ぐことが出来ない7。なので モデル名.where(“カラム名 = ?”, 変数) と書いて変数の中身をエスケープ(SQLコードに必要な特殊文字の打ち消し処理)をさせ、実行を防ぐ方法がある。また、変数の中身が配列の場合、丸括弧で囲って (?) のように書く




- テーブルから取得する条件文(Where句やHaving句)に他のテーブルから取得したレコード群を使用する場合は、サブクエリを作成し、テーブルに接続する回数を一回のみにすると処理速度が速くなる




- ActiveRecordメソッド : モデル(データベース)へアクセスする為のメソッド
  • order(:カラム名) : テーブルのレコードの順序をカラム名の値の昇順に並び替える。
  • take(数値) : テーブルの最初から数値分のレコードを取得。


- 便利なヘルパー
  • time_ago_in_words(タイムスタンプ) : タイムスタンプが示す時刻と現在の時刻との差分( 14 minutes とか about 1 years など)を返すメソッド。
  • fixture_file_upload(‘test/fixtures/ファイル名’, ‘ファイルの保存形式’) : test/fixtures 内のファイルをアップロードするメソッド。 ファイルの保存形式 にはアップロードするファイルに該当するMIMEタイプを記入。

  1. mini_magic は、画像をリサイズするgemで、 fog は、本番環境に画像をアップロードするためのgemである。

  2. このページを参照。

  3. strage :file はアップロード画像をローカルのファイルシステムrailsでは public/uploads/ 内)に保存し、 strage :fog はfogと言うクラウドシステムの操作を行う為のソフトウェアを使って、クラウドシステムに保存する。

  4. S3のREGIONは、このページを参照。

  5. has_many :関係性bの複数形, through: :シンボル名 のように source: を省く事が出来るが、呼び出す時に使うメソッド名が関係性bの複数形になる。

  6. remote: true 追加により生成されるHTMLコードには data-remote=“true” タグが追加される。このタグはrailsJavaScriptによるフォームの操作を知らせる。これにより、本来非同期処理に必要であるJavaScriptのコードをView内に書かずに済んでいる。

  7. SQLインジェクション