20201027のRubyに関する記事は27件です。

Ruby returnメソッドの使い方について

returnとは??

メソッドの戻り値を返す方法。Rubyにおいては、returnをわざわざ使用せずとも、定義したメソッドにおいて、最後に処理された値が返ってくる。

しかし、途中で処理を抜け出したい場合は、returnを使用することで、強制的に値を返すことができる。

例題

■returnを使用しない場合

def total
  price = 1000
  num = 10

  "#{price}円の服を#{num}枚購入したので、合計は#{price*num}円になります。"
  "1枚返品したので、合計は#{price*(num-1)}円になりました。"
end
p total

結果

1枚返品したので、合計は9000円になりました。

returnを使用しない場合、最後に定義した文言が出力されます。

■returnを使用する場合

def total
  price = 1000
  num = 10

  return "#{price}円の服を#{num}枚購入したので、合計は#{price*num}円になります。"
  "1枚返品したので、合計は#{price*(num-1)}円になりました。"
end
p total

結果

1000円の服を10枚購入したので、合計は10000円になります。

returnを使用すると、return後に定義した文言が出力されました。

このように、もし途中で処理を抜けたい場合はreturnを活用すると良いでしょう。
ちなみにまだ私はreturnを使用する場面には遭遇していません、、、笑

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

【rails】first_or_initialize

first_or_initializeについて学習したため、アウトプットいたします。

first_or_initializeとは?
first_or_initializeの使い方は?

の順に記述します。

first_or_initializeとは?

whereで検索した条件のレコードが存在すればそのレコードのインスタンスを返し、存在しなければ新しくインスタンスを作るメソッドです。

と言ってもなかなかわかりませんよね。
詳しく説明します。

例えば、
studentというテーブルがあったとして、そこのデータベース上に10人の名前がそれぞれ登録されていたとします。

first_or_initializeメソッドは、
そのデータベース上にそのstudentがいなかった場合→そのstudentを新規登録します。
一方、
studentがすでに登録されていた場合→その生徒の情報を取ってきます。

少しづつわかってきましたか?

すなわちこのメソッドの特徴は
「データの重複を避けること」なんです。

ではどうやって使うのでしょうか?

first_or_initializeの使い方

student = Student.where(name: "佐藤").first_or_initialize

存在しなければ新しくインスタンスを作りたいオブジェクトを定義し、
その後に
where(条件).first_or_initialize
とすると完成です。

上記の例では、
そのデータベース上に佐藤さんがいなかった場合→その佐藤を新規登録します。
一方、
佐藤さんすでに登録されていた場合→佐藤さんの情報(id, age等定義したもの)を取ってきます。

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

メソッドについてのアウトプット その2です

メソッドのアウトプット その2 引数です

その1ではメソッドをの中でif文を使用してみました。

※前回の記事です。メソッドについてのアウトプットです その1

今回は引数を使って、もう少しコードをすっきりしたいと思います!

前回のコードです。

sample.rb
def register
  eraser = 110
  pen = 150
  bill = eraser + pen
  if bill >= 200 #200円以上のお買い上げは10%off!!
    bill * 0.9
  end
end
  puts register #registerメソッドを呼び出す。

こちらの
eraser と penの数値をメソットの外で定義してみます。

sample.rb
def register
  eraser = 110 # ここの数値
  pen = 150 # ここの数値
  bill = eraser + pen
  if bill >= 200
    bill * 0.9
  end
end
  puts register

def registerの後ろに()そ追加してその中に
eraserpen を入れてあげます。

sample.rb
def register(eraser, pen) # eraserとpenの間に カンマ(,)と半角スペース
  # eraser = 110 ここは削除
  # pen = 150 ここは削除
  bill = eraser + pen
  if bill >= 200
    bill * 0.9
  end
end
  puts register(150, 100) # ここに数値をいれる

puts register(150, 100) この二つの数値は
def register(eraser, pen) ここに送られます。
それぞれ eraser には 150
pen には 100
が送られます。

sample.rb
def register(eraser, pen)
  bill = eraser + pen
  if bill >= 200
    bill * 0.9
  end
end

puts register(150, 100)

すくしだけすっきりしましたね!(多分)

今日のアウトプットでした。:sweat:

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

RubyOnRails Udemyの無料講座でエラーが発生、それを解決、最後まで貫く

RubyOnRails Udemyの無料講座でエラーが発生、それを解決、最後まで貫く

RubyOnRails学習をはじめた人で以下のUdemyの無料講座を受講したが、エラーで躓き最後まで修了できなかった方々のために、身をもって経験したエラーと解決方法を共有します。

【最短30分でできる!】Ruby on Rails入門: 初心者でも簡単! ブラウザ

エラーが発生した時点-1

1.「14. 画像ファイルの追加、編集機能の追加」のコース
スクリーンショット 2020-10-27 200600.png

  1. ターミナルにて「rake db:migrate」を打ち込んだ時点でターミナルにエラーが発生した。
    スクリーンショット 2020-10-27 212832.png

  2. localhost:3000 にても「ActiveRecord::PendingMigrationError」というエラーが発生した。
    スクリーンショット 2020-10-27 213027.png

原因、解決方法-1

原因は'paperclip'がrailsのバージョンに依存しているからだ。
よく確認したところ、講座はRubyonRails 5.2をベースにしているとの記載があった。
僕の方だと、現時点でPaizaCloudはRubyonRails 6系が標準になっていた。

1.ターミナルにて「gem list rails」を打ち、railsのバージョンを確認しよう。
スクリーンショット 2020-10-27 211106.png
*僕の場合のバージョンは
 6.0.2.1,
 5.0.7.2,
 5.0.6
だった。

2.プロジェクトを新たに作成しよう。
*講座としては、「9.プロジェクトの作成」に戻ろう。
スクリーンショット 2020-10-27 210901.png

3.ターミナルにて、「rails (version) new boardgame-app --database=mysql」を打ち、RubyOnRails 5系を使用するプロジェクトを作成する。
スクリーンショット 2020-10-27 211203.png
*僕の場合は、RubyOnRails 5.0.7.2 を使用した。

動作確認-1

1.講座の通り進もう。

2.「14. 画像ファイルの追加、編集機能の追加」のコースにて、動作を確認したところ、エラーなく進行された。localhost:3000 にても問題なし。
スクリーンショット 2020-10-27 195849_.png

ーーー

エラーが発生した時点-2

1.「14. 画像ファイルの追加、編集機能の追加」のコース
スクリーンショット 2020-10-27 200405.png

原因、解決方法-2

原因は不明だが、他と違って「<%= from...」を使っていることが原因のようだった。
スクリーンショット 2020-10-27 200428_.png

1.「<%= from...」を「<%= f...」に書き換える。
スクリーンショット 2020-10-27 200443_.png

動作確認-2

  1. localhost:3000にて問題なく表示された。

ーーー

Laravelも同じだと思うが、バージョンによる予期せぬ不備(記述方法が異なったり、packageが使えなくなったりする等)が多々あった。エラーに遭っても挫折せず、皆が力を合わせ取り組んで解決したら良いと思う。

無料講座はエラーに遭遇した時でも、講師に質問ができないことがある。
本投稿がRubyOnRailsを学習始めている方々が諦めずに最後まで貫くための原動力になることを祈る。

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

Rails学習 3日目その2

Ruby on Rails5速習実践ガイド chapter7

7-1 登録や編集の実行前に確認画面をはさむ

登録する前に確認画面が出てきてそこで確認してからデータが登録されるように設定する。
まずは確認画面が表示されるアクション(conform_newアクション)をコントローラーに書く

app/controller/tasks_controller.rb
 def confirm_new
   @task = current_user.tasks.new(task_params)
   render :new unless @task.valid? #もしデータベースに@taskがなかったら実行

その次にルーティングを記入

config/routes.rb
resources :tasks do
  post :confirm, action: :confirm_new, on: :new
end

post :confirm, action: :confirm_new, on: :new
この部分は元々以下の形であった

config/routes.rb
resources :tasks do
  new do
   post :confirm, action: :confirm_new
  end
end

newブロック内に要素が一つだけの場合は後ろにon: :ブロック名とすることでルーティングがかける

次に確認画面のビューを作る

app/views/tasks/confirm_new.html.slim
h1 新規内容の確認

