20210124のRailsに関する記事は22件です。

undefined method `upload' for nil:NilClassが出た時の解決法

今回のエラー

image.png

きっかけ

S3を作成中のアプリに導入しようとしたところ、このエラーが出ました。

結論

開くべきシェルが間違っていた。

S3を導入する際には、環境変数を指定しなければならないのですが、その際にvimメソッドのインサードモードの中に記述したのですが、その時にターミナルに

ターミナル
vim ~/.zshrc

としなければならないところを

ターミナル
vim ~/.zshr    

と打ち込んで、その中に記述していました。
要するにスペルミスですね。
散々原因を探した後だったので、「今更スペルミスなんか見逃すかよ」、とスペルミスの可能性を削除していたが故のミスでした。これからはもっと謙虚な気持ちでエラーと向き合っていきます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsのpresentメソッドの使い方

presentメソッドとは

オブジェクトであるレシーバーの値が存在すればtrue、存在しなければfalseを返すメソッドです。条件分岐(if文等)をプログラムで書くときによく使います。

例えばアプリの購入機能において「もし選択した商品に紐づく購入記録が存在していたら(空ではなかったら)、"sold out"と表示する」を実装したい場合は該当のビューファイルにおいて

index.html.erb
<% if item.purchase.present? %>
<div class='sold-out'>
<span>Sold Out!!</span>
</div>
<% end %>

という様に記述します。

<% if item.purchase.present? %>の部分ですが
itemモデルとpurchaseモデルにテーブル間のアソシエーションが組んであれば
商品(item)に紐づく購入記録(purchase)が存在していたら(空ではなかったら)=true
という解釈になります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsのpresent?メソッドの使い方

present?メソッドとは

オブジェクトであるレシーバーの値が存在すればtrue、存在しなければfalseを返すメソッドです。条件分岐(if文等)をプログラムで書くときによく使います。

例えばアプリの購入機能において「もし選択した商品に紐づく購入記録が存在していたら(空ではなかったら)、"sold out"と表示する」を実装したい場合は該当のビューファイルにおいて

index.html.erb
<% if item.purchase.present? %>
<div class='sold-out'>
<span>Sold Out!!</span>
</div>
<% end %>

という様に記述します。

<% if item.purchase.present? %>の部分ですが
itemモデルとpurchaseモデルにテーブル間のアソシエーションが組んであれば
商品(item)に紐づく購入記録(purchase)が存在していたら(空ではなかったら)=true
という解釈になります。

以下のサイトにはpresent?メソッドと逆のblank?メソッドも紹介されています。

参考:https://techacademy.jp/magazine/20214

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActionMailerを使用した問い合わせ機能の実装

実装機能

問い合わせフォームからメールを送信、それを指定したメールアドレスで受信する。
(アプリの利用者から管理者に向けてのメール機能として実装)

ActionMailerでは他にもメルマガ配信のように運営側からユーザーに対してメール送信を行ったり、問い合わせに対するメールの返信機能なども実装が可能とのことだが、今回は一番シンプルなこちらの機能を実装。
またGmailアカウントでのメールの受信方法の為、前提としてGmailのアカウントを持っている体で話を進めていく。

完成イメージ

スクリーンショット 2021-01-24 18.46.45.png

実装内容

1.コントローラの作成

使用するビューファイルはnewのみな上にルーティングの修正が面倒な為、アクションの指定はせずにコントローラファイル単体で作成。

$ rails g controller inquiries

2.ルーティングの作成

今回使用するアクションは以下の2つ
・問い合わせ作成画面に使用するnewアクション
・問い合わせのデータを作成する為のcreateアクションのみ

config/routes.rb
resources :inquiries, only[:new, :create] 

3.モデルの作成

最低限必要な情報としてユーザーの名前とメッセージ内容を保存するカラムを用意するが、今回は送信したユーザーが問い合わせに関して返答を要求する場面を想定し、emailのカラムも作成しておく。

$ rails g model Inquiry name:string email:string message:text

マイグレーションファイルに特に変更がなければ bundle installを実行してテーブルを作成。

その後必要なカラムにバリデーションをかけておく。

app/models/inquiry
class Inquiry < ApplicationRecord
  validates :name, presence: true
  validates :email, presence: true
  validates :message, presence: true
end

4.Mailerの作成

ActionMailerという機能がRailsに標準搭載されており、下記のコマンドで作成が出来る

terminal
$ rails g mailer inquiry 

以下のファイルが作成されるのを確認

terminal
create  app/mailers/inquiry_mailer.rb
invoke  erb
create    app/views/inquiry_mailer
invoke  test_unit
create    test/mailers/inquiry_mailer_test.rb
create    test/mailers/previews/inquiry_mailer_preview.rb

このうちのinquiry_mailer.rbは、メール送信機能を実装するための空のクラス

5.Mailerにメソッドを定義

InquiryMailer内でメソッドを定義する。
ここで定義したメソッドを実際にデータの作成、送信を実行するInquiriesコントローラ内で使用する

app/mailers/inquiry_mailer.rb
class InquiryMailer < ApplicationMailer

  def send_mail(inquiry)
    @inquiry = inquiry
    mail to: 'メールアドレス', subject: '【サイト名】お問い合わせ通知'
  end
end

上記のmailメソッドで指定されているプロパティの内容は以下の通り
to = 送信先(メールアドレス)の指定
subject = メールの件名

要はここで指定したアドレスから指定した件名でメールが届くということなる。

6.コントローラにメソッドを定義

app/controllers/inquiries_controller.rb
class InquiriesController < ApplicationController

  def new
    @inquiry = Inquiry.new
  end

  def create
    @inquiry = Inquiry.new(inquiry_params)
    if @inquiry.save
      InquiryMailer.send_mail(@inquiry).deliver 
      redirect_to new_inquiry_path
      flash[:email] = "Your message was successfully sent."
    else
      render 'new'
    end
  end

  private

  def inquiry_params
    params.require(:inquiry).permit(:name, :email, :message)
  end
end

アクション内の処理の流れは通常の投稿作成とほぼ同じだが、createアクション内の処理で先程作成したInquiryMailerのメソッドを使用する。

InquiryMailer.send_mail(@inquiry).deliver 

コードの文末にあるdeliverメソッドはメールの送信に関わるメソッドになる。
因みに、当然の事ながらこの行の処理が完了するまで以降のredirect等の処理が行われない為、フラッシュメッセージが現れるまで数秒間掛かることもある。
それを回避する為にActiveJobと連携して非同期にメール送信を行う為のdeliver_laterというメソッドも存在するらしいが、今回はこちらを採用。

7.development.rbにメール送信設定を記述する

ドメインの指定等の設定をconfigディレクトリ配下のdevelopment.rbファイルに記述する。

config/environment/development.rb
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address: 'smtp.gmail.com',
    port: 587,
    domain: 'gmail.com',
    user_name: 'メールアドレス',
    password: 'パスワード',
    authentication: 'plain',
    enable_starttls_auto: true
  }

このあたりはこちらの参考記事の説明がわかりやすかったのでそのまま引用させて頂くことにする。

ここでは、config.action_mailerというパラメーターに色んなオプションを指定してます。
1行目 raise_delivery_errors
メールの送信に失敗した時にエラーを出すかどうか (出したいので true)

2行目 delivery_method
メールの送信方法。 デフォルトで :smtd なので気にする必要もないのですが、
わたしみたいに「なにそれ!?」ってなった方は以下の引用を読んでみてください。

「SMTP」とは「Simple Mail Transfer Protocol(シンプル・メール・トランスファー・プロトコル)」の略で、あえて>訳せば「簡単なメールの送信の手順」というところだろうか。お約束ごとと考えてもいい。

あなたがメールを書き、宛先のアドレスを入力して「送信」アイコンをクリックする。このとき、あなたのスマホやパソコン>は、この「SMTP」のお約束ごとに従って、あなたが契約しているメールサーバーと、こんなやり取りをするのである。
「メールを送るよ〜」「ええで!」「宛先は〇◯だよ」「りょ」「本文はかくかくしかじかだよ」「受け取ったで!」――とまぁそんな具合。

出典: メール設定で最初につまずく「SMTP」「POP」「IMAP」。その意味&設定方法は?

3行目 smtp_settings
smtpの詳細設定って感じです。

port => SMTPサーバーのポート番号
address => SMTPサーバーのホスト名
domain => HELOドメイン
user_name => メール送信に使用するgmailのアカウント
password => メール送信に使用するgmailのパスワード
authentication => 認証方法
enable_starttls_auto => メールの送信にTLS認証を使用するか

※前項のMailerやここで使用するメールアドレスやパスワードはGithubにpushする際には環境変数化しておく必要があるので注意

8.ビューを作成する

問い合わせフォーム用のビュー画面を作成する。
コードは冒頭で添付した画面で使用したものなので、ご自身のアプリに合わせて作成。
通常のフォーム画面の作成と変わらないはず。

app/views/inquiries/new.html.erb
:
  <div class="contact_form text-center">
    <%= form_with model: @inquiry, local:true do |f| %>
    <%= render 'layouts/error_messages', model: f.object %>
      <h3>NAME</h3>
      <%= f.text_field :name %>
      <h3>EMAIL</h3>
      <%= f.email_field :email %>
      <h3>MESSAGE</h3>
      <%= f.text_area :message %>
    <div>
      <p><%= f.submit "送信" %></p>
    </div>
    <% end %>
  </div>
:

9.メール画面を構成するファイルを作成

上記とは別に実際に送られてくるメールのレイアウトを構成するファイルも作成する必要がある。
ActionMailerのコマンドを実行した際にviewsディレクトリの中にinquiry_mailerディレクトリが作成されているため、そこにファイルを作成する。
今回はアプリの管理者が受け取る想定の為、構成には必要最低限しか気を配っていない。

因みに場合によってはHTML形式のメールを受け取ることができない場合もあるらしく、そのためテキスト形式のファイルも用意しておくのがベスト。

HTML形式

app/views/inquiry_mailer/send_mail.html.erb
<h5>お問い合わせ内容</h5>

<P>-----------------------------------------</P>

<p>名前:<%= @inquiry.name %></p>

<p>メールアドレス:<%= @inquiry.email %></p>

<p>お問い合わせ内容:<%= @inquiry.message %></P>

<p>-----------------------------------------</p>

テキスト形式

app/views/inquiry_mailer/send_mail.text.erb
お問い合わせ内容

-----------------------------------------

名前:<%= @inquiry.name %>

メールアドレス:<%= @inquiry.email %>

お問い合わせ内容:<%= @inquiry.message %>

-----------------------------------------

実際に届くメール画面がこちら(HTML形式)

スクリーンショット 2021-01-24 21.22.33.png

10.環境変数を使用

Githubにpushしたり、本番環境でアプリを使用する際はこれまでに使用したメールアドレスやパスワードはセキュリティを考慮し環境変数化しておく必要がある。
gemのdotenv-railsをinstallしている前提での説明な為、gemをインストールしていない場合は導入する。

.envファイルに実際のメールアドレスやパスワードを記述

.env
SEND_MAIL="使用するメールアドレス"
GMAIL_PASSWORD="使用するGmailアカウントのパスワード"

定義した環境変数をコード内で使用

app/mailers/inquiry_mailer.rb
:
    mail to: ENV['SEND_MAIL'], subject: '【サイト名】お問い合わせ通知'
:
config/environment/development.rb
:
    user_name: ENV['SEND_MAIL'],
    password: ENV['GMAIL_PASSWORD'],
:

.envファイル.gitignoreファイルに記述して完了

補足

gmailのアカウントの設定の関係でアクション実行の際に以下のようなサーバーエラーが発生する可能性がある。

Net::SMTPAuthenticationError (535-5.7.1 Username and Password not accepted. Learn more at
Net::SMTPAuthenticationError 534-5.7.9 Application-specific password required.

上記エラーが現れた際は、別途Gmailアカウントの設定変更が必要となる可能性が高い(パスワードやメールアドレスのスペルミス等の可能性もあるため、まずはそこを疑う)。
個人的には実装よりもむしろこれらのエラーの解消に手こずったので、参考になれば。

参考記事

ActionMailer参考記事
Action Mailer でメール送信機能をつくる
【Rails入門説明書】Action Mailerについて解説
サーバーエラーの解決のために使用
Googleで2段階認証を使っているときにRailsのActionMailerでGmailを使う方法
[Rails5]deviseでgmailを送ろうとしたがsmtp認証のエラーが出た時にした事。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ユーザー登録時のウィザード形式に変更

はじめに

オリジナルアプリ制作にあたり、ユーザー登録時にウィザード形式(対話するように順番に操作が進んでいく方式)を用いるように変更しました。
ウィザード形式にすることで、ユーザーからすると見やすく使いやすいとのことだったため、変更することにしました。

変更前はユーザー登録と本人確認が以下の画像のように一緒の画面にある状態。
1ページが縦長になってしまい、少しわかりづらい。(スクショにも全部納まっていないし…。)
なので、今回はユーザー情報登録画面と本人確認登録画面に2ページに分けていきたいと思います。

変更前・変更後のテーブルの状態

変更前 
現状、会員情報入力と本人確認が同じテーブルになっている。
・Userテーブル

Column Type Options
nickname string null: false
email string null: false
password string null: false
last_name string null: false
first_name string null: false
last_name_kana string null: false
first_name_kana string null: false
phone_number string null: false


変更後 
ウィザード形式にするために以下の形にテーブルを変更したい。
・Userテーブル(viewでは会員情報入力画面)

Column Type Options
nickname string null: false
email string null: false
password string null: false

・Identificationテーブル(viewでは本人確認入力画面)

Column Type Options
last_name string null: false
first_name string null: false
last_name_kana string null: false
first_name_kana string null: false
phone_number string null: false
user      references optional: true

1.テーブル・モデルの変更・追加

1.Userテーブルの不要なカラム(last_nameやphone_numberなど)を以下のコマンドで削除していく。
完了したらマイグレート(rails db:migrate)を実行する。

ターミナル
% rails g migration Removeカラム名From削除元テーブル名 削除するカラム名:型
↓ 
(例)
% rails g migration RemoveLastNameFromUsers last_name:string

2.Identificationモデル・マイグレーションファイルを作成する

ターミナル
% rails g model identification

3.作成したIdentificationのマイグレーションファイルを編集し、マイグレート(rails db:migrate)を実行する。

2021***********_create_identifications
class CreateIdentifications < ActiveRecord::Migration[6.0]
  def change
    create_table :identifications do |t|
      t.string :last_name,          null: false
      t.string :first_name,         null: false
      t.string :last_name_kana,     null: false
      t.string :first_name_kana,    null: false
      t.string :phone_number,       null: false
      t.references :user
      t.timestamps
    end
  end
end

4.Identificationモデルを編集する。

app/models/idetification.rb
class Identification < ApplicationRecord
  validates :phone_number, presence: true, length: { maximum: 11 }, format: { with: /\A[0-9]+\z/, message: 'ハイフンは必要ありません' }
  with_options presence: true, format: { with: /\A[ぁ-んァ-ン一-龥]+\z/, message: '全角文字を使用してください' } do
    validates :first_name
    validates :last_name
  end
  with_options presence: true, format: { with: /\A[ァ-ン]+\z/, message: '全角カナを使用してください' } do
    validates :first_name_kana
    validates :last_name_kana
  end

  belongs_to :user, optional: true 
end

4.Userモデルを編集する。
userテーブルとidentificationテーブルは1対1の関係なのでhas_oneを使用。

app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  # 中略
  has_one :identification #追記
end

2.ルーティングの変更

本人確認を登録するページを表示するnew_identificationと情報を保存するcreate_identificationを追記する。

app/config/routes.rb
Rails.application.routes.draw do
  devise_for :users, controllers: {
    registrations: "users/registrations",
  }
  #以下を追記する。
  devise_scope :user do
    get 'identification', to: 'users/registrations#new_identification'
    post 'identification', to: 'users/registrations#create_identification'
  end
  # 中略
end

3.Userコントローラーの変更

1.ユーザー情報登録に関するコントローラー追記

app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
  def new
    @user = User.new
  end

  def create
    @user = User.new(sign_up_params)
    render :new and return unless @user.valid?
    session['devise.regist_data'] = { user: @user.attributes }
    session['devise.regist_data'][:user]['password'] = params[:user][:password]
    @identification = @user.build_identification
    render :new_identification
  end
end

render :new and return unless @user.valid?
 →ユーザー登録情報の送られてきたパラメータがバリデーションに引っかかっていないかを確認している。

session['devise.regist_data'] = { user: @user.attributes }
session['devise.regist_data'][:user]['password'] = params[:user][:password]
 →ユーザー登録情報をsessionに保持させている。
  1行目だけでは、パスワード情報が含まれていないため、2行目でパスワード情報を保持させる。

@identification = @user.build_identification
render :new_identification
 →buildで次の本人確認で使用するインスタントを生成し、そのページで遷移させている。

2.本人確認登録に関するコントローラー追記

app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
  #中略
  def create_identification
    @user = User.new(session['devise.regist_data']['user'])
    @identification = Identification.new(identification_params)
    render :new_identification and return unless @identification.valid?
    @user.build_identification(@identification.attributes)
    @user.save
    session['devise.regist_data']['user'].clear
    sign_in(:user, @user)
    redirect_to root_path
  end

  private
  def identification_params
    params.require(:identification).permit(:last_name, :last_name_kana, :first_name, :first_name_kana, :phone_number)
  end
end

render :new_identification and return unless @identification.valid?
 →本人確認情報の送られてきたパラメータがバリデーションに引っかかっていないかを確認している。

@user.build_identification(@identification.attributes)
@user.save
 →本人確認情報と先ほどsessionに保持していたユーザー登録情報を保存している。

session['devise.regist_data']['user'].clear
 →保存が完了し、sessionに保持していたユーザー登録情報が不要になったので、削除している。

sign_in(:user, @user)
redirect_to root_path
 →ログインし、トップページに遷移している。

4.viewの変更

1.views/devise/registrationsに本人確認を登録するためのviewファイル(new_identification.html.erb)を作成する。
views / devise / registrations / new_identification.html.erb

2.作成したnew_identification.html.erbに本人確認用の入力フォームを記述していく。

views/devise/registrations/new_identification.html.erb
<%= form_with model: @identification, url: identification_path, method: :post, local: true do |f| %>
<div class='form-wrap'>
  <div class='form-header'>
    <h1 class='form-header-text'>
      本人確認
    </h1>
  </div>
  <div class="form-group">
    <div class='form-text-wrap'>
      <label class="form-text">お名前(全角)</label>
      <span class="indispensable">必須</span>
    </div>
    <!-- 中略 -->
  </div>
  <div class='hoge-btn'>
    <%= f.submit "会員登録" ,class:"hoge-btn" %>
  </div>
</div>
<% end %>

5.ウィザード形式に変更完了

これで、ユーザー情報登録画面と本人確認登録画面の2ページに分けることが出来た。
ユーザー情報登録画面

本人確認登録画面

最後に

今回の実装を通して、deviseのことも一緒に学ぶことが出来ました。
これまでdeviseはユーザー登録をするための便利なgemという認識しかなくsessionなどといった知識がほとんどなかったため、いい機会になりました。

参考

以下の記事を参考にさせて頂きました。ありがとうございました。
sessionについて https://qiita.com/nakanishi03/items/51ff2ade4cec078280d6
ウィザードについて https://qiita.com/Tatsu88/items/7447a669b788b011e96b

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

listen tcp 0.0.0.0:xxx: bind: address already in us の対処法

目的

Ruby on Railsでポートフォリオを作成していた途中にdocker-compose upをした際に、listen tcp 0.0.0.0:xxx: bind: address already in usとエラーが出たのでその時の対処方法を忘れないように書きます。

エラー内容

$ docker-compose up -d
-------------------------
-------------------------
Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use
ERROR: Encountered errors while bringing up the project.

対処方法

最初にこのコマンドを打ちます。

$ sudo lsof -i -P | grep "LISTEN"

name1   633      ~~~~~~   10u  IPv4 0xc46fc72c3028ba51      0t0  TCP localhost:49362 (LISTEN)
name2   634      ~~~~~~   53u  IPv6 0xc46fc72c50688ca1      0t0  TCP *:3000 (LISTEN)
name3   96145    ~~~~~~   54u  IPv6 0xc46fc72c506892c1      0t0  TCP *:3306 (LISTEN)
name4   72412    ~~~~~~   82u  IPv4 0xc46fc72c4cf4e591      0t0  TCP localhost:62741 (LISTEN)

エラー内容は3306ポートはすでにあるよと言われています。
なので3306ポートをkillします。

$ sudo kill -9 96145

これでdocker-compose upができます!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pg_hba.confファイル内のクライアント認証の優先順位

「現場で使える Ruby on Rails 5 速習実践ガイド」のChapter 6-9-3 「production環境用のデータベースを作成する」で詰まったのでメモ書きします。

実行環境

PostgreSQL 10.15
Ruby 2.7.1
Vagrant 2.2.9
CentOS 7.8.2003

問題点

production環境用のデータベースを作成する以下のところでエラー発生

RAILS_ENV=production bin/rails db:create db:migrate

原因はPostgreSQLのユーザー認証がパスワード認証になっていないことのようだった。

修正点

修正にはpg_hba.confというファイルを書き換えてパスワードを使った認証ができるように、設定する必要があるようだった。

ユーザーtaskleafはパスワード認証、元々使っていたユーザーvagrant, rootはそのままにしておきたかったので、できないか調べたところ、pg_hba.confは上方にある記述が優先されるとの記載があった。

接続形式、クライアントアドレス、要求されたデータベース、およびユーザ名に一致する最初のレコードが認証処理に使用されます。

リンク:日本PostgreSQLユーザ会

以下のようにmd5(パスワード認証にするための設定)の行を追加、
vagrant, rootユーザーは元のとおりpeerに設定して意図どおり修正できた。
修正前

pb_hba.conf
# listen on a non-local interface via the listen_addresses
# configuration parameter, or via the -i or -h command line switches.
local   all             all                                     peer

修正後

pb_hba.conf
# listen on a non-local interface via the listen_addresses
# configuration parameter, or via the -i or -h command line switches.
local   all             vagrant                                 peer
local   all             root                                    peer
local   all             all                                     md5
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsにおけるSQLインジェクション対策について - Rails Tutorial リスト13.46

はじめに

Rails Tutorialを進めていく中で気になったところを記事にして残してます。

記事に間違いがある場合は教えてください:grin:

用語解説

SQLインジェクションとは

SQLインジェクションは、Webアプリケーションのパラメータを操作してデータベースクエリに影響を与えることを目的とした攻撃手法です。SQLインジェクションは、認証をバイパスする目的でよく使われます。他にも、データを操作したり任意のデータを読み出したりする目的にも使われます。

Rails セキュリティガイド - Railsガイド

つまり、ログインフォームや投稿フォームなどでSQLのデータを処理する際に、不正(サーバーからみると正常)なデータが実行されてしまうことです。
これによってログイン偽装やデータの抜き取りが起こります。

エスケープ処理とは

「'」「"」「NULL」「改行」などのSQL文において都合の悪い文字を使えなくすることです。

悪い例

不正に認証が通ってしまう

以下のコードでログイン処理をするとしましょう。

User.find_by("login = '#{params[:name]}' AND password = '#{params[:password]}'")

一見問題はなさそうに見えますが、もし以下のパラメータが入っていたとします。

params = { name:     "' OR '1'='1",
           password: "' OR '2'>'1" }

これを実行すると以下のようなSQL文が呼ばれることになります。

SELECT * FROM users WHERE login = '' OR '1'='1' AND password = '' OR '2'>'1' LIMIT 1

要約すると1=1, 2>1が成り立つ時usersから1人取り出してくださいということです。
ログインとしての機能を果たさなくなってしまいました。

原因

こうなってしまう原因はエスケープ処理をしていないからです。

対策

対策としてSQL文を書くときには直接文字列を代入するのではなく、必ずエスケープ処理をするようにしましょう。

エスケープ処理には以下の方法があります。

  1. 配列、ハッシュとして渡す。(モデルのインスタンスのみ)
  2. sanitize_sql()を使う。(それ以外)

対策1

モデルの場合はこちらが楽です。

# 配列
Model.where("login = ? AND password = ?", entered_user_name, entered_password).first

# もしくはハッシュ
Model.where(login: entered_user_name, password: entered_password).first

対策2

sanitize_sqlというメソッドでエスケープできます。

# 3つの例
sanitize_sql(["name=? and group_id=?", "foo'bar", 4])

sanitize_sql(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])

sanitize_sql("name='foo''bar' and group_id='4'")

参照

Rails セキュリティガイド - Railsガイド
ActiveRecord::Sanitization::ClassMethods - Rails API

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

bundle exec

bundle exec をつける時

bundle execをつけずにrailsコマンドを叩くと、デフォルトのrailsが動く
bundle execをつけると、そのプロジェクトで管理している(rbenvなどのバージョンを管理してくれるもの)rails が動く

bundlerとは
そのプロジェクトのgemを管理しているよ
bundle install をするとgemfileの中身が読み込まれる

参考:https://qiita.com/d0ne1s/items/fa2dafcee02e963fe997

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

refileで画像を複数投稿したい!

今回はrefileで画像を複数投稿できる機能を作ります。
調べたところ、画像複数投稿には gem 'carrierwave'を使用する記事がたくさん出てきましたが、うまくいかなかったので今回はrefileで実装してみました。

画像投稿用のテーブルを作成

画像1枚だけの投稿だと、対象のモデルにimageカラムを追加するだけでいいのですが、複数枚となると別でテーブルを作成する必要があります。

私はpet_imageモデルを新規作成しました。

 create_table "pet_images", force: :cascade do |t|
    t.integer "pet_id"
    t.string "image_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["pet_id"], name: "index_pet_images_on_pet_id"
  end

リレーションを組む

1:Nの関係性を持たせます。

pet.rb
 has_many :pet_images, dependent: :destroy
 accepts_attachments_for :pet_images, attachment: :image
pet_image.rb
 belongs_to :pet
 attachment :image

コントローラーを編集

pet.controller.rb
 private
 def pet_params
    params.require(:pet).permit(:name, :birthday, :gender, :introduction, :genre_id, :prefecture_id, :age, :is_active, :image,  pet_images_images:[] )
  end

新規投稿フォーム編集

pet.new.html
<%= form_with model: @pet, url: pets_path, method: :post, local: true do |f| %>
  <%= f.attachment_field :pet_images_images, multiple: true %>
<% end %>

ペット一覧には画像を一枚だけ表示させたいので以下のように記述

pet.index.html
  <% pet.pet_images.first(1).each do |image| %>
   <%= attachment_image_tag image, :image, size: '200x200' %>
  <% end %>

画像を複数枚表示させたいところには↓

pet.show.html
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js"></script>
 <div id="slider">
   <% @pet.pet_images.each do |image| %>
      <%= attachment_image_tag image, :image, size: '350x350', class: "rounded mt-4" %>
   <% end %>
 </div>

プラスでスライドショーにする:smile:

application.html
<head>
  <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css"/>
  <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick-theme.css"/>
</head>
application.js
$(function() {
  $('#slider').slick({
      dots: true, 
      autoplay: true, 
      autoplaySpeed: 4000, 
  });
});
application.css
.slick-next {
    right: 10px 
    z-index: 100;
 }

.slick-prev {
    left: 10px 
  z-index: 100;
 }

以上です!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ubuntu上で作ったRails環境をVSCodeで書けるようにする(Windows)

はじめに

今回はUbuntu上に構築したRails環境を
VSCode上でコードなどを書くことができる手順となります。
Ubuntu上にRails環境を構築する方法は以下の記事をご参照ください。
Ubuntu Rails Widowsで環境構築をしたよ(2021年版)
VSCodeについては以下のリンクからダウンロードできます。
Vscode

VScodeのセットアップ

拡張機能>入力欄に「Remote WSL」を入力。インストールします。
WSL.png

次にメニューバーから
ファイル>ユーザ設定>設定>設定(JSON)を開きます。
WSL.png

設定の中に以下のコマンドを入力

VSCode
    // デフォルトの起動するターミナルをbashにする
    "terminal.integrated.shell.windows": "C:\\WINDOWS\\Sysnative\\bash.exe",

WSL.png

入力したら、一度VSCodeを再起動させると左下に以下のマークが出ると思います。
WSL.png
このマークを押すとフォルダーを選択できると思うので「Remote-WSL:Open Folder 」を選択し
開発用のフォルダを選択します。
最後にメニューバーのターミナルを実行させて以下の画面が出れば無事終了です。
お疲れ様でした!
WSL.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rspecでテストを作成する時、毎回 require 'rails_helper' と書くのを省略する

環境

Mac OS X
Ruby: 2.7.1
Rails: 6.0.3.4

課題

RSpecでテストを作成する時、何も設定しないと以下のように記述すると思う

model_spec.rb
require 'rails_helper'
Rspec.describe Model, type: :model do

~以下テスト~

しかしrequire 'rails_helper'と毎回記述するのは面倒くさいので省略できないか調査した

解決法

.rspecに以下のコードを追加する

.rspec
--require rails_helper

結果

以下のようにしてもテストが動き、コードを削減することができた

model_spec.rb
Rspec.describe Model, type: :model do

~以下テスト~

参考記事

https://qiita.com/yuta-ushijima/items/ffb34823b8bba2180c94

最後に

お読みいただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rspecでテストを作成する時、各ファイル毎に require 'rails_helper' と書くのを省略する

環境

Mac OS X
Ruby: 2.7.1
Rails: 6.0.3.4

課題

RSpecでテストを作成する時、何も設定しないと以下のように記述すると思う

model_spec.rb
require 'rails_helper'
Rspec.describe Model, type: :model do

~以下テスト~

しかしrequire 'rails_helper'と毎回記述するのは面倒くさいので省略できないか調査した

解決法

.rspecに以下のコードを追加する

.rspec
--require rails_helper

結果

以下のようにしてもテストが動き、コードを削減することができた

model_spec.rb
Rspec.describe Model, type: :model do

~以下テスト~

参考記事

https://qiita.com/yuta-ushijima/items/ffb34823b8bba2180c94

最後に

お読みいただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails + jQuery]初学者向けAjaxを取り敢えず飛ばしてみたい

課題

初学者が感覚掴むために取り敢えずAjax飛ばしてみたい。

例として以下フォームで入力された文字をサーバに送ってみる。

form.erb
<%= text_field_tag :myname %>
output
<input type="text" name="myname" id="myname">

スクリーンショット 2021-01-24 11.18.12.png

結論

以下コードで取り敢えず飛ぶ。

ajax.js
$("#myname").change(function(){
  let name = $(this).val();
  $.ajax({
    type: 'GET',
    url: "/api/v1/users",
    data: { name: name },
    dataType: 'json'
    })
  .done(function (response) {
    console.log(response)
  }
  .fail(function (){
  });
})

受け口のRouteやControllerは一般的なRailsの範囲なので割愛します。

参考情報

Ruby on RailsのAjax処理のおさらい
https://qiita.com/ka215/items/dfa602f1ccc652cf2888

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(備忘録)Everyday Rails 第2章「RSpecのセットアップ」

「Everyday Rails - RSpecによるRailsテスト入門」

Railsを使用したアプリケーションを作成したものの、テストの記述が全然分からない、という状態になったので、RSpecの勉強をできる教材を探していたところ、なんとプロを目指す人のためのRuby入門 (チェリー本)の著者が翻訳を手がけた本を発見しました。
こちらのサイトから購入できます!
販売方法はなんと、購入金額を自由に設定できるという、画期的なシステムでした(最低購入価格は$19からですが)。
先日、なんとか1周は終わらせたのですが、全然理解できていない部分が多いので、復習がてらアウトプットしていきたいと思います!
image.png

第1章 「イントロダクション」

第1章はイントロダクションということで、この本のアウトラインや著者の想いなどが書かれています。

著者の思い

その中で、著者の考える基本的な信条というものがあり、

・テストは信頼できるものであること
・テストは簡単に書けること
・テストは簡単に理解できること(今日も将来も)

と書かれており、また

・とはいえ結局、一番大事なことはテストが存在することです。信頼性が高く、理解しやすいテストが書いてあることが大事な出発点になります。

とありました。
テストはどちらかと言うと、とっつきにくいイメージがあったので、学習することから逃げていた節もあったのですが、心を入れ替えてしっかりと取り入れていきたいと思います!

サンプルコードについて

GitHubからサンプルコードを入手できます。

第2章 「RSpecのセットアップ」

早速、本に従って進めていきたいところですが、いきなり、「テストスイート」という聞いたこともない単語に出くわしました。
スルーしてもいいのですが、最初が肝心なので、調べてみました。
テストスイートとは、

ソフトウェアテストの目的や対象ごとに複数のテストケースをまとめたもの。自動化テストにおいては、テストの実行単位となる。
 ソフトウェアテスト(動的テスト)の最小単位はテストケースといえるが、実際にテスト作業ではいくつものテストケースを組み合わせることによって不具合をあぶり出したり、確率的に十分なテストを行ったという結論を出したりする。このようなテスト目的やテスト対象に応じて、多数のテストケースを束ねたものをテストスイートという。

らしいです。
僕は知りませんでしたので、勉強になりました。

Gemfileのインストール

まずはRSpecをインストールする必要があります。

Gemfile
group :development, :test do
  gem 'rspec-rails', '~> 3.6.0'
end

開発環境とテスト環境の両方で、rspec-railsを読み込みますが、本番環境では読み込みません。

テストデータベースの作成

config/database.yml
test:
  <<: *default
  database: db/test.sqlite3

接続可能なデータベースの作成を行います。
$ bin/rails db:create:all

RSpecの設定

続いて、RSpecのインストールを行います。
$ bin/rails generate rspec:install

インストール時に作成された.rspecファイルを以下のように変更すると、RSpecの出力がドキュメント形式になるので、非常に読みやすくなります。

.rspec
--require spec_helper
--format documentation

rspec binstubで起動時間の短縮を図る

Gemfile
group :development do
  gem 'spring-commands-rspec'
end

bundle install後、新しいbinstubを作成します。
$ bundle exec spring binstub rspec

RSpecを実行してみる

まだテストファイルは一個も作成していませんが、RSpecのインストールを確認する上でも、以下のコードで一度RSpecを起動してみるのがいいと思います。
$ bin/rspec

ジェネレータの設定

今後、アプリを作成していく中で、$ rails gコマンドを使用してコードを追加する際に、RSpec用のテストファイルも同時作成できるように設定を変更します。

config/application.rb
require_relative 'boot'
require 'rails/all'

Bundler.require(*Rails.groups)

module Projects
  class Application < Rails::Application
    config.load_defaults 5.1

    config.generators do |g|
      g.test_framework :rspec,
        fixtures: false,
        view_specs: false,
        helper_specs: false,
        routing_specs: false
    end
  end
end

fixtures: false テストデータベースにレコードを作成するファイルの作成をスキップ
view_specs: false ビュースペックを作成しないことを指定
helper_specs: false ヘルパーファイル用のスペックを作成しないことを指定
routing_specs: false config/routes.rb用のスペックファイルの作成を省略

まとめ

これでRSpecのテスト実行するためのセットアップが整ったことになります。
色々と設定があって、大変ですね。
本によると、既存のtestディレクトリがあった場合は、rails testコマンドでテストの有無を確認し、必要ならRSpecへの移行を検討するべき、とのことでした。
あくまで準備段階が終わっただけですが、一苦労でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Railsでアプリを作ってみよう④

ビュー

MVCの役割の一つでブラウザにレスポンスとして見た目を返す役割を持っています。
image.png

ブラウザに表示するのはHTMLで書かれた物ですが、Rubyの記述も使って表現したい物です。
しかしそのままHTMLの文法で書いてしまうと問題があるので特別な書き方をします。

ERB(Embedded Ruby)

テンプレートエンジンと呼ばれる仕組みを持った物で
HTMLの中にRubyを埋め込むことができます。
ERBファイルは

ファイル名.html.erb

とhtmlの拡張子に追加してerbを記入することで作れます。

中身の記述をする時に
<%= %>というタグでRubyのコードを挟むことで埋め込んで表示することができます。
埋め込んだコードをブラウザに表示する必要のない場合(条件式など)は<% %> のタグを使います。

コントローラーにインスタンス変数を定義することで
アクションに対応するビューファイルでその値を使うことができます。

#コントローラーのファイル
class PostsController < ApplicationController 
  def index
    @post = "こんにちは" #インスタンス変数@postを定義
  end
end

ビュー入るでアクションに定義したインスタンス変数を使ってみましょう。

#ビューファイル
<%= @post %>  #こんにちは と表示される
#ビューファイル
<% @post %>  #何も表示されない

view.gif

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails deviseの使い方

devise(超初心者の備忘録)

どうも、はじめまして!yukkyです。今回が初投稿でQiitaの書き方もよくわかっていないですが記録を残さないとすぐ忘れてしまうため、頑張って書いていきたいと思います。題名にも書きましたが自分はがつくレベルの初心者ですので間違えがあったら(多分いっぱいあります。。)コメントで教えてくれると嬉しいです。さっき調べてみたら初めてvisual studioを入れた日(=初めてプログラムに触れた日)が2020/9/9でした(-_-;)まだ4.5か月ほどしかしてないですね。。

deviseでできること

ログイン機能が使えるようになる

使い方

まず練習用アプリとしてlogin_appを作る

rails new login_app 

gemにdeviseを追加

Gemfile
gem 'devise'
bandle install
rails g devise:install

すると以下の画面が出てくれば成功

Depending on your application's configuration some manual setup may be required:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

     * Required for all applications. *

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

     * Not required for API-only Applications *

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>
     * Not required for API-only Applications *

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

     * Not required *

===============================================================================

何やらセットアップをしなきゃいけないらしい(1番をしてなくて後で痛い目にあいました..)
1 config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }をconfig\environments\development.rbに追加

2 ここは後でhomeコントローラを作るとき自動でやってくれるので大丈夫

3

<%= notice %>


<%= alert %>


これをつけるとポップアップが出るよ

4 後でやるので大丈夫

rails g devise User

でdevise用のユーザーモデルが作れる。今回は名前でログインしたいのでmigrateする前にnameカラムを作る

**_devise_create_users.rb(**には日付が自動で入る)
t.string :name

を追記。その後migrate

rails db:migrate

新規登録フォーム、ログインフォーム作成

rails g devise:views

これでviewが出来る。
新規登録フォームのviewはapp\views\devise\registrations\new.html.erb
ログインフォームのviewはapp\views\devise\sessions\new.html.erb
中身を見るとデフォルトではメアドでログインになっているので名前に変更。
(VSCcodeを使っている方は、cmd(ctrl) + pを押すとファイル名で検索できます.)
(VSCcodeを使っている方は、cmd(ctrl) + fを押すと文字列で検索できます)

app\views\devise\sessions\new.html.erb
<h2>Log in</h2>

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>

<!-- ここから追加 --!>
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
  </div>
<!-- ここまで追加 --!>

<!-- ここから削除 --!>
  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>
<!-- ここまで削除 --!>

さらに新規登録画面でも名前を追加(注:さっきは変更だったけど今度は追加)

app\views\devise\registrations\new.html.erb
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>
<!-- ここから追加 --!>
  <div class="field"> 
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
  </div>
<!-- ここまで追加 --!>

を追加。これだとまだ名前を送れないので新規作成(singn up)名前の情報を送ることを許可する設定を行う

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
<!-- ここから追加 --!>
  before_action :configure_permitted_parameters, if: :devise_controller? 

  private

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up,keys:[:name])
    end
end

さらにログイン(sign in)するとき名前の情報を送ることを許可する設定を行う

config\initializers\devise.rb
<!-- ここを削除 --!>
  # config.authentication_keys = [:email]
<!-- ここを追加 --!>
  config.authentication_keys = [:name]

しかしこれではログインしてもホームパス(Yay! You’re on Rails!のところ)に行ってしまうため画面を作る。

rails g controller home top (ログインした後行く場所)
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller? 
  <!-- ここから追加 --!>
  def after_sign_in_path_for(resource)
    home_top_path
  end
  private
<!-- ここまで追加 --!>
    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up,keys:[:name])
    end
end

さらにホームトップにログアウトボタンを作る。

app\views\home\top.html.erb
<%= link_to "ログアウト", destroy_user_session_path, method: :delete %>

これで一通り機能が完成!ありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActiveRecordのwhere notの挙動について

はじめに

普段、RailsはActiveRecord使っているんですが、条件を複数書いたときに、
where.not()の挙動が直感と反しており、なかなかバグに気づかなかったので、共有します。

環境

Ruby : 2.7.1
Rails : 6.0.2
Posgresql : 13.1

where.notの挙動

まず、where.not()の単数条件で名字が山田以外のuserを取得したい時を考えてみます。
発行されるSQLは以下のようになります。

User.where.not(last_name: '山田')
=> SELECT "users".* FROM "users" WHERE "users"."last_name" != $1 
 [["last_name", "山田"]]

これは期待通りにlast name山田でないuserを取得してくれます。

では次に「名字が山田」かつ「名前が太郎」以外のuserを取得するとしましょう。
僕の直感では以下のような記述で取得できると思ってましたが...

User.where.not(last_name: '山田', first_name: '太郎')
=> SELECT "users".* FROM "users"
WHERE "users"."last_name" != $1 AND "users"."first_name" != $2 
[["last_name", "山田"], ["first_name", "太郎"]]

上記、SQLを見てみると、「山田ではない」かつ「太郎ではない」というSQLが発行されています。でも欲しかったのは「名字が山田」かつ「名前が太郎」ではない userです。集合記号を使うと以下のようにかけます。

\overline{ 山田 \cap 太郎} \neq \overline {山田} \cap \overline {太郎}

スクリーンショット 2021-01-24 1.37.55.png
取得したいuserは赤と青の共通部分(山田太郎)以外の箇所です。
しかし、発行されるSQLで取得しているのは、赤と青以外、すなわち白の部分のuserです。
悲しいかな、「山田孝之」や「麻生太郎」は取得してくれません。

解決

では、山田孝之や麻生太郎を取得するにはどうすれば良いかというと、以下のようになります。

User.where.not(last_name: '山田').or(User.where.not(first_name:'太郎'))
=> SELECT "users".* FROM "users"
WHERE ("users"."last_name" != $1 OR "users"."first_name" != $2)
[["name", "山田"], ["public_id", "太郎"]]

上記は、書き方的には「山田ではない」または「太郎ではない」になります。これはドモルガンの法則を用いて

\overline{A \cap B} = \overline A \cup \overline B

となることを使っています。A={山田},B={太郎}です。
よって、山田孝之は「山田ではある」ものの「太郎ではない」ので取得することができます。

もっとスマートに書きたいんじゃ!と思っておりますので、良い方法あったら教えてくだされー!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】ルーティングの基礎的な書き方【Ruby】

ルーティングの役割

railsガイド( https://railsguides.jp/routing.html )によると

Railsのルーターは受け取ったURLを認識し、適切なコントローラ内アクションやRackアプリケーションに割り当てます。

とのこと。

「route」を直訳すると「経路」ですから、リクエストの道案内役といったところでしょうか。

基礎的な書き方について記してみたいと思います。


基本の書き方
rootの指定
resourcesを用いた書き方


基本の書き方

HTTPリクエスト 'URIパターン', to: 'コントローラー名#アクション名'
もしくは
HTTPリクエスト 'URIパターン', controller: 'コントローラ名', action: 'アクション名'

Rails.application.routes.draw do
  get 'profile', to: 'users#show'
  post 'tweets', controller: 'tweets', action: 'create'
end

rootの指定

root(ルート)とは、Railsアプリを実行する上で基本となる場所(パス)のことです。
例えばローカル環境にてアプリを実行した時に、「 http://localhost:3000 」のURLを指定した際に遷移するページを設定することができます。
root to: 'コントローラー名#アクション名'
もしくは
root 'pages#main'

Rails.application.routes.draw do
  root to: 'pages#main'
  root 'pages#main'
end

resourcesを用いた書き方

resourcesメソッドを使用すると、index, new, create, edit, update, show, deleteの七つのアクションへの割り当てを自動的に行うことができます。

Rails.application.routes.draw do
  resources :articles
end

こちらは、以下の7行のルーティングと同義になります。

get    '/articles',          to: 'articles#index'
get    '/articles/:id',      to: 'articles#show'
get    '/articles/new',      to: 'articles#new
get    '/articles/:id/edit', to: 'articles#edit
post   '/articles',          to: 'articles#create
patch  '/articles/:id',      to: 'articles#update'
delete '/articles/:id',      to: 'articles#destroy'

参考文献

https://railsguides.jp/routing.html
https://web-camp.io/magazine/archives/16815

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

bundle installしてもエラーが続き沼にハマる。(備忘録として)

bundle installしてもエラーが続き沼にハマる。(備忘録として)

rails newしてbundle installすると

Make sure that `gem install #### -v '"#.#.#' --source https:・・・・`

