6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2021年9月18日 git resetとgit revertについて

git resetコマンド

間違えて"git add"、"git commit"をした場合、"git reset"を行うことでそれらの操作をなかったことにできます。コミットidを指定すると、指定したコミットまで戻ります。 resetはコミットIDを指定したコミット時点まで戻るが指定したコミットより新しい履歴が消えてしまうので リモートにプッシュしてからresetを使うと最終的に整合性が取れずコンフリクトを起こす場合があります。

reset --hard :add、commit、ワーキングツリーの取り消し

「ステージングエリアにも作業ディレクトリにも残らなくていいから、コミットをまるごと消したい」というときに使えるコマンドです。

# ひとつ前のコミットまでまるごと消したい
$ git reset --hard HEAD^

画像引用 画像引用

reset --mixed :commitとaddの取り消し

# ステージしたものを取り消したい
$ git reset --mixed HEAD
# オプション無しでも--mixedを実行したときと同じ結果が得られます
$ git reset HEAD

画像引用 画像引用

reset --soft :commitのみ取り消し

# 直前のコミット内容を修正したい
$ git reset --soft HEAD^

画像引用 画像引用
※HEADというのは、「自分が今いる位置」のことです。たいていはブランチの先頭のコミットを指していることが多いですが、それを過去のコミットに移動させることで、ブランチを過去に巻き戻すわけだが、そのときにステージも道連れにするのがmixedで、ステージも作業ディレクトリも道連れにするのがhardです。

※HEADの代わりにコミットIDを指定することもできます。コミットIDを使うと、指定した時点まで「HEAD・ステージングエリア・作業ディレクトリ」のすべてが巻き戻されます。
※git reset --hardを使う場合は、プッシュ前のコミットに対してのみ、使うようにする。

# 指定したコミットID時点までのHEAD・ステージングエリア・作業ディレクトリの状態が元に戻る
$ git reset --hard 02f11b7

git reflogコマンド

HEADでの動きが履歴として一覧表示することが出来ます。
・新規コミット(コミット、マージ、プル、リバートなど)
・ブランチの切り替え(チェックアウト)
・履歴の書き換え(リセット、リベースなど)
このコマンドとgit resetコマンドを使うことで、間違えてリセットしてしまっても指定した時点に戻すことが出来ます。

# 操作履歴を見る
$ git reflog
# 以下操作一覧
02f11b7 HEAD@{0}: reset: moving to 02f11b7
0488e28 HEAD@{1}: merge develop: Merge made by the 'recursive' strategy.
6978c20 HEAD@{2}: checkout: moving from develop to master#=> 間違えてresetしてしまった時点
32275f0 (develop) HEAD@{3}: commit: 制作事例を追加
0e95561 HEAD@{4}: checkout: moving from master to develop
6978c20 HEAD@{5}: commit: 3回目のコミット
0e95561 HEAD@{6}: commit: 2回目のコミット
02f11b7 HEAD@{7}: commit (initial): はじめてのコミット

# resetの操作をする前(1つ前)に戻したい場合
$ git reset --hard HEAD@{1} #=> 間違えて実行してしまったコマンドの1つ前まで戻る

git revert

revertはコミットの履歴自体は消さずに、指定したコミットidを作る前の状態に戻れます(結果としてコミットを消した状態になります)。 revertで指定したコミットを打ち消すようなコミットを作成します。そのコミットがあるおかげで、指定したコミットがなかったことになります。 間違えた時点で、新たにコミットをしてその作成したコミットをrevertすることで、間違える前の状態に戻れます。(ただし、コミットした履歴は残っています。)

$ git revert 消したいコミットid

画像引用

ポケモンに例えると

ジムリーダーに初挑戦する前にコミットして、負けたときに挑戦前に戻りたい場合
負けた後に新しくコミットする→負けた後の最新のコミットIDをgit revert コミットID にして実行する→ジムリーダーに初挑戦時に戻ります。

参照

第5話 プッシュ済みのコミットを取り消したい!リバートの使い方【連載】マンガでわかるGit ~コマンド編~

第6話 git reset 3種類をどこよりもわかりやすい図解で解説!【連載】マンガでわかるGit ~コマンド編~