= form_with model: @task, local: true do |f|
  table.table.table-hover
    tbody
      tr
        th= Task.human_attribute_name(:name)
        td= @task.name
        =f.hidden_field :description
      tr
        th= Task.human_attribute_name(:description)
        td= simple_format(@task.description)
        =f.hidden_field :description
  =f.submit '戻る', name: 'back', class: 'btn btn-secondary mr-3'
  =f.submit '登録', class: 'btn btn-primary'

7-1-3 登録アクションで「戻る」ボタンからの遷移に対応する。

上記の確認画面のビューには戻るボタンと登録ボタンの2つがある。戻るボタンを機能させようと思ったらこの二つのボタンのどちらが押されているかの判断をする必要がある。そのために戻るボタンにはname属性にbackをつけた。プログラミング上ではもしname属性のbackが押されたら元に戻るという操作になる。
つまりparams[:back]の結果が出れば良い。
params[:back]が押されると元に戻るという動作をcreateアクションに書けば良い

app/controllers/tasks_controller.rb
def create
  @task = current_user.tasks.new(task_params)

  if params[:back].present? #present?は値がある場合trueとなる真偽値
    render :new
    return
  end

真偽値で使うメソッドの種類

メソッド名 メソッドの意味
nil? 変数の値がnil、または値がないときにtrueになる
empty? 変数の値が""(文字列の場合)や値が空白の場合、真となります。nil?との違いは、empty?は変数の値はあることはあるが、その値が空を示しているところ
blank? 値と言えるものがない場合にtrueとなる
present? 値と言えるものがある場合はtrueとなる

7-2 一覧画面に検索機能を追加する

タスク一覧にあるタスクの数が多くなってくるといちいち探し出すのがめんどくさくなってくる。そんな時に検索機能があった方が便利だろう。
検索機能をつけるにはRansackというgemを使う

7-2-2 名称による検索
Ransackを使って検索機能を追加する

app/controllers/tasks_controller.rb
def index
  @q = current_user.task.ransack(params[:q])
  @task = @q.result(distinct: true).recent
end

@q = current_user.task.ransack(params[:q])

ransackではquery parameter(params[:q])を取って検索をかける
ログイン中のユーザーのtaskをransackで検索しそれを@qと置いている

@task = @q.result(distinct: true).recent

検索で出た@qを
重複する検索結果を除外しつつ(result(distinct: true))
登録日時の並びで表示する(recent)

ransackが実装できたので実際にビューで検索できるようにしてみる
検索機能の追加にはsearch_form_forを使う

app/views/tasks/index.html.slim
h1 タスク一覧

= search_form_for @q, class: 'mr-5' do |f|
  .form_group.row
    =f.label :name_cont, '名称', class: 'col-sm-2 col-form-label'
    .col-sm-10
      =f.search_field :name_cont, class: 'form-control'
  .form-group.row
    =f.label :created_at_gteq, '登録日時', class: 'col-sm-2 col-form-label'
    .col-sm-10
      = f.search_field :created_at_gteq, class: 'form-control'
  .form-group
    =f.submit class: 'btn btn-outline-primary'

= link_to '新規登録', new_task_path, class:  'btn btn-primary mb-3'

name_cont:nameと部分一致している物を選ぶ。
.search_field:記入場所
created_at_gteq:記入した投稿日時より大きい(未来:gteq)の投稿を選ぶ

7-3 一覧画面にソート機能を追加する

app/controllers/tasks_controller.rb
def index
  @q = current_user.task.ransack(params[:q])
  @task = @q.result(distinct: true).recent
end

recentでソートをしていたが次は任意の順番でソートをする
まずresentをとる

app/controllers/tasks_controller.rb
def index
  @q = current_user.task.ransack(params[:q])
  @task = @q.result(distinct: true)
end
app/views/tasks/index.html.slim
table.table.table-hover
  thead.thead-default
    tr
      th= sort_link(@q, :name, default_order: :desc)
      th= Task.human_attribute_name(:created_at)
      th

sort_linkをつけるとソート操作ができるようになる
第一引数にはransackによって得られた値(ここでは@q)
第二引数にはソートを行う対象のカラム(ここではname)
default_order: :desc

7-4 メールを送る

Railsはメールを送るためにメイラーという仕組みを利用している。メイラーを使いメールを作成・送信する。
メイラーはメイラーファイルに記述する

app/mailers/task_mailer.rd
class TaskMailer < ApplicationMailer
  def creation_email(task)
    @task = task
    mail(
      subject: 'タスク作成完了メール'
      to: 'user@example'
      from: 'taskleaf@example'
     )
  end
end

subjectやto、fromといった情報のmailをcreation_emailメソッドとしておく

7-4-3 メールの送信処理

実際にメールを送信できるようにしていく

app/controllers/tasks_controller.rb
def create
  @task = current_user.tasks.new(task_params)

  if params[:back].present?
    render :new
    return
  end

  if @task.save
    TaskMailer.creation_email(@task).deliver_now
    redirect_to @task, notice: "タスク「#{@task.name}」を登録しました"
  else
    render :new
  end
end

上記のようにTaskMailer.creation_email(@task).deliver_nowをつけると@taskについてのメールが送信される。deliver_nowは即時送信を行うためのメソッド。他にもdeliver_laterメソッドも存在している

7-5 ファイルをアップロードしてモデルに添付する

Active Storageというファイル管理gemが出てきて、それらを使って写真や画像を添付する
実際に添付するには以下の方法で添付する

app/models/task.rb
class Task < ApplicationRecord
  has_one_attached :image
....

end

has_one_attachedメソッドを使うことによって1つのタスクに1つの画像(image)を紐付けることが可能になる。

app/views/tasks/_form.html.slim
...
...
...
.form-group
  =f.label :image
  =f.file_field :image, class: 'form-control'
...
end

ja.ymlにも「image:画像」と設定しておく
task_paramsメソッドのpermitもimageも許可しておく

確認画面にも表示されるようにコードを書く

app/views/tasks/show.html.slim
...
tr
  th= Task.human_attribute_name(:image)
  td= image_tag @task.image if @task.image.attached?
tr
...
...
...

if @task.image.attached?は画像が添付されているかどうかを表す。
実際に画像があればimage_tagで表示する

7-7 ページネーション

タスクが多くなればなるほど今までやっていた情報を全て表示する方法では動作が重たくなってきてしまう。ページネーションは一定数以上のファイル数になればそれ以上の表示は次のページへ渡すなどをし、ページによって情報を分散させ動作を軽くする方法。
このページネーションにはkaminariというgemファイルが用いられる。

元々のtasks_controllerファイルを

app/controllers/tasks_controller.rb
def index
  @q = current_user.task.ransack(params[:q])
  @task = @q.result(distinct: true)
end

.page(params[:page])を後ろにつけることによって1ページあたりに表示する件数を決めることができる(デフォルトで1ページ25件)

app/controllers/tasks_controller.rb
def index
  @q = current_user.task.ransack(params[:q])
  @task = @q.result(distinct: true).page(params[:page])
end

次に実際にビューファイルに反映されるようにする

app/views/tasks/index.html.slim
.mb-3
  =paginate @tasks
  =page_entries_info @tasks
...
...
...

paginateヘルパーメソッドとpage_entries_infoヘルパーメソッドを使うことによって自動的に作成してくれる。

7-8 非同期処理や定期実行を行う(Jobスケジューリング)

Railsではバックグラウンドで様々な処理を非同期に行うためのActive Jobというフレームワークが用意されている。ActiveJobは以下の時に使われる

・処理が重たくユーザーを待たせてしまっている
・指定した日時にアクションを起こしてほしい

そんな時に使うのがsidekiqという仕組みである

①まずRailsとsideskiqを同期する

config/environments/development.rb
config.active_job.queue_adapter = :sideskiq

②app/jobs/sample_job.rbを作りperformメソッドを作る

app/jobs/sample_job.rb
class SampleJob < ApplicationJob
  queue_as :deault

  def perform(*args)
    Sidekiq::Logging.logger.info "サンプルジョブを実行しました"
  end
end

performメソッドを呼び出して処理する

app/controller/tasks_controller.rb
def create
  @task = current_user.tasks.new(task_params)
  ...
  if @task.save
    TaskMailer.created_email(@task).deliver_now
    SampleJob.perform_later
...
...
...

SampleJob.perform_laterが非同期処理を行うようになる

7-8-3 実行日時指定

setメソッドを使うと日時を指定して処理を実行できるようになる

#翌日の正午に実行
SampleJob.set(wait_until: Date.tomorrow.noon).perform_later

