ブロック「do...end」と「{}」/CSVを扱う/sendメソッド/respond_to/strftimeメソッド/send_dataメソッド
ブロックdo...end
と{}
ブロックの文法の種類を忘れていたので復習しました。
numbers = [1, 2, 3, 4] sum = 0 (i)標準的なブロック文 numbers.each do |n| sum += n end (ii)改行しないブロック文 numbers.each do |n| sum += n end (iii)「do...end」を使う代わりに「{}」を使ったブロック文 numbers.each { |n| sum += n } (i), (ii), (iii)のどれも出力は同じ。 sum #=> 10
この使い分けとしては、
改行を含む長いブロックを書く場合は → do...end
1行でコンパクトに書きたい場合は → {}
(iii)の「{}」でブロックを実装する方法が多いのですが、この書き方を忘れていてつまづいた。
CSVを扱う
Rubyのcsvライブラリを利用する。(config/application.rb)に記述します。
require 'csv'
csv_data = CSV.read('member.csv', headers: true)
headers: true
オプションを使うと、CSVの初めの1行はheaderとして出力の際に無視されます。今回はこのオプションを使っていますが、headerがないときはこのオプションはいりません。
sendメソッド
sendとは、レシーバの持っているメソッドを呼び出してくれるメソッドのこと。 レシーバの持っているメソッドを呼び出し、そのメソッドの戻り値を返します。 以下はメソッドを定義したときの例です。
class User def name puts "taro" end end user = User.new #定義したメソッドを呼び出す user.name # => taro # sendを使った書き方 user.send(:name) # => taro user.send("name") # => taro
CSVをエクスポートするときに使った。
CSV.generate(headers: true) do |csv| csv << csv_attributes all.each do |task| csv << csv_attributes.map{ |attr| task.send(attr) } end
respond_toにできること
def destroy @tweet = Tweet.find(params[:id]) respond_to do |format| if @tweet.destroy format.html { redirect_to root_path } #root_pathへリダイレクトする format.js { render :action => "index" } #.index.html.erbで作成されたものをjson形式で表示する。 end end end
destroy action が呼び出された時、formatがhtmlで指定されていたらroot_pathにリダイレクト、jsonで指定されていたらindex.html.erbをindex.html.jsで返す
strftimeメソッド
Rubyのstrftimeメソッドは、日付や日時のデータを編集して文字列に変換するためのメソッドです。
使い方はstrftimeメソッドの第1引数に書式を指定して次のように記述します。
> Time.zone.now => Tue, 12 Nov 2019 13:57:27 UTC +00:00 > Time.zone.now.strftime('%Y%m%d%S') => "2019111242" > Time.zone.now.strftime("%Y年%-m月%-d日 %-H時%-M分%-S秒") => "2019年11月12日 14時11分17秒"
send_dataメソッド
CSV出力機能を実装したかったので、このsend_data
メソッドを使ってレスポンスを送り出し、送り出したデータをブラウザからファイルとしてダウンロードできるようにします。
send_data(data、options = {})
第一引数:生成するCSVデータ
オプション:filename -使用するブラウザのファイル名を提案します。
今回は下記の様に実装した。
def index @q = current_user.tasks.ransack(params[:q]) @tasks = @q.result(distinct: true) respond_to do |format| format.html format.csv { send_data @task.generate_csv, filename: "tasks-#{Time.zone.now.strftime('%Y%m%d%S')}.csv"} end end