第7話 間違えて reset しちゃった?git reflogで元どおり【連載】マンガでわかるGit ~コマンド編~

git commit を取り消して元に戻す方法、徹底まとめ

2021年9月17日 GitとGitHub

Gitとは?

ソースコードをはじめとしたファイルの変更履歴(バージョン)を管理することを「バージョン管理」と呼びます。 ファイルの追加や変更の履歴情報を管理することで、過去の変更箇所を確認する、特定時点の内容に戻す、などの「バージョン管理」という作業が可能となります。 そのバージョン管理を行うのがGitです。

GitHubとは?

複数人のエンジニアがリモートリポジトリとして活用する他、チーム開発を行うための機能を提供するWEBサービスGitHubです。

git status

git status コマンドは、このワークツリーという領域で変更・追加した状態のファイルや、インデックスという領域に反映されている状態のファイルを確認することができます。

つまり、現在のインデックスの状態を見ることができるのです。 画像引用

# 現在の状況を確認する
$ git status

#ディレクトリの状態を確認する
$ git status [ディレクトリ]

以下の表示結果では、項目ごとに該当するファイルを確認できます。

  • Changes to be committed = コミットする予定の変更したファイル(インデックスに反映されているファイル)
  • Changes not staged for commit = まだインデックスに追加されていない、変更したファイル
  • Untracked files = Gitでまだ管理されていないファイル(新しく追加したファイル) 画像引用

直前のコミットからの変更があった場合、以下のものがファイルの前についています

  • modified:修正したファイル
  • deleted:削除したファイル
  • Untracked files:新規作成したファイル

git add

git add コマンドを打つと、インデックスにaddで指定したファイルが入ります。(コミットする前の準備段階) インデックスとは、コミット前に変更内容を一時的に保存する領域を指し、インデックスに追加されたファイルのみがコミットの対象となります。

$ git add 変更したい(コミット)ファイル名
$ git add .
# git add .は変更したファイルを全て、インデックスに追加してしまうので、色んなファイルの変更したコミットする時は、色んな変更をしたコミットとして登録されます。
# 色んな変更をまとめてaddとcommitはしないほうが良い。

あどちょんの"ちょん"はカレントディレクトリを指しています。 カレントディレクトリ配下の全てのディレクトリやファイルを指定していることになります。

git commit

ファイルの追加・変更をローカルリポジトリに反映する操作を意味します。 以下のコマンドを入力すると、インデックスに存在するファイルがローカルリポジトリへ追加されます。

※)コミットは編集した機能や修正内容ごとにすることが大切です。1修正ごとにコミットするのをオススメします。
※)コミット時点で正常に機能しているか確認しましょう。

# Add:の部分はprefix名
$ git commit -m "Add:ファイル名"

ここで -m はコミットメッセージを入力するためのオプションです。 コミットメッセージは任意ですがAddやFixなどを先頭につけたり、作業内容などを分かりやすく書いておくと良いです。

push

ローカルのコードをリモートリポジトリに送ります。 画像引用

origin

リモートリポジトリの保管場所の名前です。 名前は実は変更することも出来ますが慣習的にoriginとされることが多いです。

GitHubのフォークとクローンの違い

  • clone リポジトリの複製をローカル環境に作成することを指します。 ローカルにクローンしたリポジトリに対しては、自由にコミット、プッシュ、マージをおこなうことができます。

  • fork リモート上で公開されているリポジトリを自分のGithubにコピー出来ます。フォークすると、オリジナルのリポジトリの所有者にforkしたことが通知されます。

単に公開されているリポジトリをベースにして何かを作ろう、とか、ビルドして動きを見てみようという場合ならforkを使います。

画像引用

じゃあ、ナイフは?git knife??🔪🔪🔪

参照

【超入門】初心者のためのGitとGitHubの使い方

GitHubのforkはリポジトリの複製 フォークの手順と、クローン、ブランチとの違い

GitHub初心者はForkしない方のPull Requestから入門しよう

リポジトリのフォークポリシーを管理する

【Git入門】git status の使い方(ファイルの状態を確認する)

2021年9月16日 現場Rails Chapter8-2-2 AjaxでRailsサーバーと通信する