#1週間後に実行
SampleJob.set(wait: 1.week).perform_later
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyの条件分岐(case,while,無限ループ,break)

Rubyの条件分岐

case文

条件分岐を表現するための文法。複数の条件を指定する時に、if文のelsifを重ねるよりもシンプルにコードを書くことができる

sample
case 対象のオブジェクトや式
when 値1
 # 値1に一致する場合に実行する処理
when 値2
 # 値2に一致する場合に実行する処理
when 値3
 # 値3に一致する場合に実行する処理
else
 # どれにも一致しない場合に実行する処理
end

while文

繰り返し処理を行うためのRubyの構文。指定した条件が真である間、処理を繰り返す

sample
number = 0

while number <= 10
 puts number
 number += 1
end

# ターミナル出力結果
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
# 10

無限ループ

処理が永遠に繰り返されること

sample
number = 0

while true
 puts number
 number += 1
end

# ターミナル出力結果
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
# 10
# .
# .
# .

上記のコードは条件式の部分にはじめからtrueと書くことによって意図的に無限ループを発生させている

break

eachメソッドやwhile文などのループから脱出するために使われる

sample
number = 0

while number <= 10
 if number == 5
   break
 end
 puts number
 number += 1
end

# ターミナル出力結果
# 0
# 1
# 2
# 3
# 4

このようにif文などの条件分岐とbreakを使うと、特定の条件のときにループを脱出することができる

現場からは以上です!

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

ActiveHashはアソシエーションをしっかり設定しよう

※結果を知りたい方は下の方までスクロールしてください。

エラー発生

商品を出品する機能を実装中のこと…

d812404dd725355d1e491026dce6f911.png
何これ…初めて見た…

原因を探る

コントローラーの記述は間違ってないよね…

item_controller.rb 一部割愛
class ItemsController < ApplicationController

  def create
    @item = Item.new(item_params)
    if @item.valid?
      @item.save
      redirect_to root_path
    else
      render :new
    end
  end

  private
  def item_params
    params.require(:item).permit(:name, :info, :price, :category_id, :status_id, :delivery_charge_id, :shipment_source_id, :date_of_shipment_id).merge(user_id: current_user.id)
  end

end

うん…大丈夫

ええー
じゃあモデルかなぁ

item.rb
class Item < ApplicationRecord

  validates :name, :info, :price, presence: true
  validates :category_id, :status_id, :delivery_charge_id, :shipment_source_id, :date_of_shipment_id, numericality: { other_than: 1 }

  belongs_to :user
  has_many   :comments
  has_one    :buyer

  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :category, :status, :delivery_charge, :shipment_source, :date_of_shipment
end

いや、記述の抜け漏れもないし、半角全角もスペルも大丈夫
バリデーションも大丈夫(←これが落とし穴)

ビューファイル(割愛)は…うーん大丈夫そう

そして、インターネットの海を彷徨うこと30分…
本当にわからん

しゃあないか

助け舟を呼ぶことに

大海に投げ出されたような気分だったのでもうこれは人に聞くしかあるまい
某短期講習中なので頼もしい方々に聞くことはできる

早速原因究明に向けて色々と思案してくださった
ありがたや〜?

これを、あれを試し、色々触っていった結果どうやらモデルの記述に問題があった模様

class Item < ApplicationRecord

  validates :name, :info, presence: true
  validates :price, presence: true
  validates :category_id, :status_id, :delivery_charge_id, :shipment_source_id, :date_of_shipment_id, numericality: { other_than: 1 }

  belongs_to :user
  has_many   :comments
  has_one    :buyer

  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :category
  belongs_to_active_hash :status
  belongs_to_active_hash :delivery_charge
  belongs_to_active_hash :shipment_source
  belongs_to_active_hash :date_of_shipment

end



↓つまりはこの部分↓

  belongs_to_active_hash :category
  belongs_to_active_hash :status
  belongs_to_active_hash :delivery_charge
  belongs_to_active_hash :shipment_source
  belongs_to_active_hash :date_of_shipment

ここを別々に書くだけ!
バリデーションなんやからまとめて書かせてくれや…と思ったが、

この話をしていると聞いていたうちの一人が






「それバリデーションじゃなくてアソシエーションですよ」






…まじかぁ…
まじかぁぁぁぁ!!!

恥ずかしいぃ!///
そういやそうだわ!思いっっきりBelongs_toって書いてあるし!
なんなら俺がActiveHashを導入してた時にrails gで生成してたものは?

モデルだよ!
モデルを生成してたんだよ!
それを関連付けるんだからアソシエーション以外に何があんの!

知らなかったとはいえ思いつく材料は目の前にあった訳だ
反省するとともに判断材料が増えたので一歩前進したと思う


本当に今回は勉強になった
真摯に対応してくれた方ありがとうございました

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

Uncaught ReferenceError: Vue is not definedが起こった話

はじめに

Vue.jsをCDN読み込みで簡単なミニアプリを使う際に起こったエラーです。
備忘録のため残しておきます。初学者のため間違えがあればご指摘下さい!

Uncaught ReferenceError: Vue is not defined

vue.jsの動作確認をするため以下のコードを記述したところvue.jsが読み込まれませんでした。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <link rel="stylesheet" href="vue.css">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <p>現在{{ number }}回クリックされています</p>
    <button>カウントアップ</button>
  </div>
  <script src="vue.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</body>
</html>

//vue.js

new Vue({
  el: '#app',
  data: {
    number: 0
  }
})

解決策は簡単。
下から3行目のVueを使うためのCDNをjsが読み込まれるより上に記述するだけです。
headタグの中に入れるかbodyタグの一番上に記述しましょう。

<!-- 修正後 -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <link rel="stylesheet" href="vue.css">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <p>現在{{ number }}回クリックされています</p>
    <button>カウントアップ</button>
  </div>
  <script src="vue.js"></script>
</body>
</html>

最後に

Vue.jsの超初心者の方の助けになれば幸いです。

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

ISUCON10 Online event

こんにちは, This is Santosh.I participated in ISUCON2020 Online event, It was held on September 12,2020.
Rules and regulations are mentioned on the official sites. please go through once(~5 minutes)
http://isucon.net/archives/54704557.html
Around 500~ teams participated on that day, It was fun as my first isucon! let's move to the technical side,
There was an application given「isummo」、It was about finding chair(isu in japanese) by different conditions. The goal was to improve the search time and processing speed of isummo application.
issumo1.png
issumo2.png

lightly just go through the following;
http://sinatrarb.com/
・new relic
ruby version check-install,start mysql(may be it will helpful next time too)
installruby.png
dbSetting.png
If any login issue with mysql just try this or follow stackoverflow↓
mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_passw

About coding language, you can choose any language Rust, Python, Go, Php or whatever you are comfortable with,I did with ruby as other team member were very familiar with it.Now the question is how to optimize our isummo app?
① Check all SQL queries -> Add index, as no index key was there
eg. SQL -> select * from isuumo.chair where kind = 'some value'
check kind is indexed or not ,if not -> KEY kind (kind)
adding index is easy as soon as you find the query, and it's fasten our app to some level.(rank was going up & team was enjoying)

② Index based on order BY ASC OR DESC
eg; select * from issumo.desk where some_condition order by popularity DESC;
Please not here, order by have column by DESC, and the default index we add earlier will be ASC .To speedup execution of query make it, DESC INDEX, -> KEY popularity (popularity DESC)
https://dev.mysql.com/doc/refman/8.0/en/descending-indexes.html
After this our app performance increased a bit.

③ Next, find n+1,source code and try to fix that,
this was a bit tough ,I tried but there was no such improvement in speed.
Other things can be done on infrastructure side,as other member was doing that part I don't have much idea about it. Next isucon will try to cover up infra as well.
Good luck everyone for next event!

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

binding.pryの追加(rails)

ターミナルにて(追加したいディレクトリ)を「cd ~ 」で指定する。
VSCodeで(追加したいディレクトリ)のgemfileを開き、「gem 'mysql2', '0.?.?'」の「mysql2」のあとのバージョンを「'0.5.3'」に変更し、
「gem 'mysql2', '0.5.3'」とする。

gemfileの一番下に「gem 'pry-rails'」と記述し、ターミナルに戻る。
ターミナルにて、bundle updateをするとgemがインストールされる。

mysql2のバージョンが既に変更されていたら、pry-railsを記述した後に「bundle install」をすると導入される。