のようなエラーが延々と続く。

gemを指定してinstallしてもエラーは解消されず。
ググった情報を頼りにカタカタするも、エラーは解消されず。

結局解決方法は以下でした。

1rbenvでrubyを管理する
2xcodeのupdateをする

1rbenvでrubyを管理する。

デフォルトのrubyを使っていたが、toolのアップデートかなにかで齟齬が出てしまった?のかもしれない。
標準rubyは一つしか入っていないためrbenvでrubyのバージョンを管理する。
基本的に開発ではrbenvを用いてrubyを管理する。
参考:https://qiita.com/hujuu/items/3d600f2b2384c145ad12

2xcodeのupdateをする。

これが今回最も遠いようで近いエラーの原因でした。
エラー分には
you have to ....のような文字があったがなんのことやらと無視していた。
しかしそれはtoolをupdateしてくれと言うメッセージでした。
xcodeをupdateしないとだめだった。


bundle installでめっちゃ変更が多くなった。。
3k+!?

gitignoreに
/vendor/bundle/*/
vendor配下のbundleを追加してあげることで解決

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

パーシャルで繰り返し処理

教えていただいたことの備忘録として残します。

bar.html.erb
<%= render partial: 'foo', hoges: @hoges %>
_foo.html.erb
<% hoges.each do |hoge| %>
 <% hoge.name %>
 <% hoge.price %>
<% end %>

これでも動作確認はできましたが、以下のようにします。

bar.html.erb
<%= render partial: 'foo', collection: @hoges, as: 'hoge' %>
_foo.html.erb
 <% hoge.name %>
 <% hoge.price %>

こうすることで読み込み速度が向上します。
collectionオプションを使うと1回しか読み込まれないみたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RSpecでJavaScript等で挿入されるiframe内のコンテンツを確認する

概要

RSpecでテストを書いている時に、Twitter、Youtube等のリンクを貼り付けた時に、JavaScript等で時間差で挿入されるiframe内のコンテンツを確認する際に詰まったのでメモ。

方法

以下の通り。

# iframeがあるか確認。この場合、挿入されるまでデフォルトのwait timeだけ待ってくれる
expect(page).to have_selector 'iframe'
# iframe内のコンテンツを確認
within_frame find('iframe') do
  expect(page).to have_content 'コンテンツ'
end

デフォルトのwait time内で挿入されない場合は以下の様に待ち時間を指定する。

expect(page).to have_selector 'iframe', wait: 5

1行目はチェックする必要がなければuntilでJavaScriptでiframeが挿入されるまで待ってもいい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む