前回はクライアント側でイベントハンドラとして用意してあったJavaScriptコードを実行してタスクを非表示にしていましたが、今回はAjax通信をした後にAjaxのリクエストボディにJavaScriptコードを返却してそれをブラウザ側で実行するという方法で削除機能の実装を行います。

Viewファイル

# app/views/tasks/index.html.slim
table.table.table-hover
  thead.thead-default
(略)
  tbody
    - @tasks.each do |task|
      tr id= "task-#{task.id}" # tr要素にタスクのid情報を与える
        td= link_to task.name, task

前回での方法との違う点で、サーバ側は、DOM要素としてどの削除ボタンがクリックされたことによってAjax通信が発生したのかが判別出来ないため、あらかじめDOM要素側にタスクのid情報を与えておく必要があります。  

Controllerファイル

# app/controllers/tasks_controller.rb
def destroy
  @task.destroy
end

JavaScriptファイル

# app/views/tasks/destroy.js.erb
document.querySelector("#task-<%= @task.id %>").style.display = 'none';

var message = document.createElement('p');
message.innerText = 'タスク「<%= @task.name %>」を削除しました。残りのタスクは<%= Task.count %>件です。';
document.querySelector('table').insertAdjacentElement('beforebegin', message);

一行目のdestroyアクションに対応するコードに加えて、削除と同時に「残りのタスクは〇〇件です」といったメッセージを表示する記述を行っています。

Railsでは上記のようにサーバーサイドで生成したJavaScriptからなるレスポンス(またはこのレスポンスからなる画面更新までのプロセス)のことをServer-generated JavaScript Responses(SJR)といいます。

手軽にテンプレートやヘルパー、モデルなどのサーバーサイドの資産を簡単に使えるメリットがあることに対して、複雑なJavaScriptSJRを行ってしまうと一つの画面に関するコードがあちこちに散らばってしまって共通化など管理がしづらい点があります。

rails-ujsとは?

remote: trueオプションを加えるとAjax通信が送信されますが、それは、rails-ujsというActionView添付のjavaScriptライブラリによって処理されています。また、rails-ujsによって、Ajaxリクエストを送信時に、関連するイベントを発行する役割も持ちます。

Gitについても少し復習しました

[画像引用]

  • masterブランチ…ローカルの中心となる統合ブランチで、他のローカルの作業ブランチと繋がったもの。
  • origin/masterブランチ…ローカルにある、リモートのmasterブランチを追跡するリモート追跡ブランチ。

①masterブランチから作業ブランチを切ります。その作業ブランチにて、実際の作業などを行うコードを書いていきます。

②fooブランチで変更した内容をリモートリポジトリに反映するまでの流れは、 fooリポジトリをadd→commitで、ファイルの追加・変更をローカルリポジトリに反映します。最後にpushをすることで、リモートリポジトリに反映できます。ただし、ここで反映されるのは画像のリモートリポジトリfooの部分であり、masterではないところに注意が必要です。

③リモートリポジトリのmasterに反映させるには、プルリクを出して、確認後マージボタンを最終的に押すことで、masterリモートリポジトリに反映されます。マージボタンを押した後に、fooリモートリポジトリを削除するのをオススメします。

④リモートリポジトリのmasterからローカルのmasterブランチにpull(git fetch + git merge)すると、リモートリポジトリに反映した内容をブランチにも反映させることができます。 pullすると、origin/masterブランチ(追跡ブランチ)を超えて、直接masterブランチに反映することが出来ます。

※Gitを操作する時はgit branchコマンドで自分がどこにいるのかを確認するのが大切です。

参照

【超入門】初心者のためのGitとGitHubの使い方

【初心者向け】git fetch、git merge、git pullの違いについて

2021年9月15日 現場Rails Chapter8-1 JavaScriptでページに変化をつける

ページが読み込まれてからJavaScriptを実行する方法

ページが読み込まれてからJavaScriptを実行する方法は、2種類存在します。Turbolinks機能を有効にしていない場合と、有効にしている場合です。以下に、Turbolinks機能を有効にしていない場合のコードを記載します。

assets/javascripts/task.js