間違いなどあれば、ご指摘いただけるとありがたいです。

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

Railsで日付比較の検索の書き方

Ruby2.7.1
Rails6.0.3.3
で確認

久しぶりにRailsでDBの検索処理を書いていて日付の比較の検索ってどう書くんだと調べていたのでメモ書き。
調べてるとたいてい、SQLを書くかArel使うかみたいのばっかで他に無いのかと調べていたら下記のような書き方でもいけた。

[0] pry(main)> User.where(created_at: ..DateTime.now)
  User Load (0.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`created_at` <= '2020-10-27 14:41:26.943067'
[
    [0] #<User:0x000055861898f208> {
                   :id => 1,
           :created_at => Tue, 27 Oct 2020 14:18:54 JST +09:00,
           :updated_at => Tue, 27 Oct 2020 14:18:54 JST +09:00,
    }
]

逆は

 User.where(created_at: DateTime.now..)
  User Load (0.5ms)  SELECT `users`.* FROM `users` WHERE `users`.`created_at` >= '2020-10-27 14:52:57.534880'

へぇって感じ。

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

Rails学習 3日目

Ruby on Rails5速習実践ガイド chapter6

6-2-1 「ルート」を構成する5つの要素

ルーティングとはリクエストをどのアクションで実行するかを指定するもの。ルーティングを構成するのに必要な物は以下である

要素の名前 要素の内容の例 説明
HTTPメソッド GET,POST,PATCH,PUT,DELETE 情報の送信、取得の方法を表す物
URLパターン /tasks、/tasks/:idなど URLそのもの
URLパターンの名前 new_task、tasksなど 定義したURLパターンごとに一意な名前をつけたもの
コントローラー tasks(Taskcontroller) 呼びたいアクションのコントローラークラスを指定する
アクション index 呼びたいアクションを指定する

6-2-5 resourcesでCRUDのルート一式を定義する

前の説明でresourcesについて説明した今回はそれの応用編である。

/config/routes.rb
resouces :tasks

このように記述するとtaskルーティングの7つのHTTPメソッドが自動的に1つにまとまる。ということを書いた。それではそれ以外のルーティングを書きたいときはどうすれば良いのか?プラスで付け加えたい時はcollectionを使う

/config/routes.rb
resouces :tasks do
  collection do
    get 'export'
  end
end

このようにcollectionのなかにHTTPメソッドとアクション名を書くことで自動的にルーティングが機能するようになる。

6-3 国際化

ja.ymlファイルなんかによりプログラミングでも日本語対応させてコードを書くことが可能である。利用者もまた日本語に対応したサービスにはなるが外国のかたが使う機会があるかもしれない。利用者によって言語を変える必要も出てくる。そんな時に使うのがI18n.localeである。I18nは一つのプログラムで複数の国向けに使えるようにするものである。

class ApplicationController < ActionController::Base
  before_action :set_locale


private

  def set_locate
    I18n.locale = current_user&.locale || :ja #ログインしていなければ日本語
  end
end

コントローラに定義することで使えるようになる

6-6 Railsのログ

ログとは自分が何か処理をしたときの履歴である。もしエラーやバグがあればログを遡り何の操作が正しくなかったかなどをみることができる。
例えばタスク作成時に保存したタスクの情報をログ出力させたい時は、以下のようにする。

app/controllers/tasks_controller.rb
   def create

     if @task.save
       logger.debug "task: #{@task.attributes.inspect}"
       redirect_to @task, notice: "タスク「#{@task.name}」を登録しました"
     else

inspectはわかりやすく表示してくれるもの。

ただログに残ってはいけない個人情報なんかもある、その時にはログに映らないようにしなければならない。

config/initializers/filter_parameter_logging.rb
Rails.application.config.filter_parameter +=[:password]

ここで指定されたパラメータの値は、ログ上では[FILTERED]と表示される。

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

[Rails]Google Analytics コンバージョンタグを設定する

目標(コンバージョン率の測定)とは