window.onload = function() {
  document.querySelectorAll('td').forEach(function(td) {
    td.addEventListener('mouseover', function(e)
# function(e)の引数eは、eventの「e」です。
# mouseoverはマウスポインタが乗ったときの処理です。
      e.currentTarget.style.backgroundColor = '#eff';
    });

    td.addEventListener('mouseout', function(e) {
      e.currentTarget.style.backgroundColor = '';
    });
  });
});

Turbolinks機能を有効にしている場合、 一番上の行を下記に書き換える必要があります。

document.addEventListener('turbolinks:load', function() {

いずれも「ページの読み込みが完了したタイミング」で処理を開始するという意味です。これがない場合、ページの読み込みよりも早い「JavaScriptが読み込まれたタイミング」で処理が実行されますが、ページの読み込みが完了するタイミングでないと イベントハンドラの定義先となる要素がDOM上に存在せず、期待した挙動が実現しない場合があります。

addEventListenerメソッド

addEventListenerメソッドは、特定のイベントが対象に配信されるたびに呼び出される関数を設定します。 下記はaddEventListenerの一般的な構文です。

対象要素.addEventListener(種類, function() {
  
  //ここに処理を記述する
}, false);

上記のjavascriptDOMを使って、HTMLを操作しています。具体的には、タスクのtd要素にmouseover(マウスを乗せている間)というイベントに対応するイベントハンドラを登録し、その中で、背景色を変更する処理を記述しています。

Javascriptイベントハンドラを用いることで、ページの遷移なしに画面を動的に変更することが出来るのです。(非同期通信)

イベントハンドラとは?

イベントハンドラとは、特定の処理(イベント)が発生した時に実行する処理です。

DOMとは?

DOMは「Document Object Model」の略。 「ドキュメントを物として扱うモデル」。プログラムからHTMLやXMLを自由に操作するための仕組み。

例えばブラウザに表示される文字の色を変更したり、大きくしたりと、Webページの見た目をプログラムで処理をしたい場合があるだろう、しかし何もしていない状態のHTMLファイルではJavaScriptから手を出す事が出来ない。そこでファイルの特定の部分に目印を付けて「この部分」に「こういう事をしたい」という処理を可能にするための取り決めがDOMである。

DOMの特徴

  • ツリー構造とも呼ばれる階層構造を取る

  • それぞれノードという言葉で説明される

  • WEBページとJavaScriptなどのプログラミング言語とを繋ぐ

[画像引用]

CoffeeScriptとは

JavaScriptのコードを生成するためのスクリプト言語です(高級言語)。 Rubyの文法に似ているのが特徴です。

RailsではAsset Pipelineを利用して、CoffeeScriptを自動的にコンパイルしてくれますので、特にコンパイル作業を意識する必要はありません。拡張子を「〇〇.js.coffee」とし、/app/assets/javascriptsフォルダに配置するだけで利用できます。JavaScript に変換されることを前提としています。CoffeeScript を書き、それをコンパイル(変換)したら、JavaScript ファイルができます。

ECMAScript2015(ES2015)という仕様以降、Javascriptでもクラス構文やアロー関数が導入されました。そのため、CoffeeScriptを導入するメリットは以前よりも少なくなりました。

高級言語とは

機械語に近い言語で記述を行う低級言語に対し、高級言語は言語の理解がしやすく、汎用性が高いという利点があります。

Ajaxとは

Asynchronous JavaScript AndXMLの頭文字をとった言葉で、Webブラウザ上で非同期通信を行い、ページの再読み込みなしでページを更新するためのJavaScriptのプログラミング手法です。

rails-ujsとは

Ajaxの送信の部分を JavaScript で実装せずに、よしなにやってくれるJavaScriptのライブラリです。 Rails 5.0 までは jquery-rails を使ってフォームやリンクの Ajax 通信を可能にしていましたが、Rails 5.1 からは rails-ujs として切り出され、jQueryに依存しなくなりました。

Rails 5.1 ではデフォルトで rails-ujs が入っているので、require するだけです。

# app/assets/javascripts/application.js
//= require rails-ujs

これで読み込みが完了します。

JS形式のリクエストとHTML形式のリクエストの違い

[pikawaka 引用]

↑ 上記はremote:trueを指定しているかしていないかの違いです。remote:trueと記述することで、Ajax通信のリクエストをサーバーに送ることができます。 つまり、remote:trueオプションをつけることで、サーバーとのやりとりを非同期で行うAjax通信が実行できます。ただし、更新された画面を表示するのはjsで更新する必要があるので、別途記述が必要です。

更新された画面を表示する方法は2通りあり、1つはコントローラーで、head :no_contentと記述することで、HTTPレスポンスを返すとともに、削除成功のajax:successイベント呼び出し、そのイベント内で、DBで削除済みのタスクを表示上でも削除が反映されるような処理を記述します。 もう1つは、ビューファイルのjs.erbファイル内で、更新された画面を表示する処理を記述しており、そのファイルに処理が移ることで、新しいビューが表示されます。

参照

EventTarget.addEventListener()-WEB API|MDN

2021年9月14日 現場Rails Chapter7 非同期処理や定期実行を行う(Jobスケジューリング)

非同期処理とは?

非同期処理とは、あるタスクが実行している際に同時にバックグラウンドで他のタスクを実行できる方式です。

例えば、処理が重く時間が掛かるタスクを非同期処理として裏で動作させ、ユーザーに見える処理では処理の受付だけを行わせることで、ユーザーは受付をしながら非同期処理の結果を待つことが出来ます。結果として、ユーザーがただ何もしないで待つ時間を減らすことが出来ます。 例:非同期処理を用いたメールの送信

対して、同期処理とは?

1つずつ順番にタスクが実行される処理のことです。同時に2つ以上の処理を行うことはできず、1つの処理が終わるまで、もう1つの処理は待つ必要があります。

Active Jobとは?

バックグラウンドでさまざまな処理を非同期に行うための共通フレームワークのことです。  

Active Jobを使うメリットは、非同期処理を行うための様々なGem(sidekiq, Resque, Delayedjob)の記述方法や機能の違いを気にすることなく、非同期処理が行えることです。つまり、Active Jobを使うことで、どのGemを使用しても同じように非同期通信が行えます。

詳しくはRailsガイド

Redisとは

Redisはオープンソースの永続化可能なインメモリデータベース(In-memory database)で、BSDライセンスで公開されています。 特徴はインメモリ型データ構造ストアであること、そしてデータの永続化ができることといえるでしょう。 メモリ上で動作するキーバリューストア型のデータベースです。

Sidekiqとは

wikipediaで詳しく説明されているので、以下に引用します。

SidekiqはRubyで書かれたオープンソースのジョブスケジューラです。デフォルトではスケジューリングは行わず、ジョブの実行のみを行います。エンタープライズ版では、スケジューリング機能が搭載されています。

Sidekiqを使用するためには、sidekiqというgemをインストールします。

sidekiqのインストール

redisをbrew経由でインストール後、Gemのsidekiqのインストールを行います。

$ brew install redis
gem 'sidekiq' # bundle install

インストールしたらRailsとSidekiqを連携するために以下のように追記を行います。

# config/environments/development.rb
(略)
  config.active_job.queue_adapter = :sidekiq
end

下記のコマンドでジョブの雛形を生成します。

$ bin/rails g job sample

performメソッド内部に、非同期で実行したい処理を書きます。

# sample_job.rb
class SampleJob < ApplicationJob
  queue_as :default

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

Railsアプリケーションからperformメソッドの処理を呼び出すと、ジョブを登録できます。

def create
  @task = current_user.tasks.new(task_params)
  ...
  if @task.save
    TaskMailer.created_email(@task).deliver_now
    # 以下の一文で、performメソッドを呼び出せます。
    Sample.Job.perform_later 
    redirect_to @task, notice: "タスク「#{@task.name}」を登録しました。"
  else
    render :new
  end
end

ジョブは実行する時間を予約することも可能です。

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

# 1時間後に実行
SampleJob.set(wait: 1.hour).perform_later

雑学🤘🏽

スケーラビリティとは拡張性という意味です。

スケーラビリティ考慮してこ!!🙆🏽‍♂️

スタックとキューについて

Sidekiqでは、複数のジョブを並列して実行することができるのですが、キュー(queue)をいう仕組みを使ってそのジョブをどのような優先順位で実行するのか決めています。

スタックキューも、「データの持ち方 (データ構造)」のことで、どのようにpop(データを取り出すか)に違いがあります。

キューとは?

データ構造に入っている要素のうち、最初に push した要素から順に取り出します。(popする)

スタックとは?

データ構造に入っている要素のうち、最後に push した要素から順に取り出します。(popする)

参照

BSDライセンス wikipedia

インメモリデータベース

【Active Job】Sidekiq vs Resque vs Delayed Job

Railsガイド Active Job

Rails:Sidekiqを用いて非同期処理を実行する

スタックとキューを極める! 〜 考え方と使い所を特集 〜

Railsで非同期処理を行える「Sidekiq」

2021年9月10日 現場Rails Chapter7-7 ページネーション

9/9朝会の続き

前回にモデルファイルで実装したimportメソッドを使用して CSVデータをインポート出来るボタンを実装していきます。

# app/controllers/tasks_controller.rb
def import
  current_user.tasks.import(params[:file])
  redirect_to tasks_url, notice: "タスクを追加しました"
end  
# routes.rb
resources :tasks do
  post :confirm, action: :cofirm_new, on: :new
  post :import, on: :collection
end
# tasks/index.html.slim
= link_to 'エクスポート', tasks_path(format: :csv), class: 'btn btn-primary mb-3'

= form_tag import_tasks_path, multipart: true, class: 'mb-5' do
  = file_field_tag :file
  = submit_tag "インポート", class: 'btn btn-primary'

form_withのmultipartオプション

モデルと紐づかないform_with使用時にファイルや画像データを送信する場合に指定するオプションです。 この場合のform_withで、multipart:trueと指定しないと、ファイル名を記述した際に、文字列として認識されてしまいます。

現場Railsではモデルと紐づかない場合にのみ使用する旧form_withのforn_tagを使用しているため、ファイルや画像データを送信するのであればmultipart: trueの設定が必要です。

form_with #=> form_tagとform_forが合体したもの。
form_tag #=> フォームのデータの送り先に、モデルを指定しない。
form_for #=> フォームのデータの送り先に、モデルを指定する。

これでTaskをインポートする機能の実装が完了しました。

7-7 ページネーション

ページネーションとは?

表示したいレコードがとても膨大にある時に、そのレコードを一度に全て表示するのではなく、複数のページに分けて表示させる機能です。そのようにすることで、見つけたいレコードを見つけやすくするとともに、表示するデータがそれほど多くないので、処理速度も落ちることはありません。Railsでは、kaminariというgemがページネーションを提供しています。

まずkaminariをインストールします。その後、pageというスコープを使います。
↓現場で使えるRuby on Railsのコード例

# app/controllers/tasks_controller.rb

# params[:page]にページ番号が入ります。
def index
  @q = current_user.tasks.ransack(params[:q])
  @tasks = @q.result(distinct: true).page(params[:page])
end

7-7-3 ビューにページネーションのための情報を表示する

paginateヘルパー

  • 現在どのページを表示しているのかの情報
  • 他のページに移動するためのリンク

page_entries_infoヘルパー

  • 全データが何件なのかといった情報
# app/views/tasks/index.html.slim

.mb-3
  =paginate @tasks
  =page_entries_info @tasks

動作を確認するためにはそれなりにデータが必要になるため コンソールで以下のように実行します。また、初期データを入れる際に、コンソールではなくseed-fuを使うやり方もあります。seed-fuの使い方

> user = User.find(1)
> 100.times {|i|user.tasks.create!(name: "サンプルタスク#{i}")}

(※)kaminariが内部で用意してくれている翻訳ファイルは英語なので、日本語にしたい場合は翻訳する必要があります。

7-7-5 デザインの調整

paginateヘルパーが表示に利用するパーシャルテンプレートをアプリケーション内に用意し、自分でカスタマイズすることでデザインを好きなように調整することができます。 kaminariの提供するジェネレータで生成しますが、テーマ(Thema)と呼ばれるデザインの種類を指定できます。 利用できるテーマの一覧はgithubから確認できます。

$ bin/rails g kaminari:views 指定したいファイル名

一度に表示する件数を変更する

kaminariでは、1ページに25件までのデータを表示するという設定がデフォルトで指定されていますが、その表示件数を変更する方法もあります。その方法は、以下の3つです。

1. perスコープを使用する方法

perスコープ kaminariで提供されているスコープです。1ページあたりに表示する件数を指定することが出来ます。perスコープに引数として渡した数字が、1ページあたりに表示する件数として反映されます。

# タスク一覧機能だけ、1ページあたり50件のデータを取得したい
# indexアクション内にperスコープを用いて、表示件数を変更する
def index
    
  # @tasks = @q.result(distinct: true).page(params[:page])部分を変更
  @tasks = @q.result(distinct: true).page(params[:page]).per(50)

end

2. paginates_perを使って、モデルごとの表示件数を指定する方法

# taskモデルの1ページのデフォルト表示件数を50件に指定します
# app/models/tasks.rb内に記述
class Task < ApplicationRecord
  paginates_per 50
    
  ~省略~
end

3. configファイルを設定する方法

Kaminari全体としての表示件数のデフォルトを変更します。 下記のコマンドで、Kaminariの設定ファイルが生成されます。

$ bin/rails g kaminari:config

この設定ファイル内に、表示件数の設定を記述します。

# config/initializers/kaminari_config.rb
Kaminari.configure do |config|
  # ここではデフォルトの表示件数を10件に設定しています。
  config.default_per_page = 10
  
  ~省略~
end

参照

Action View Form Helpers
https://guides.rubyonrails.org/form_helpers.html#uploading-files
GitHub kaminari_themes
https://github.com/amatsuda/kaminari_themes GitHub kaminari https://github.com/kaminari/kaminari railsで初期データを入れる(seed-fuの使い方) https://qiita.com/ko2ic/items/be96e450a33d631e0059

2021年9月9日 現場Rails Chapter7-6-2 CSVデータを入力(インポート)する

CSVデータをインポートする際に使われるメソッド

Csv.foreach

1行ずつ処理をするため、行数が多いCSVファイルを扱う場合でもメモリ使用量を気にしないで使えます。

slice

引数で指定されたキーとその値だけを含む Hash を返します。

to_hash

to_hashメソッドを呼ぶことで、次のようなハッシュの形に変換されます。

{"name"=>"たすくのなまえ", "description"=>"", "created_at"=>2021-09-07 02:30:00 UTC", "updated_at"=>"2021-09-09 09:30:00 UTC"

CSVデータを入力(インポート)する

#  app/models/task.rb
def self.import(file)
  # headers: trueで1行目をヘッダーとして扱うことができる。
  # headers: trueとすることで、DBに登録する際に1行目をレコードとして登録せずに、2行目以降からレコードしてDBに登録するようにしている。
  CSV.foreach(file.path, headers: true) do |row|
    task = new
    task.attributes = row.to_hash.slice(*csv_attributes)
    task.save!
  end
end

attributes = は、変数ではなく特定のattributeを変更するメソッドです。 オブジェクトの属性を変更しただけで、DBには保存されていないため、saveします。

def import
  current_user.tasks.import(params[:file])
  redirect_to tasks_url, notice: "タスクを追加しました"
end

可変長引数

引数に* をつけると、個数に制限なく、引数を渡せる可変長引数というものになります。可変長引数を使うことで、引数を配列として受け取ることが出来ます。

a = [1, 2]
b = [1, 2, 3]

p a.push(b)
#=> [1, 2, [1, 2, 3]]
p a.push(*b)
#=> [1, 2, [1, 2, 3], 1, 2, 3]

参照

Ruby】よく使う、CSVライブラリを使ったCSV操作
https://qiita.com/mogulla3/items/2d2053f0e4c13ba3b6dc
Ruby 3.0.0 リファレンスマニュアル ライブラリ一覧 csvライブラリ CSV::Rowクラス
https://docs.ruby-lang.org/ja/latest/class/CSV=3a=3aRow.html#I_ROW instance method Hash#slice
https://docs.ruby-lang.org/ja/latest/method/Hash/i/slice.html
Active Recordのattributesの更新メソッド
https://morizyun.github.io/ruby/active-record-attributes-save-update.html Ruby 3.0.0 リファレンスマニュアル ライブラリ一覧 組み込みライブラリ Hashクラス
https://docs.ruby-lang.org/ja/latest/method/Hash/i/slice.html