Google Analyticsの機能で、「会員登録」「コンテンツ登録」「5ページ以上の閲覧」など目標を設定することにより、Webサイトの指標を出すことができます。
僕のWebサイト( https://www.mini4wg.com/ )でも目標設定をしたので、設定項目や実装方法などを解説していきます。

スクリーンショット 2020-10-27 14.05.21.png

目標設定 1/3

テンプレートが準備されており非常に便利です。google analyticsを指定してあれば、サイトに手を入れ図に対応することもできます。
しかし、画面遷移などによってはコンバージョンタグを仕込むなどの準備が必要になります。

最初の目標では
 - 収益
 - 集客
 - 問い合わせ
 - ユーザーのロイヤリティ
など良く使われる項目が最初から定義されています。自分のサイトにあった目標を設定しましょう。

スクリーンショット 2020-10-27 14.13.49.png

目標の説明 2/3

目標の説明では測定のタイプを設定します。
- 到達ページ
- 滞在時間
- ページビュー数
- イベント
が設定できます。

スクリーンショット 2020-10-27 14.25.22.png

目標の詳細 3/3

目標の説明(2/3)で設定したタイプにより、ここのフォームが変化します。
イベントを選択した場合は、Webサイトからeventを送信する必要があります。
到達ページや滞在時間やページビューはGoogle Analyticwの画面から設定するだけで利用可能です。

スクリーンショット 2020-10-27 14.28.03.png

Railsでイベントを送信する場合

僕のサイトでも画像を登録する機能があるのですが、コンバージョンを測定するのに作成時に一度だけ送信したい時に下記の様な実装を行いました。
※ gtag.jsかanalytics.jsかでevent送信のコードが違うのでご注意ください。
僕のサイトではコンテンツ送信を測定する場合,ECサイトではよくある[thanks.html]などのサンクスページないため、
作成時に一回限りだけjavascriptのタグを出力し、google analyticsにeventを送信する様にしました。

ProductsController

ruby
class ProductsController < ApplicationController
  =省略=
  def create
    @product = current_user.products
                           .build(product_params)
    authorize @product

    if @product.save
      flash[:cv] = true
      redirect_to @product, notice: t('.saved')
    else
      render :new
    end
  end
 =省略=
end

views/products/show.html.slim

slim
~~省略
- if flash[:cv] == true
  javascript:
    gtag('event', 'created', { 'event_category': 'products', 'event_label': '#{@product.id}'});
~~省略

確認方法

実際にeventの送信が行われているかは下記のChrome Extensionを入れることにより、どんなeventが送信されているかわかります。

Page Analytics (by Google) - Chrome ウェブストア https://chrome.google.com/webstore/detail/page-analytics-by-google/fnbdnhhicmebfgdgglcdacdapkcihcoh/related?hl=ja

最後に

目標設定をすることにより、サイトの改善に役立てると共に人に説明する時にも指標があると非常に便利です。

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

initializeメソッドの役割について

initializeメソッド萌えという謎のジャンルを一人で開拓していた時期があったんですが受講生様からクラスとインスタンス、インスタンスメソッドとクラスメソッドの分類と役割の違いについてよく質問を受けるので、改めて上記リンク先記事で言及しているものをコード化しようと思います。

【イニシャライズが可愛いって話】
https://qiita.com/yamazaki_akihiro/private/32ea4cf5e653913d2485

class Mother

  def initialize(sleeper)
    puts "#{sleeper}の部屋に入りましたが起きる気配はありません。実に穏やかな寝姿です"
    @sleeper = sleeper
  end

  def ding_frypan
    puts "「イヤーーーッッ!!!」※フライパンをガンガン鳴らしています。割と近所迷惑です"
    puts "「グワーーーッッ!!!」#{@sleeper}の断末魔!"
  end

  def open_curtain
    puts "「イヤーーーッッ!!!」※カーテンを勢いよく開けました。レールに負荷をかけるのであまり推奨されません"
    puts "「グワーーーッッ!!!」#{@sleeper}の断末魔!"
  end

  def strip_duvet
    puts "「イヤーーーッッ!!!」※布団をひっぺがしました。これがラブコメならこのあと色々あって二人は遅刻しますが今回は違います"
    puts "「グワーーーッッ!!!」#{@sleeper}の断末魔!"
  end

  def self.go_job
    puts "「遅刻してもお母さん知らないからね!」"
    puts "そして母は朝靄に包まれた街へ消えていった..."
  end
end

puts "7時です。そろそろ寝坊助を起こしますか?"
puts "1, 部屋へ行って起こす"
puts "2, 起こさずに仕事へ出かける"
num = gets.to_i
if num == 1
  puts "誰を起こしますか?"
  sleeper = gets.chomp
  mother = Mother.new(sleeper)
  puts "どうやって起こしますか?"
  puts "1, フライパンをガンガン鳴らす(うるさいぞ!)"
  puts "2, カーテンを開けて朝の陽射しを食らわせる(眩しいぞ!)"
  puts "3, 布団をひっぺがす(寒いぞ!※あと思春期だとちょっと恥ずかしいかも)"
  plan = gets.to_i
  if plan == 1
    mother.ding_frypan
  elsif plan == 2
    mother.open_curtain
  elsif plan == 3
    mother.strip_duvet
  else
    puts "ほんとは起こす気ないでしょ。ほな仕事いきましょ"
    Mother.go_job
  end
elsif num == 2
  Mother.go_job
else
  puts "貴様ッッッ!さては母親ではないなッッッ!!!何奴!!?"
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】SameSiteとSecure属性の付与〜Railsのセキュリティ対策〜

はじめに

社内でcookieのセキュリティに関する勉強会があったので、学んだことをまとめておきます〜〜:writing_hand::writing_hand:
Railsは優秀なフレームワークなので、そこそこのセキュリティ対策が標準装備されているんですよねえ。
セキュリティについてはあまり考えなくても、実装できてしまうんですよねえ。
良いことでもあり、悪いことでもありますね:runner::runner:

GoogleChrome80のリリース

2020年2月4日(現地時間)にGoogleChrome80が正式にリリースされました。
https://developers-jp.googleblog.com/2019/11/cookie-samesitenone-secure.html
今回のバージョンアップでデフォルトのCookieのSameSite属性がNone⇒Laxに変更されました。
またSameSite属性をNoneにする場合、Secure属性を付与しなければならない仕様になりました。

???
なにそれ??

私もピンと来ませんでしたし、よくわからない方もいるかも知れないので、ざっくり解説します。

SameSite属性

SameSite属性とは、CSRF(クロスサイトリクエストフォージェリ)というサイバー攻撃からユーザーを守るために、Cookieに付与される属性のことです。
安全のためのCookieのオプション設定みたいに考えておいてください。

GoogleChrome80からこれのデフォルト値がNone⇒Laxに変更になったのです。
簡単に言うとセキュリティが強化されましたということです。
最近、Googleはセキュリティ対策に厳しいですからね〜

SameSite属性は三段階にわかれています。

属性 内容
None ドメインをまたいでCookieの受け渡しが可能
Lax (GETでのリクエストのみ)ドメインをまたいでCookieの受け渡しが可能
Strict ドメインをまたいでCookieの受け渡しが不可

セキュリティのレベル的には
None < Lax < Strictですね。

つまり、ドメインをまたいでCookieの受け渡しができるか?できないのか?という違いを設定する設定のことですね!

secure属性

Secure属性はHTTPS化していないCookieの動作を制御する属性のことです。
Secure属性が付与されているCookieはHTTPS通信の場合のみ送信できます。
要はCookieが盗まれにくくなります。

GoogleChrome80からはSameSiteがNoneのときはSecure属性を付与しなければならない仕様に変更になりました。

つまり「SameSiteがNoneなんだろ?セキュリティー不安だからせめてSecure属性くらいつけておけよ〜」というGoogle様からのお達しということですね。

Railsでの設定

ではGoogleChrome80の仕様もSameSite属性・secure属性も理解したところで、Railsで設定をしてみましょう!

Gemfile
gem 'rails_same_site_cookie'
ターミナル
bundle install

はい。これだけです。

特に設定等もいりません。gem「rails_same_site_cookie」をインストールするだけです。
めちゃめちゃ簡単ですね。
自動的に全cookieにSameSite=None; Secure属性が追加してくれます。

確認方法

確認方法も簡単です。
chromeの検証からApplicationをクリックして、使用中のCookieの中身を見ます。
secure属性にチェックが入っていて、SameSite属性がNoneになっていたらOKです。

スクリーンショット 2020-10-23 18.31.24.png

※ローカル環境では確認できないことがあるので注意してくださいね〜

おわりに

勉強会でとんでもないハッカーに出会ってしまったので、毎日震えながら開発しています:baby::baby:

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

[Payjp] Payjp::InvalidRequestError No such tokenの解決法

概要

Payjpでcustomerを作成しようとした際、No such tokenというエラーを解決するのに時間を要したため、解決した流れを記載しておきます。

エラーの内容

Image from Gyazo

上記のように、そのようなトークンはありませんと言われてしまいました。

  • トークンはJs→Rails側に送信できている
  • Completed 500 Internal Server Error

となっているため、サーバーサイド側のエラーだと思い、秘密鍵が合っているか等、色々試してみましたが解決できませんでした。

card.jsの記述

サーバーサイド側のエラーだと踏んでいたのですが、jsの記述も確認してみました。

card.js
const pay = () => {
  Payjp.setPublicKey(process.env.PAYJP_PUBLIC_KEY);
  const form = document.getElementById("charge-form");
  form.addEventListener("submit", (e) => {
    e.preventDefault();
    const formResult = document.getElementById("charge-form");
    const formData = new FormData(formResult);

    const card = {
      number: formData.get("number"),
      cvc: formData.get("cvc"), 
      exp_month: formData.get("exp_month"),
      exp_year: `20${formData.get("exp_year")}`
    };
    Payjp.createToken(card, (status, response) => {
      if (status === 200) {
        const token = response.id;
        const renderDom = document.getElementById("charge-form");
        const tokenObj = `<input value=${token}, type="hidden", name="card_token">`;
        renderDom.insertAdjacentHTML("beforeend", tokenObj);

        document.getElementById("card-number").removeAttribute("name");
        document.getElementById("card-exp-month").removeAttribute("name");
        document.getElementById("card-exp-year").removeAttribute("name");
        document.getElementById("card-cvc").removeAttribute("name");

        renderDom.submit();
        renderDom.reset();
      }
    });
  });
};
window.addEventListener("load", pay);

特におかしなところは無いように思えます・・・。

ある違和感

同じような記述で、jsを使って商品の合計金額(total_price)をサーバーサイドに送信するコードも書いていました。

sendTotalPrice.js
function sendTotalPrice() {
  const totalPriceDom = document.getElementById("cart-total-price")
  const totalPrice = parseInt(totalPriceDom.innerHTML);

  const renderDom = document.getElementById("charge-form");
  const totalPriceObj = `<input value=${totalPrice}, type="hidden", name="total_price">`;
  renderDom.insertAdjacentHTML("beforeend", totalPriceObj);
};
window.addEventListener('load', sendTotalPrice);

ここでおかしいと感じたことがあります。
Image from Gyazo
送信されたparamsのtotal_priceの中に
Image from Gyazo
不要な " , " が入ってしまっています。

原因はjs内の記述だった

トークンの値をフォームに含めるための記載に間違いがありました。

間違い
 const tokenObj = `<input value=${token}, type="hidden", name="card_token">`;
正しい
 const tokenObj = `<input value=${token} type="hidden" name="card_token">`;

value=${token}のあとのカンマ "," は不要でした!

勉強になったこと

Rails等のform_withなどでは属性を区切るためにカンマが必要ですが、HTML要素では属性を区切るカンマは不要ですね・・・。


同じような内容で悩まれている方がもしいらっしゃったら、参考になれば幸いです。

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

メソッド、Proc、Method クラスのオブジェクトの作り方とその実行

メソッド

メソッドの定義

メソッド定義

def メソッド名(引数)
  # 式
end

endless メソッド定義

Ruby 3 から使用可(予定)

def メソッド名(引数) = # 式

メソッドの呼び出し

レシーバ.メソッド名(引数)

Proc クラス

Proc クラスのオブジェクトの作り方

Proc

Proc.new{|引数| }
proc{|引数| }
Symbol または Hash または Method クラスのオブジェクト.to_proc[引数]

lambda

lambda{|引数| }
-> (引数){}

Proc オブジェクトの実行

レシーバ[引数]
レシーバ.(引数)
レシーバ.call(引数)
レシーバ.yield(引数)
レシーバ === # 引数

Method クラス

Method クラスのオブジェクトの作り方

レシーバ.method(メソッド名の Symbol または String)

メソッドの起動

レシーバ[変数]
レシーバ.(変数){}
レシーバ.call(変数){}
レシーバ === 変数

参考文献

class Proc
class Method

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

【Ruby on Rails】確認ページ作成

目標

画面収録 2020-10-25 18.11.03.mov.gif

開発環境

ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

準備

今回はscaffoldを使用し、投稿の確認画面を作成します。

ターミナル
$ rails g scaffold post body:string
$ rails db:migrate

controllerの編集

下記を追加。

app/controllers/posts_controller.rb
def confirm
  @post = Post.new(post_params)
end

routeの編集

下記を追加

config/routes.rb
  resources :posts
  post 'posts/confirm', to: 'posts#confirm', as: 'confirm'

viewの編集

このままの状態であれば、new画面で投稿するとcreateアクションが実行され、保存されてしまいます。
したがって、new画面からはconfirmにparamsを飛ばすよう記述します。
<%= render 'form', post: @post %>を削除し、下記のように記述します。

app/viwes/posts/new.html.erb
<h1>New Post</h1>

<%= form_with(model: @post, local: true, url: confirm_path) do |form| %>
  <% if @post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>

      <ul>
      <% @post.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :body %>
    <%= form.text_field :body %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>


<%= link_to 'Back', posts_path %>

app/viwes/posts配下にconfirm.html.erbを作成します。
<%= @post.body %>で投稿内容を表示し、
<%= form.hidden_field :body %>でcreateアクションにparamsを渡しています。

app/viwes/posts/confirm.html.erb
<div>投稿内容確認<br><br>
  <%= @post.body %><br><br>
</div>
<%= form_with(model: @post, local: true) do |form| %>
  <div class="actions">
    <%= form.hidden_field :body %>
    <%= form.submit %>
  </div>
<% end %>

まとめ

投稿画面での確認画面はあまりないとは思いますが、
新規登録画面ではよく見る表示だと思いますので、
会員登録等の機能を実装するなら必須の機能です。

またtwitterではQiitaにはアップしていない技術や考え方もアップしていますので、
よければフォローして頂けると嬉しいです。
詳しくはこちら https://twitter.com/japwork

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

【Rails】アプリケーションを削除してみた

はじめに

テストで作成したミニアプリを削除てみました。備忘録もかねて記事に残します。

目次

1.手順
2.削除

1. 手順

・データベースの削除
・フォルダ削除

アプリを削除するには、ただフォルダを削除すれば良いと思っていました。
しかし、それではデータベースがの残ったままなので、不具合が起きる可能性があります。

下記に参考にさせていただいた記事があります。アプリ以外もいろんなフォルダの削除方法を紹介されてるので、興味がある方は参考にしてみてください。

2. 削除

それでは削除して行きます〜

・データベースの削除

$ rails db:drop

開発とテスト二つのデータベースが削除されれば成功です。

・フォルダ削除

$ cd ..
$ rm [アプリ名]

コマンドで削除可能ですが、ファインダーからゴミ箱に入れても削除できます。

以上です!

最後に

私はプログラミング初学者ですが、同じ様に悩んでる方々の助けになればと思い、記事を投稿しております。
それでは、また次回お会いしましょう〜

参考

https://qiita.com/ruemura3/items/63eb805aa2b4e250df81

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

【Ruby】Rails/Sinatraを使わない場合のrbファイル実行時、i18nに`en is not a valid locale (I18n::InvalidLocale)'怒られる

背景

記事を書いた理由

公式サイトを見ればすぐに分かる何の事はない内容ですが、
ブログだったりQiitaのような、
わかりやすさ重視の非一次情報はなかなか見つからなかったので。

状況

メタプログラミングRubyMonetizeの例の項を実行していた時。
このような表示に。

ruby $ ruby 202010270014.rb
[WARNING] The default rounding mode will change from `ROUND_HALF_EVEN` to `ROUND_HALF_UP` in the next major release. Set it explicitly using `Money.rounding_mode=` to avoid potential problems.
[DEPRECATION] You are using the default localization behaviour that will change in the next major release. Find out more - https://github.com/RubyMoney/money#deprecation
Traceback (most recent call last):
  10: from 202010270014.rb:5:in `<main>'
   9: from /Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/money-6.13.8/lib/money/money.rb:600:in `format'
   8: from /Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/money-6.13.8/lib/money/money/formatter.rb:232:in `to_s'
   7: from /Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/money-6.13.8/lib/money/money/formatter.rb:257:in `format_number'
   6: from /Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/money-6.13.8/lib/money/money/formatter.rb:333:in `format_whole_part'
   5: from /Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/money-6.13.8/lib/money/money/formatter.rb:238:in `thousands_separator'
   4: from /Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/money-6.13.8/lib/money/money/formatter.rb:366:in `lookup'
   3: from /Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/money-6.13.8/lib/money/locale_backend/legacy.rb:15:in `lookup'
   2: from /Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/money-6.13.8/lib/money/locale_backend/i18n.rb:19:in `lookup'
   1: from /Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/i18n-1.6.0/lib/i18n.rb:182:in `translate'
/Users/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/i18n-1.6.0/lib/i18n.rb:326:in `enforce_available_locales!': :en is not a valid locale (I18n::InvalidLocale)

ソースコード

エラー発生時

error.rb
require "monetize"
bargain_price = Monetize.from_numeric(99, "USD")
p bargain_price.format

エラー解消時

success.rb
require "monetize"
I18n.load_path << Dir[File.expand_path("config/locales") + "/*.yml"]
I18n.default_locale = :en # (note that `en` is already the default!)
bargain_price = Monetize.from_numeric(99, "USD")
p bargain_price.format

公式リポジトリのREADMEより2,3行目を拝借。
上記のソースの書き換え+config/locales/en.ymlにymlファイルを設置。
その中身は公式リポジトリのREADMEそのままで以下。

en.yml
en:
  test: "This is a test"

実行時表示

ruby $ ruby 202010270014.rb
[WARNING] The default rounding mode will change from `ROUND_HALF_EVEN` to `ROUND_HALF_UP` in the next major release. Set it explicitly using `Money.rounding_mode=` to avoid potential problems.
[DEPRECATION] You are using the default localization behaviour that will change in the next major release. Find out more - https://github.com/RubyMoney/money#deprecation
[DEPRECATION] You are using the default localization behaviour that will change in the next major release. Find out more - https://github.com/RubyMoney/money#deprecation
"$99.00"

WARNINGなんかは出ていますが、一応動作しました。

参考文献/サイト

メタプログラミングRuby
i18n公式リポジトリ

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

RspecのテストでArgumentError: wrong number of arguments (given 2, expected 0)が出た時の対処法

はじめに

RSpecのテストを実行したときに

   Failure/Error:
       post login_path, params: { session: { email: user.email,
                                             password: user.password } }

     ArgumentError:
       wrong number of arguments (given 2, expected 0)

と出てエラー解決に時間がかかったので書いていきます。

エラー内容

このエラーは「呼び出し側の引数」(given 2)と2に対して「メソッド側の仮引数」(expect 0)で0ですよと言われています。何らかの理由で値にズレが生じているということです。

発生した原因

RSpecのコード内で

let!(:post) { create(:post, user: user) }

という記述をしていて、post login_path, params: { session: { } }のpostがget,post,deleteなどのpostではなくてRSpecコード内のlet!(:post)を呼び出してしまっているから。

解決方法

先ほどあったコードの名前を変えてあげるだけです。

let!(:new_post) { create(:post, user: user) }

参照

https://qiita.com/yo0917/items/20c165a3b06805bf2e37

最後に

すごい初歩的なミスかもしれませんがRSpec書きたての僕はすごい悩まされたので今後も頑張って解決していきたいです。
文章力も上げていきたいです。

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

RSpecのテストでArgumentError: wrong number of arguments (given 2, expected 0)が出た時の対処法

はじめに

RSpecのテストを実行したときに

   Failure/Error:
       post login_path, params: { session: { email: user.email,
                                             password: user.password } }

     ArgumentError:
       wrong number of arguments (given 2, expected 0)

と出てエラー解決に時間がかかったので書いていきます。

エラー内容

このエラーは「呼び出し側の引数」(given 2)と2に対して「メソッド側の仮引数」(expect 0)で0ですよと言われています。何らかの理由で値にズレが生じているということです。

発生した原因

RSpecのコード内で

let!(:post) { create(:post, user: user) }

という記述をしていて、post login_path, params: { session: { } }のpostがget,post,deleteなどのpostではなくてRSpecコード内のlet!(:post)を呼び出してしまっているから。

解決方法

先ほどあったコードの名前を変えてあげるだけです。

let!(:new_post) { create(:post, user: user) }

参照

https://qiita.com/yo0917/items/20c165a3b06805bf2e37

最後に

すごい初歩的なミスかもしれませんがRSpec書きたての僕はすごい悩まされたので今後も頑張って解決していきたいです。
文章力も上げていきたいです。

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

カレンダーから日付を選択するフォーム作成方法

普通の入力フォーム(変更前)

ビューファイル
<%= form.text_area :day, placeholder: "day" %>

前.png

カレンダー選択フォーム(変更後)

text_area → datetime_fieldに変更する。

ビューファイル
<%= form.datetime_field :day, placeholder: "day" %>

後.png

まとめ

変更前は色々と記述しないといけなくて難しいのかと思うかもしれませんが、
実際は記述を少し変えるだけでできちゃうんです!!
ぜひ、やってみて下さい。

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

演算子とは

演算子

プログラミングにおける値の計算や比較などに使用する記号のことです。
計算における代表的な演算子は+-、比較における代表的な演算子は><があります。

この簡単な記号である演算子を用いることで、計算や比較処理を瞬時に行ってくれます。

代数演算子

演算子の中でも計算を行うものは、代数演算子と呼ばれます。
Rubyで一般的な計算をする場合、以下の様な演算子が使えます。

演算子.png

使い方は、普通の算数の計算と同じです。ただし、剰余の計算は馴染みがないので注意が必要です。
例えば、「17を5で割ったときの余り」を求めることができます。

以下の例を見てください。

【例】irb
# 足し算
irb(main):001:0> 1000 + 2000
=> 3000

# 引き算
irb(main):002:0> 3000 - 1500
=> 1500

# 掛け算
irb(main):003:0> 50 * 40
=> 2000

# 割り算
irb(main):004:0> 600 / 15
=> 40

# 剰余演算5 ÷ 2をした余り
irb(main):005:0> 5 % 2
=> 1

irbで以下のコードを実行しましょう

1年は何時間か計算してみましょう。

irb
irb(main):001:0> 24 * 365

実行すると、一瞬で計算結果が表示されますね。
実際にやってみて下さいね!!

まとめ

・演算子とは、プログラミングにおける値の計算や比較などに
使用する記号のこと。
・代数演算子とは、演算子に属し、その中でも計算を行うもの。

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

【Rails6】jQuery導入・uncaught reference error $ is not definedエラーの解決法

開発環境

  • Rails 6.0.0
  • yarn 1.22.4

目次
1)jQuery導入
2)uncaught reference error $ is not definedエラーの解決法

1) jQuery導入_箇条書き

 1. yarn add jquery でjqueryを導入
 2. environment.jsへ webpackの設定ファイルにjQueryを管理下に追加する記述を書く
 3. application.jsへ jQueryを呼び出すための記述を書く
 4. application.html.erbへ javascriptの呼び出しが記述されているか念の為確認

1) jQuery導入_詳しく解説

 1. yarn add jquery でjqueryを導入

ターミナル
$ yarn init *補足:OSにHomebrewでyarnインストールをすでにされている場合は不要だと思います。
$ yarn add jquery

*補足:私は"yarn add jquery"だけで問題ないのですが、他の方の記事を確認したところ、"yarn init"を先に入力するという説明もあったので、補足として記載させていただきます。『Homebrewでyarnインストール』についてはこちらの記事が参考になると思います。

*補足2:
gem 'jquery-rails'をGemfileへ記述する方法もありますが、Rails6からはyarn addが推奨されているらしいです。Webpackerで管理しているため、Node.jsのパッケージを利用しています。

 2. environment.js

app/config/webpack/environment.js
//この記述内容をコピペ(もともとの記述は削除でOK)
//これは、webpackの設定ファイルでjQueryを管理下に追加するための記述です。
const { environment } = require('@rails/webpacker')
const webpack = require('webpack')

environment.plugins.prepend('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    jquery: 'jquery',
  })
)

module.exports = environment

 3. application.js

app/javascript/packs/application.js
// 省略
require("@rails/ujs").start()
require("turbolinks").start()  //私はいつもコメントアウトします
require("@rails/activestorage").start()
require("channels")
require('jquery') //ここを追記
// 省略

*補足:turbolinksはキャッシュを積極的に利用するため、ページがロードされてから起こるイベントがうまく動かないことがあります。私はjavascriptを使う上で少し厄介だなという認識なので、コメントアウト。(キャッシュを利用するとページの読み込み時間は短縮されるんですけどね)

 4. application.html.erb **念のために確認

app/view/layouts/application.html.erb
<!-- tourbolinksを削除する場合こうなります -->
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_pack_tag 'application' %>

ここまでがJqueryを導入するまでの一連の流れです。

2) $ is not definedエラーの解決法

$がnot defined(定義されていない)ということは、jQueryがうまく入れることができていないということなので、jQuery導入で説明した4ステップを確認すれば、解決するのではないかなと思います。

 1. yarn add jquery でjqueryを導入
 2. environment.jsへ webpackの設定ファイルにjQueryを管理下に追加する記述を書く
 3. application.jsへ jQueryを呼び出すための記述を書く
 4. application.html.erbへ javascriptの呼び出しが記述されているか念の為確認

以上です。

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

Rails学習 2日目その2

Ruby on Rails5速習実践ガイド chapter5

5-4 本章で記述するテストの種類(RSpec)

テストの一番外枠に位置しているシステムテスト(System Test)が重要
RSpecとはSystemTestが行われるソフトみたいなもの
systemtestの中ではcapybaraというソフトがまるでウェブアプリケーションを実行しているかのように動き、その動きの中でシステムエラーが無いかなどを見てくれる。

5-7 FactoryBotでテストデータを作成できるように準備する

まずはじめにデータベースを使ってテストをする時にはテスト用のデータがないと話にならない。FactoryBotでテストデータを作成し、そこからテストという流れになっている。ここではFactoryBotでの具体的なデータの書き方を見てみる。テストを実行するために必要な具体的な工程は2つある
1.FactoryBotでデータを作成するためのテンプレートを作成する。
2.SystemSepcの適切なbeforeなどで、FactoryBotのテンプレートを利用してテスト用データベースにテストデータを投入する。

spec/factories/users.rb
FactoryBot.define do
 factory :user do #①
  name {'テストユーザー'}
  email {'test@example.com'}
  password {'password'}
 end
end

factoryというメソッドを書きその中にユーザー情報(仮)の値を入れた。これがテスト用のデータになる。
①factory:〇〇 do(今回はuser)この〇〇の部分がこのファクトリーの名前となり呼び出す時に使う名前となる。基本は作ったデータのテーブルに対応するクラス(userテーブルに対応するのはuserクラス)の名前を使う。そうすることによってクラス名もfactoryメソッド名も両方をまとめることができる。
しかしどうしてもクラス名とメソッド名が違う物を用いたい場合は

factory :admin_user, class: User do

上記のようにfactory :ファクトリー名, class:クラス名 doというようにしてもいい

テスト用のTaskデータも作成する

spec/factories/tasks.rb
FactoryBot.define do
 factory :task do 
  name {'テストを書く'}
  description {'RSpec & Capybara & FactoryBotを準備する'}
  user  #①
 end
end

①上記のuserはtaskとuserを関連付けるためのもの(この作ったタスクはどのユーザーのものなのかをここに書く)

5-8 タスクの一覧表示機能のSystemSpec

上記では
1.FactoryBotでデータを作成するためのテンプレートを作成する。
2.SystemSepcの適切なbeforeなどで、FactoryBotのテンプレートを利用してテスト用データベースにテストデータを投入する。
の1番を行ってきた。次に2番のテストをSystemSpecを用いて行う。今回は

一覧画面に移ったら作成済みのタスクが表示されている

といった動作が正しく動くかテストコードを書いて確認してみる。
まず確認するためには動くようのテストコードを書かなければならない。テストコードは

①ユーザーAを作成しておく(準備)
②作成者がユーザーAであるタスクを作成しておく(準備)
③ユーザーAでブラウザからログインする(準備)
④ユーザーAの作成したタスクの名称が画面上に表示されていることを確認(実行)

この4つの工程をテストコードで書いていく

①ユーザーAを作成しておく(準備)

spec/system/tasks_spec.rb
user_a = FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')

userという名前のファクトリーを引っ張り出してきてその情報をuser_aとしている.
後ろについているnameやemailを書くことによって内容を変更しユーザーAだけの情報が作られる(なおpasswordなどの変更していない部分はfactoryメソッドを作った時に設定した値になる)

②作成者がユーザーAであるタスクを作成しておく(準備)

spec/system/tasks_spec.rb
FactoryBot.create(:task, name: '最初のタスク', user:user_a)

user:user_aと書くことでこのタスクはuser_aが書いたということになる。

③ユーザーAでブラウザからログインする(準備)
ログインするには

A.ログイン画面にいく
B.メールアドレスを入力する
C.パスワードを入力する
D.「ログインする」ボタンを押す

という動作が必要。

A.ログイン画面にいくにはvisit login_pathという書き方で実行できる(visit URL)

spec/system/tasks_spec.rb
visit login_path

B.メールアドレスを入力する、C.パスワードを入力するにはfill_inメソッドを使う

spec/system/tasks_spec.rb
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'

D.「ログインする」ボタンを押すにはclick_buttonメソッドを使う

spec/system/tasks_spec.rb
click_button'ログインする'

③をまとめると

spec/system/tasks_spec.rb
visit login_path
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'
click_button'ログインする'

このようになる。

④ユーザーAの作成したタスクの名称が画面上に表示されていることを確認(実行)

確認するにはRSpec独自の書き方で

expect(page).to have_content '最初のタスク'

expect(page).to→画面に期待するよ
have_content '最初のタスク'→最初のタスクというコンテンツがあるかどうか
という意味になる

以上の操作を1つのコードにまとめてみる
①②③は準備のためのコードなのでbefore
④は実行のためのコードなのでitを使い記入する

spec/system/tasks_spec.rb
require 'rails_helper'

describe 'タスク管理機能',type:system do #一番大枠のdescribeにはtype:systemをつける
 describe '一覧表示機能' do
   before do
    user_a = FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')
    FactoryBot.create(:task, name: '最初のタスク', user:user_a)
   end

   context'ユーザーAがログインしているとき' do
     before do
       visit login_path
       fill_in'メールアドレス', with: 'a@example.com'
       fill_in'パスワード', with: 'password'
       click_button'ログインする'
     end

     it'ユーザーAが作成したタスクが表示される' do
       expect(page).to have_content '最初のタスク'
     end
   end
 end
end

PSpecの概要

Untitled-1 copy.jpg

5-10 beforeを利用した共通化

ユーザーAだけでなくユーザーBがログインしているパターンを作る

spec/system/tasks_spec.rb
require 'rails_helper'

describe 'タスク管理機能',type:system do #一番大枠のdescribeにはtype:systemをつける
 describe '一覧表示機能' do
   before do
    user_a = FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')
    FactoryBot.create(:task, name: '最初のタスク', user:user_a)
   end

   context'ユーザーAがログインしているとき' do
     before do
       visit login_path
       fill_in'メールアドレス', with: 'a@example.com'
       fill_in'パスワード', with: 'password'
       click_button'ログインする'
     end

      it'ユーザーAが作成したタスクが表示される' do
        expect(page).to have_no_content '最初のタスク'
      end
   end

   context'ユーザーBがログインしているとき' do
     before do
       visit login_path
       fill_in'メールアドレス', with: 'b@example.com'
       fill_in'パスワード', with: 'password'
       click_button'ログインする'
     end

     it'ユーザーAが作成したタスクが表示されない' do
       expect(page).to have_no_content '最初のタスク'
     end
   end
 end
end

visit login_path
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'
click_button'ログインする'
が2つあってわかりにくくなる。なのでこれを1つにまとめる。

spec/system/tasks_spec.rb
require 'rails_helper'

describe 'タスク管理機能',type:system do #一番大枠のdescribeにはtype:systemをつける
 describe '一覧表示機能' do
   before do
    user_a = FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')
    FactoryBot.create(:task, name: '最初のタスク', user:user_a)

    visit login_path
    fill_in'メールアドレス', with: 'a@example.com'
    fill_in'パスワード', with: 'password'
    click_button'ログインする'
   end

   context'ユーザーAがログインしているとき' do
     it'ユーザーAが作成したタスクが表示される' do
       expect(page).to have_content '最初のタスク'
     end
   end

   context'ユーザーBがログインしているとき' do
     before do
       FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')
     end

     it'ユーザーAが作成したタスクが表示されない' do
       expect(page).to have_no_content '最初のタスク'
     end

   end
 end
end

ユーザーAがログインしているときは上のitを実行し、ユーザーBがログインしているときは下のitを実行する。

5-11 letを利用した共通化

FactoryBotで作ったデータをletを使って変数みたいに扱うことができる。

spec/system/tasks_spec.rb
require 'rails_helper'

describe 'タスク管理機能',type:system do #一番大枠のdescribeにはtype:systemをつける
 describe '一覧表示機能' do
   let(:user_a){FactoryBot,create(:user, name:'ユーザーA', email: 'a@example.com')} #ユーザーAを作ったパターン
   let(:user_b){FactoryBot,create(:user, name:'ユーザーB', email: 'b@example.com')} #ユーザーBを作ったパターン


   before do
    FactoryBot.create(:task, name: '最初のタスク', user:user_a)
    visit login_path
    fill_in'メールアドレス', with: login_user.email #ログインするのがAかBかわからないのでどちらでも行けるようにする
    fill_in'パスワード', with: login_user.password #ログインするのがAかBかわからないのでどちらでも行けるようにする
    click_button'ログインする'
   end

   context'ユーザーAがログインしているとき' do
     let(:login_user){user_a} #上で定義したユーザーAの情報を引き出す
     it'ユーザーAが作成したタスクが表示される' do
       expect(page).to have_content '最初のタスク'
     end
   end

   context'ユーザーBがログインしているとき' do
     let(:login_user){user_b} #上で定義したユーザーBの情報を引き出す

     it'ユーザーAが作成したタスクが表示されない' do
       expect(page).to have_no_content '最初のタスク'
     end
   end
 end
end

5-13 shared_exampleを利用する

同じitの結果を様々なdescribeで実行する時にまとめる方法

#it操作をshared_example_forに書く
shared_example_for 'ユーザーAが作成したタスクが表示される' do
   it {expect(page).to have_content '最初のタスク'}
end

#it_behaves_likeと書くだけでit操作を一回一回書かなくていいようになる
it_behaves_like 'ユーザーAが作成したタスクが表示される'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Herokuへデプロイする手順

Herokuへデプロイする手順

ターミナル
brew tap heroku/brew && brew install heroku
ターミナル
heroku --version
ターミナル
# Herokuへログインするためのコマンド
% heroku login --interactive
  => Enter your Heroku credentials.
# メールアドレスを入力しエンターキーを押す
  => Email:
# パスワードを入力してエンターキーを押す
  => Password:
Gemfile
# ファイルの一番下の行に追記する
group :production do
  gem 'rails_12factor'
end
ターミナル
# Gemをインストール
% bundle install
ターミナル
% git add .
% git commit -m "gem rails_12factorの追加"
ターミナル
% heroku create アプリケーション名
ターミナル
% git config --list | grep heroku
ターミナル
% heroku addons:add cleardb
Creating cleardb on  アプリケーション名... free
Created cleardb-vertical-00000 as CLEARDB_DATABASE_URL
Use heroku addons:docs cleardb to view documentation
ターミナル
% heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL`
ターミナル
% heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5}

# 以下コマンドの実行結果
Setting DATABASE_URL and restarting  アプリケーション名... done, v◯◯
DATABASE_URL: mysql2://000000000000:0aa0000@us-cdbr-east-02.cleardb.com/heroku_aaa00000000?reconnect=true
ターミナル
% EDITOR="vi" bin/rails credentials:edit
ターミナル
% heroku config:set RAILS_MASTER_KEY=`cat config/master.key`
ターミナル
% heroku config
ターミナル
% git push heroku master
ターミナル
% heroku run rails db:migrate

公開を確認

ターミナル
% heroku apps:info

===ajax-app-123456
Addons:         cleardb:ignite
Auto Cert Mgmt: false
Dynos:          web: 1
Git URL:        https://git.heroku.com/アプリケーション名.git
Owner:          sample@sample.com
Region:         us
Repo Size:      165 KB
Slug Size:      56 MB
Stack:          heroku-18
Web URL:        https:/アプリケーション名.herokuapp.com/

現場からは以上です!

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