- 投稿日:2020-11-25T23:58:54+09:00
ひな祭り[Ruby]
ひな祭り[Ruby]問題
問題
ひな祭りの準備をしましょう。あなたが持っている 10 体の人形を "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" で表します。ひな壇の各段 (計 3 段) に並べる人形の数が与えられるので、各段にならべる人形の記号を改行区切りで出力してください。人形は必ずもとの A, B, C, ... の順番で並べます。
例)
各段にならべる人形の数: 2, 3, 5
→ 人形の並べ方:
AB
CDE
FGHIJ入力される値
入力は以下のフォーマットで与えられます。
h_1 h_2 h_3
ひな壇の 1 段目、2 段目、3 段目に並べる人形の数を表す整数 h_1, h_2, h_3 がこの順に半角スペース区切りで与えられます。入力は 1 行となり、末尾に改行が 1 つ入ります。期待する出力
ひな壇への人形の並べ方を以下の形式で出力してください。
s_1
s_2
s_3
ひな壇の 1 段目、2 段目、3 段目に並べる人形を表す文字列 s_1, s_2, s_3 をこの順に改行区切りで出力してください。s_i (1 ≦ i ≦ 3) は i 段目に並べる人形の記号をアルファベット順に結合した文字列です。
入力例1
2 3 5
出力例1
AB
CDE
FGHIJ入力例2
1 1 8
出力例2
A
B
CDEFGHIJ入力例3
3 4 3
出力例3
ABC
DEFG
HIJアドバイス頂いた結果
ns = gets.split.map(&:to_i) str = "ABCDEFGHIJ" i = 0 ns.each do |n| puts str[i, n] i += n endこのほかにも Array#shift で求めるコードも!
以上!
- 投稿日:2020-11-25T23:10:16+09:00
【Ruby ~基本(コマンド/メソッド)~】勉強メモ
Rubyの復習。
ほぼ自分の勉強メモです。
過度な期待はしないでください。Rubyファイル
Rubyファイルには、
.rb
という拡張子を付ける
irbコマンド
irbコマンドは、ターミナルから直接Rubyのプログラムを動かすことができる機能。
ちなみに、irbは「Interactive Ruby」の略。ターミナルsample@sampleMBP ~ % irb // エンターキーで実行 irb(main):001:0> "Hello! こんにちは!" // このように表示されれば成功 => "Hello! こんにちは!" // 終了するときは、exitと記述して実行 irb(main):002:0> exit sample@sampleMBP ~ %
rubyコマンド
rubyコマンドはRubyに関するさまざまな操作が実行できるコマンド。
Rubyファイルをプログラムとして実行するためには、
ターミナルにruby [実行したいRubyファイルのパス]
と打ち込む。ターミナル// Rubyファイルを実行するには、ファイルがあるディレクトリ迄移動する // 今回で有ればsampleディレクトリにあるsample.rbというRubyファイルを実行 sample@sampleMBP sample % ruby sample.rb "hello, GitHubDesktop."
出力命令
「puts "○○"」と書くと、putsの後の○○という文字がコンソールに出力される。
×××.rb# 文字の出力 puts "Hello World" # 数値の出力 puts 77 # 数値の計算 puts 7 + 7 # 文字の連結 puts "Hello" + "World"出力結果Hello World 77 14 Hello World
入力命令
- getsメソッド
ターミナルに値の入力機能を起動するメソッド。
getsをコードに記述すると、記述した行を読み込んだ段階で入力機能が起動し、
ターミナル画面は入力待ちの状態になる。ちなみに、getsメソッドで入力された値は、末尾に改行がついた文字列になる。
×××.rbinput = gets puts "明日の天気は#{input}です。"ターミナル~ % ruby ×××.rb # 入力した文字 晴れ # 出力結果 明日の天気は晴れ です。
- chompメソッド
chompメソッドは、文字列の末尾に存在する改行を取り除いた文字列を返す。
×××.rbinput = gets puts "明日の天気は#{input}です。"ターミナル~ % ruby ×××.rb # 入力した文字 くもり # 出力結果 改行されずに1行で出力される 明日の天気はくもりです。
メソッド
- lengthメソッド
lengthメソッドは、文字列の文字数を数える。
×××.rbputs "Hello World".length出力結果11
- to_sメソッド
数値を文字列に変換する。
ちなみに、 to_sのsの意味は「string(文字列)」ターミナル# 数値「20」にto_sメソッドをつけて実行 irb(main):001:0> 20.to_s => "20"
- to_iメソッド
文字列を数値に変換する。
ちなみに、 to_iのiの意味は「integer(整数)」ターミナル# 文字列「30」にto_iメソッドをつけて実行 irb(main):001:0> "30".to_i => 30
バックスラッシュ記法
(バックスラッシュ) から始まる文字の記法のこと。
バックスラッシュの入力は、option + ¥
バックスラッシュ記法が適応されるのは文字を "(ダブルクォーテーション)で囲んだときの。\n で → 改行
×××.rbputs "ようこそ!\n日本へ!"出力結果ようこそ! 日本へ!
- 投稿日:2020-11-25T22:48:20+09:00
Active Storage の導入まとめ
はじめに
・Active Strage の導入を自分なりにまとめたもので、メモのようなものです。
・投稿者は初学者ですので誤った情報を投稿してしまうことがあります。その時はぜひ、遠慮会釈なしにご指摘いただけると幸いです。Active Strageとは
ファイルアップロード機能を手軽に実装できるGemのこと。
元々はインストールが必要だったが、Rails5.2.0以降、初期段階から統合される事となった。このGemを用いると、ファイルアップロードのメソッドを使用できたり、画像を保存するテーブルを簡単に作成できる。Active Strageのお供
Active Strageと一緒に導入すると画像の加工の幅が広がる物を3つ列挙します。
・ImageMagick
・MiniMagick
・ImageProcessingImageMagickはソフトウェアで、MiniMagickとImageProcessingはGemになります。
ImageMagick
コマンドラインから画像に処理を加えることができるツールのこと。
画像の作成やサイズ変更、保存形式の変更などが可能となる。
Homebrewよりインストールする。
MiniMagick
ImageMagickをRubyで扱えるようにしてくれる接合の役割を担うGemのこと。
ImageProcessing
ImageMagickでの画像サイズ機能を拡張してくれるGemのこと。導入の手順
1、ImageMagickをHomebrewからインストールするために、下記のコードをターミナルに入力する。
% brew install imagemagick2、MiniMagickとImageProcessingをインストール。
Gemfile.gem 'mini_magick' gem 'image_processing', '~> 1.2'bundle install
'~> 1.2'
と表記があるが、これは、1.2.0以上、1.3.0未満のバージョンを指定、という意味。3、ローカルサーバーを再起動
rails s4、Active Strageをインストール
導入手順1でrailsアプリの中にActive Strageを入れた。
ここでのインストールはActive Strageを用いるための周辺準備のためのインストール。rails active_storage:installこれにより、Active Strageに関連したマイグレーションファイルが作成される。
続けて、以下のように
migrate
をすることでテーブルが作成される。rails db:migrate余談 ※読み飛ばし可*
導入手順1と4はどちらもインストールであるが、何が違うのかを自分なりに解説。
アパートの引越しで例えるならば、
導入手順1は「仲介業者と賃貸の契約」
導入手順4は「家具や消耗品を部屋へ搬入」である。
仲介業者と契約を結んだだけでは(導入手順1)その部屋で快適には過ごせない。冷蔵庫に電子レンジ、シャンプーにお皿などの生活用具を部屋に運搬して(導入手順2)初めて生活ができる空間となる。
まとめ
Active Strage
を調べていく中で、CarrierWave
という、同じく画像アップロード実装のGemを見つけました。
CarrierWaveは10年ほど前から利用されている古い技術ということで今はActive Strageが主流なのかと思いましたが、意外にもCarrierWaveも現役選手でした。
Active Strage
はシンプルなファイルアップロード。
CarrierWave
はアップロード+細かな設定。
それぞれ別の役割がしっかりと備わっているようなので、CarrierWaveのことも調べて実装したいと思います。
- 投稿日:2020-11-25T21:28:24+09:00
【Week 6】my_help, ruby_second
はじめに
マルチスケールシミュレーション特論の講義メモです.講義メモのインデックスはコチラ.
授業内で
学習メモがpublicになっていて,LGTMをもらえている
という指示があったので,拙い内容ですが投稿しています.チャート式 Ruby
参照記事はコチラ
variable
前回の講義ではコマンドライン引数として受け取った文字を ARGV[0] を用いて出力するプログラム hello_name.rb を作成した.
(参考) hello_name.rb
puts "Hello #{ARGV[0]}."今回は受け取った引数 ARGV[0] を name という変数 (variable) に代入し,出力するプログラムを作成する.
まずは変数 name を用意する必要がある.Ruby では変数の型宣言の必要がない(Python も然り)ため,変数は以下のように定義できる.
name = ARGV[0]コマンドライン引数を変数に代入し,出力するプログラム name_variable.rb を作成したい.はじめに変数 name に "Rudy" を代入して,出力するプログラムを作成する.
name = "Rudy" puts "Hello #{name}."次に ARGV[0] を変数 name に代入し,出力するプログラムにリファクタリングする.
name = ARGV[0] puts "Hello #{name}."これを実行すると
> ruby name_variable.rb Hiroki. Hello Hiroki.期待どおり受け取った引数を変数に代入し,出力するプログラムを作成できた.
method
これまでの講義で引数や変数を用いて "Hello xxx." を出力するプログラムを作成してきたが,これらをメソッド化したい.
Rubyではメソッド (method) を定義することで,関数やプロシージャなどを実装できる.メソッドは以下のように定義できる.
(参考)メソッドの例
def hello(name) p name endname_variable.rb を参考に,"Hello xxx." を出力するメソッドをプログラム hello_method.rb に作成する.
まずはじめに hello メソッドを作成・呼び出してみる.
def hello (name) end name = ARGV[0] hello (name)メソッド内に処理を書いていないので勿論実行しても何も出力されない.メソッドの引数を出力するように以下のようにメソッドに追記する.
def hello (name) puts name end name = ARGV[0] hello (name)これを実行すると
> ruby hello_method.rb Rudy Rudyコマンドラインで受け取った引数を出力するメソッドを作成できた.あとは出力に文字列を加えればよいので,
def hello(name) puts "Hello #{name}." end name = ARGV[0] hello(name)実行すると
> Ruby hello_method.rb Rudy Hello Rudy.期待どおり "Hello xxx." を出力する hello メソッドを作成できた.
TDD
まずTDDとは…
Test Driven Development: テスト駆動開発
以下の手順でコーディングを行う
- テストを作る (test)
- エラーを出す (red)
- エラーをなくす (green)
- code を brush up する (refactoring)
最終目標は 動く綺麗なコードを作る こと,らしいです.自分もどちらかというと TDD に近いスタイルだった.
折角なので hello_method.rb をリファクタリングしていく.まずはメソッド名が hello と何をするメソッドか分かりづらいので, puts_hello に変更する.
def puts_hello name puts "Hello #{name}." end name = ARGV[0] puts_hello name続いて command の option に名前を指定し忘れた場合,問い合わせるようにしたい.追加する処理は以下のようになる.
name = ARGV[0] if name == nil puts "What\'s your name?" name = gets.chomp end上記の処理を gets_name メソッドとしてプロシージャにまとめる.hello_method.rb をリファクタリングした後のプログラム hello.rb は以下のとおり.
def puts_hello name puts "Hello #{name}." end def gets_name name = ARGV[0] if name == nil puts "What\'s your name?" name = gets.chomp end return name end name = gets_name puts_hello namehtllo_method.rb と比較して,よりまとまりのある分かり易いプログラムになった.
Ruby 開発周辺情報
参照記事はコチラ
myhelporg-modebash や emacs については前回の講義メモにまとめています.
また,org-mode によるCUIでのメモについて,詳しい内容は以下の記事に随時追加していきます.
次回の講義内容 <2020-11-04 Wed>
次回の講義は
だそうです.
- source ~/grad_members_20f/members/e79a93e5b7b1/posts/class/c6_20201028.org
- 投稿日:2020-11-25T21:20:45+09:00
【Week 6】my_help, ruby_second
はじめに
マルチスケールシミュレーション特論の講義メモです.講義メモのインデックスはコチラ.
チャート式 Ruby
参照記事はコチラ
variable
前回の講義ではコマンドライン引数として受け取った文字を ARGV[0] を用いて出力するプログラム hello_name.rb を作成した.
(参考) hello_name.rb
puts "Hello #{ARGV[0]}."今回は受け取った引数 ARGV[0] を name という変数 (variable) に代入し,出力するプログラムを作成する.
まずは変数 name を用意する必要がある.Ruby では変数の型宣言の必要がない(Python も然り)ため,変数は以下のように定義できる.
name = ARGV[0]コマンドライン引数を変数に代入し,出力するプログラム name_variable.rb を作成したい.はじめに変数 name に "Rudy" を代入して,出力するプログラムを作成する.
name = "Rudy" puts "Hello #{name}."次に ARGV[0] を変数 name に代入し,出力するプログラムにリファクタリングする.
name = ARGV[0] puts "Hello #{name}."これを実行すると
> ruby name_variable.rb Hiroki. Hello Hiroki.期待どおり受け取った引数を変数に代入し,出力するプログラムを作成できた.
method
これまでの講義で引数や変数を用いて "Hello xxx." を出力するプログラムを作成してきたが,これらをメソッド化したい.
Rubyではメソッド (method) を定義することで,関数やプロシージャなどを実装できる.メソッドは以下のように定義できる.
(参考)メソッドの例
def hello(name) p name endname_variable.rb を参考に,"Hello xxx." を出力するメソッドをプログラム hello_method.rb に作成する.
まずはじめに hello メソッドを作成・呼び出してみる.
def hello (name) end name = ARGV[0] hello (name)メソッド内に処理を書いていないので勿論実行しても何も出力されない.メソッドの引数を出力するように以下のようにメソッドに追記する.
def hello (name) puts name end name = ARGV[0] hello (name)これを実行すると
> ruby hello_method.rb Rudy Rudyコマンドラインで受け取った引数を出力するメソッドを作成できた.あとは出力に文字列を加えればよいので,
def hello(name) puts "Hello #{name}." end name = ARGV[0] hello(name)実行すると
> Ruby hello_method.rb Rudy Hello Rudy.期待どおり "Hello xxx." を出力する hello メソッドを作成できた.
TDD
まずTDDとは…
Test Driven Development: テスト駆動開発
以下の手順でコーディングを行う
- テストを作る (test)
- エラーを出す (red)
- エラーをなくす (green)
- code を brush up する (refactoring)
最終目標は 動く綺麗なコードを作る こと,らしいです.自分もどちらかというと TDD に近いスタイルだった.
折角なので hello_method.rb をリファクタリングしていく.まずはメソッド名が hello と何をするメソッドか分かりづらいので, puts_hello に変更する.
def puts_hello name puts "Hello #{name}." end name = ARGV[0] puts_hello name続いて command の option に名前を指定し忘れた場合,問い合わせるようにしたい.追加する処理は以下のようになる.
name = ARGV[0] if name == nil puts "What\'s your name?" name = gets.chomp end上記の処理を gets_name メソッドとしてプロシージャにまとめる.hello_method.rb をリファクタリングした後のプログラム hello.rb は以下のとおり.
def puts_hello name puts "Hello #{name}." end def gets_name name = ARGV[0] if name == nil puts "What\'s your name?" name = gets.chomp end return name end name = gets_name puts_hello namehtllo_method.rb と比較して,よりまとまりのある分かり易いプログラムになった.
Ruby 開発周辺情報
参照記事はコチラ
myhelporg-modebash や emacs については前回の講義メモにまとめています.
また,org-mode によるCUIでのメモについて,詳しい内容は以下の記事に随時追加していきます.
次回の講義内容 <2020-11-04 Wed>
次回の講義は
だそうです.
- source ~/grad_members_20f/members/e79a93e5b7b1/posts/class/c6_20201028.org
- 投稿日:2020-11-25T21:10:57+09:00
[Rails]オーバーライド(継承)について勉強してみた![初心者]
オーバーライドとは?
親クラス(スーパークラス)で定義されたメソッドについて、小クラス(サブクラス)で同じ名前で再定義すること。
クラスの継承とは?
他のクラスをベースとして新しいクラスを作成することをクラスの継承と言います。
利用したいクラスが複数存在する場合、全てを1から作成していると骨が折れますし、共通する部分を複数のクラスに重複して定義する必要があります。
そこで、あるクラスが既に作成されている場合、そのクラスを拡張することで、新しいクラスを作成することができます。クラスの継承は以下のように記載します。
class 子クラス名 < 親クラス名 end継承の具体例
class Days def study puts "勉強する" end end class Holiday < Days def sleep puts "寝過ごす" end end holiday = Holiday.new holiday.study実行結果勉強する
オーバーライドの具体例
class Days def study puts "勉強する" end end class Holiday < Days def sleep puts "寝過ごす" end def study super puts "休日だろうと勉強しなければ" end end holiday = Holiday.new holiday.study実行結果勉強する 休日だろうと勉強しなければサブクラスにメソッド定義がない場合
サブクラスで定義していないメソッドが呼び出された時は、スーパークラスに同じ名前のメソッドがある場合に限り、スーパークラスのメソッドが呼び出せます。
具体例を以下に載せました。class Days def study puts "勉強する" end end class Holiday < Days end holiday = Holiday.new holiday.study実行結果勉強する
superclassメソッド
全てのクラスは、クラスメソッドとして
superclassメソッド
を持っています。
また、スーパークラスのメソッドを引数なしで呼び出したい時には、super()
も使用できます。
- 投稿日:2020-11-25T21:05:40+09:00
【Ajax】jQueryを使って一覧ページでいいね機能
はじめに
一覧ページでのいいね機能を実装しようとしましたが、一番上の星をいいねしたら全てのチームにいいねがついてしまうという問題が発生しました。この問題が起きたことで大変学習になったので、思考の整理とアウトプットとして記事にまとめさせていただきました。また、いいね機能は多くのアプリで実装することが多いと思います。同じような問題が起きている方や別の実装方法など、ご意見いただけたら幸いです!
概要
まず大前提にテーブルは、
users
,teams
,likes
の3つでlikes
は
users
とteams
の中間テーブルになっています。
AjaxでHTTPメソッドのGET
,POST
,DELETE
ができるように実装していきます。起きている問題・解決したいこと(仮説)
起きている問題と解決したいことを簡単に書いていきたいと思います。
起きている問題
- 全ての記事にいいねがついてしまう。
- 全てのチームのidを取得していたつもりが一番上のチームのidしか取得できていない。(デベロッパーツールで確認)
解決したいことと仮説
- 配列にして取得できていると思ったができていないので配列から一つずつチームを取得できるようにする。
- いいね対象を判断できるようにクラスをつけないといけない。
- クリックした対象に動的idが付与されていれば実装できるのではないか。
Ajaxで実装すること
- いいねの表示
- いいねされたら黄色い星を表示
- いいねされているものをクリックしたら白い星を表示
LikesController
show
,create
,destroy
アクションを使用しています。
Railsでの定義と違うところはリクエストに対して返すのがjson形式のデータということです。LikesControllerclass LikesController < ApplicationController before_action :authenticate_user! before_action :set_like def show like_status = current_user.has_liked?(@team) render json: { hasLiked: like_status } end def create @team.likes.create!(user_id: current_user.id) render json: { status: 'ok' } end def destroy like = @team.likes.find_by!(user_id: current_user.id) like.destroy! render json: { status: 'ok' } end private def set_like @team = Team.find(params[:team_id]) end enduser.rb
has_liked?
はuser.rb
で定義しています。showアクション内の処理のようにcurrent_userがteamをlikeしてる?
と直感的にわかりやすいと思い、定義しております。user.rbdef has_liked?(team) likes.exists?(team_id: team.id) endindex.html.haml
HTTPリクエストを送るにはJavaScriptでidを取得できるようにしなくてはいけないので、テンプレートにカスタムデータを記述しています。
data-<情報>
とすることで任意の属性を付与することができます。今回はチームに対していいねをしたいのでteam
のid
が必要です。
※routes
を確認するとどこにリクエストを送れば良いかよくわかります。たとえばですが、以下
index.html.haml
のように記述してデベロッパーツールで確認すると
data-team-id="1"
id="active-star1"
このようにdata属性とチームのidが入ったidを取得することができます。
チームのidが入ったidは一覧ページでのいいね機能なので、クリックしたときに特定のチームをいいねするという状況になります。それを判定するために記述しております。実際にjQueryのコードを見ていただいたほうが早いと思いますが、簡単に説明させていただきますと、active-star
というid
だけだと、active-star
というidは複数あるので、全てのチームにいいねをつける処理が実行されてしまいます。そのため、動的なid(今回はチームのid)
を付与しております。数字の1
の部分がチームのidです。ここで重要なのは、
- カスタムデータ
- hiddenでいいねの表示を隠していること
hiddenを使っている理由はいいねの状態を確認し表示するということをAjaxで表示するためです。
index.html.haml.hidden.active-star{id: "active-star#{teams.id}", data: {team_id: tams.id}} = image_tag 'star-yellow.png' .hidden.in-active-star{id: "in-active-star#{teams.id}", data: {team_id: teams.id}} = image_tag 'star-white.png'css.hidden { display: none; }jQuery
本題のいいね機能の実装部分です。
記述が冗長になってしまったので、コメントを入れております。重要なのはcsrfToken
をリクエスト時に持たせることです。これをしないと422 (Unprocessable Entity)というエラー
が起きます。なぜかというとGETと違ってPOSTなどの処理はデータベースの変更をするリクエストなので、簡単に操作されては困るため制約がついています。そのため、rails-ujs
を使ってaxios
でリクエスト時にcsrfToken
というのを持たせるようにしております。jQueryimport $ from 'jquery' import axios from 'axios' import { csrfToken } from 'rails-ujs' // リクエスト時にCSRFトークンを持たせる axios.defaults.headers.common['X-CSRF-Token'] = csrfToken() document.addEventListener('DOMContentLoaded', () => { // ロード時にいいねされていない星を配列で取得 $('.in-active-star').each(function (index, element) { // テンプレートで記述したカスタムデータを取得 let likeData = $(element).data() // カスタムデータからチームIDを取得 let getId = likeData.teamId // カスタムデータを入れてGETリクエストを送る axios.get(`/teams/${getId}/like`) // リクエストを送ったらレスポンスが返ってくる .then((response) => { // responseでrenderされたlikeの状態を取得(true or false) const inActiveStatus = response.data.hasLiked // falseであればいいねされていない => 白い星を表示するために、'hidden'を取り外す if ( inActiveStatus === false ) { $(element).removeClass('hidden') } }) }) // ロード時にいいねされている星を配列で取得 $('.active-star').each(function (index, element) { // テンプレートで記述したカスタムデータを取得 let likeData = $(element).data() // カスタムデータからチームIDを取得 let getId = likeData.teamId // カスタムデータを入れてGETリクエストを送る axios.get(`/teams/${getId}/like`) // リクエストを送ったらレスポンスが返ってくる .then((response) => { // responseでrenderされたlikeの状態を取得(true or false) const activeStatus = response.data.hasLiked // trueであればいいねされている => 黄色い星を表示するために、'hidden'を取り外す if ( activeStatus === true) { $(element).removeClass('hidden') } }) }) // #create いいねをつけたいときの処理 $('.in-active-star').on('click', (e) => { e.preventDefault(); let dataset = $(e.currentTarget).data() // クリックした要素のidを取得 let teamId = dataset.teamId // teamIdを使いPOSTリクエストを送る axios.post(`/teams/${teamId}/like`) .then((response) => { // リクエスト成功なら処理を行う if (response.data.status === 'ok') { $(`#in-active-star${teamId}`).addClass('hidden'); $(`#active-star${teamId}`).removeClass('hidden'); } }) // エラー時の処理 .catch((e) => { window.alert('Error') console.log(e) }) }) // #destroy いいねを外したいときの処理 $('.active-star').on('click', (e) => { e.preventDefault(); let dataset = $(e.currentTarget).data() // クリックした要素のidを取得 let teamId = dataset.teamId // teamIdを使いdeleteメソッドを使う axios.delete(`/teams/${teamId}/like`) .then((response) => { // リクエスト成功なら処理を行う if (response.data.status === 'ok') { $(`#active-star${teamId}`).addClass('hidden'); $(`#in-active-star${teamId}`).removeClass('hidden'); } }) // エラー時の処理 .catch((e) => { window.alert('Error') console.log(e) }) }) })まとめ
- Ajax処理はデベロッパーツールを使い
debugger
やconsole.log()
を使い値が取れているか確認をしっかりすると開発が捗る。- 詳細ページのように一つしかいいねがないときは意識していなかったが、一覧ページなど複数ある中の一つというように特定したいときは個別のidを付与することで実装できる。
- POSTやDELETE時にはデータベースの操作をすることからCSRFトークンというものが必要になる。
最後に
今回はjQueryを使って実装しました。Vue.jsの学習も始めたので、生JSやjQueryをもっと理解したら開発に使っていきたいなと思っています。このように実装するのもひとつの方法だと思いますが、他にもたくさんの実装方法があると思います。他のライブラリやフレームワークではどのように実装するのか、また一度書いたコードもリファクタリングを積極的にやっていけたらと思います!
参考文献
- 投稿日:2020-11-25T21:05:40+09:00
【Rails】いいね機能をjQueryで実装
はじめに
一覧ページでのいいね機能を実装しようとしましたが、一番上の星をいいねしたら全てのチームにいいねがついてしまうという問題が発生しました。この問題が起きたことで大変学習になったので、思考の整理とアウトプットとして記事にまとめさせていただきました。また、いいね機能は多くのアプリで実装することが多いと思います。同じような問題が起きている方や別の実装方法など、ご意見いただけたら幸いです!
概要
まず大前提にテーブルは、
users
,teams
,likes
の3つでlikes
は
users
とteams
の中間テーブルになっています。
AjaxでHTTPメソッドのGET
,POST
,DELETE
ができるように実装していきます。起きている問題・解決したいこと(仮説)
起きている問題と解決したいことを簡単に書いていきたいと思います。
起きている問題
- 全ての記事にいいねがついてしまう。
- 全てのチームのidを取得していたつもりが一番上のチームのidしか取得できていない。(デベロッパーツールで確認)
解決したいことと仮説
- 配列にして取得できていると思ったができていないので配列から一つずつチームを取得できるようにする。
- いいね対象を判断できるようにクラスをつけないといけない。
- クリックした対象に動的idが付与されていれば実装できるのではないか。
Ajaxで実装すること
- いいねの表示
- いいねされたら黄色い星を表示
- いいねされているものをクリックしたら白い星を表示
LikesController
show
,create
,destroy
アクションを使用しています。
Railsでの定義と違うところはリクエストに対して返すのがjson形式のデータということです。LikesControllerclass LikesController < ApplicationController before_action :authenticate_user! before_action :set_like def show like_status = current_user.has_liked?(@team) render json: { hasLiked: like_status } end def create @team.likes.create!(user_id: current_user.id) render json: { status: 'ok' } end def destroy like = @team.likes.find_by!(user_id: current_user.id) like.destroy! render json: { status: 'ok' } end private def set_like @team = Team.find(params[:team_id]) end enduser.rb
has_liked?
はuser.rb
で定義しています。showアクション内の処理のようにcurrent_userがteamをlikeしてる?
と直感的にわかりやすいと思い、定義しております。user.rbdef has_liked?(team) likes.exists?(team_id: team.id) endindex.html.haml
HTTPリクエストを送るにはJavaScriptでidを取得できるようにしなくてはいけないので、テンプレートにカスタムデータを記述しています。
data-<情報>
とすることで任意の属性を付与することができます。今回はチームに対していいねをしたいのでteam
のid
が必要です。
※routes
を確認するとどこにリクエストを送れば良いかよくわかります。たとえばですが、以下
index.html.haml
のように記述してデベロッパーツールで確認すると
data-team-id="1"
id="active-star1"
このようにdata属性とチームのidが入ったidを取得することができます。
チームのidが入ったidは一覧ページでのいいね機能なので、クリックしたときに特定のチームをいいねするという状況になります。それを判定するために記述しております。実際にjQueryのコードを見ていただいたほうが早いと思いますが、簡単に説明させていただきますと、active-star
というid
だけだと、active-star
というidは複数あるので、全てのチームにいいねをつける処理が実行されてしまいます。そのため、動的なid(今回はチームのid)
を付与しております。数字の1
の部分がチームのidです。ここで重要なのは、
- カスタムデータ
- hiddenでいいねの表示を隠していること
hiddenを使っている理由はいいねの状態を確認し表示するということをAjaxで表示するためです。
index.html.haml.hidden.active-star{id: "active-star#{teams.id}", data: {team_id: tams.id}} = image_tag 'star-yellow.png' .hidden.in-active-star{id: "in-active-star#{teams.id}", data: {team_id: teams.id}} = image_tag 'star-white.png'css.hidden { display: none; }jQuery
本題のいいね機能の実装部分です。
記述が冗長になってしまったので、コメントを入れております。重要なのはcsrfToken
をリクエスト時に持たせることです。これをしないと422 (Unprocessable Entity)というエラー
が起きます。なぜかというとGETと違ってPOSTなどの処理はデータベースの変更をするリクエストなので、簡単に操作されては困るため制約がついています。そのため、rails-ujs
を使ってaxios
でリクエスト時にcsrfToken
というのを持たせるようにしております。jQueryimport $ from 'jquery' import axios from 'axios' import { csrfToken } from 'rails-ujs' // リクエスト時にCSRFトークンを持たせる axios.defaults.headers.common['X-CSRF-Token'] = csrfToken() document.addEventListener('DOMContentLoaded', () => { // ロード時にいいねされていない星を配列で取得 $('.in-active-star').each(function (index, element) { // テンプレートで記述したカスタムデータを取得 let likeData = $(element).data() // カスタムデータからチームIDを取得 let getId = likeData.teamId // カスタムデータを入れてGETリクエストを送る axios.get(`/teams/${getId}/like`) // リクエストを送ったらレスポンスが返ってくる .then((response) => { // responseでrenderされたlikeの状態を取得(true or false) const inActiveStatus = response.data.hasLiked // falseであればいいねされていない => 白い星を表示するために、'hidden'を取り外す if ( inActiveStatus === false ) { $(element).removeClass('hidden') } }) }) // ロード時にいいねされている星を配列で取得 $('.active-star').each(function (index, element) { // テンプレートで記述したカスタムデータを取得 let likeData = $(element).data() // カスタムデータからチームIDを取得 let getId = likeData.teamId // カスタムデータを入れてGETリクエストを送る axios.get(`/teams/${getId}/like`) // リクエストを送ったらレスポンスが返ってくる .then((response) => { // responseでrenderされたlikeの状態を取得(true or false) const activeStatus = response.data.hasLiked // trueであればいいねされている => 黄色い星を表示するために、'hidden'を取り外す if ( activeStatus === true) { $(element).removeClass('hidden') } }) }) // #create いいねをつけたいときの処理 $('.in-active-star').on('click', (e) => { e.preventDefault(); let dataset = $(e.currentTarget).data() // クリックした要素のidを取得 let teamId = dataset.teamId // teamIdを使いPOSTリクエストを送る axios.post(`/teams/${teamId}/like`) .then((response) => { // リクエスト成功なら処理を行う if (response.data.status === 'ok') { $(`#in-active-star${teamId}`).addClass('hidden'); $(`#active-star${teamId}`).removeClass('hidden'); } }) // エラー時の処理 .catch((e) => { window.alert('Error') console.log(e) }) }) // #destroy いいねを外したいときの処理 $('.active-star').on('click', (e) => { e.preventDefault(); let dataset = $(e.currentTarget).data() // クリックした要素のidを取得 let teamId = dataset.teamId // teamIdを使いdeleteメソッドを使う axios.delete(`/teams/${teamId}/like`) .then((response) => { // リクエスト成功なら処理を行う if (response.data.status === 'ok') { $(`#active-star${teamId}`).addClass('hidden'); $(`#in-active-star${teamId}`).removeClass('hidden'); } }) // エラー時の処理 .catch((e) => { window.alert('Error') console.log(e) }) }) })まとめ
- Ajax処理はデベロッパーツールを使い
debugger
やconsole.log()
を使い値が取れているか確認をしっかりすると開発が捗る。- 詳細ページのように一つしかいいねがないときは意識していなかったが、一覧ページなど複数ある中の一つというように特定したいときは個別のidを付与することで実装できる。
- POSTやDELETE時にはデータベースの操作をすることからCSRFトークンというものが必要になる。
最後に
今回はjQueryを使って実装しました。Vue.jsの学習も始めたので、生JSやjQueryをもっと理解したら開発に使っていきたいなと思っています。このように実装するのもひとつの方法だと思いますが、他にもたくさんの実装方法があると思います。他のライブラリやフレームワークではどのように実装するのか、また一度書いたコードもリファクタリングを積極的にやっていけたらと思います!
参考文献
- 投稿日:2020-11-25T21:00:29+09:00
【Week 5】bash, ruby_first
はじめに
マルチスケールシミュレーション特論の講義メモです.講義メモのインデックスはコチラ.
授業内で
学習メモがpublicになっていて,LGTMをもらえている
という指示があったので,拙い内容ですが投稿しています.概要
今回から Ruby の講義に入っていく.講義のメモは各回
- チャート式 Ruby
- Ruby 開発周辺情報
の2点を軸としてまとめる.
チャート式 Ruby 一覧
チャート式 Rubyで扱う内容は以下を予定している.
- puts (出力)
- variable and method (変数とメソッド)
- if-else, case, array and each (条件分岐と配列まわり)
- gem (ライブラリの使い方)
- recursion (再帰)
- class
- 仕上げ問題
Ruby 開発周辺情報 一覧
Ruby 開発周辺情報で扱う内容は以下を予定している.
- bash + emacs
- myhelp
- bundler
- rake
- rubular
- thor
- rubcoop
チャート式 Ruby
参照記事はコチラ
puts
今回から Ruby の講義に入る.はじめに学ぶ内容はプログラミングの初歩中の初歩である文字列の出力についてである.まずはみんな大好き
Hello World.を出力するプログラムを作ってみる.
プログラムを管理するためにcodes ディレクトリを作成し, puts_hello_world.rb を編集する.
> mkdir codes > cd codes > emacs puts_hello_world.rbputs_hello_world.rb は以下のとおり.
puts "hello world."これを実行してみると,
> ruby puts_hello_world.rb hello world.期待通り hello world. が出力された.
Ruby で文字を出力できるメソッドは puts だけでない.以下にいくつか例を挙げる.
メソッド 使い方 引数の値を出力. 改行なし puts 引数の値を出力.改行あり p デバッグ用の出力.引数のオブジェクトがわかる pp require 'pp'が必要.p と同じデバッグ用 printf c 言語と同等.複数の引数を渡すことができる 上記のメソッドを比較するプログラム p_print_hello_world.rb を作成する.p_print_hello_world.rb は以下のとおり.
puts "hello world." print "hello world." p "hello world." pp "hello world." printf "hello world."これを実行してみると,
> ruby p_print_hello_world.rb hello world. hello world."hello world." "hello world." hello world各々出力が異なるので考察してみる.
> puts "hello world." hello world. # > print "hello world." hello world. (改行なし) # > p "hello world." "hello world." # > pp "hello world." "hello world." # > printf "hello world." hello world #ARGV[0]
続いてコマンドライン引数を用いて
> ruby hello_name.rb Rudyと実行したときに,
Hello Rudy.と出力するプログラムを作ってみる.
Ruby でコマンドライン引数を扱うには ARGV[]を使う.python でも sys.argv (sys モジュールの argv メソッド) を使うので,コマンドライン引数を使いたいときはどの言語も argv で検索すれば良さそう.とりあえず hello_name.py を作成し,
puts ARGV[0]を実行してみる.
> ruby hello_name.rb Rudy Rudy確かにコマンドラインの値を出力することができた.
ARG[0]は引数 (argment) 配列のインデックス番号 0 を指している.unix shell 上では command の option として引数を直接渡せるように用意されているらしい.
次にコマンドライン引数と文字列を組み合わせて出力させたい.Ruby ではいくつか方法があるので以下にまとめる.
メソッド プログラム puts puts "Hello " + ARGV[0] puts puts "Hello #{ARGV[0]}" print "Hello #{ARGV[0]}\n" print "Hello " + ARGV[0] + "\n" 先に書いたように printf でも問題なく出力できる.Ruby on Rails で Web アプリケーションを作った際に一番お世話になった2番目のプログラムで書いたものを実行する.
> ruby hello_name.rb Rudy Hello Rudy.無事コマンドライン引数を用いて出力をするプログラムを作成できた.
リダイレクト
実行結果を別ファイルに保存するには,以下のようにリダイレクトを用いるとよい.
> ruby hello_name.rb Hiroki > hello_name.txt'>' はリダイレクト(redirect)といい,出力を txt に変更したものが指定したファイル先に保存される.
Hello Hiroki.また,'<' の場合は 指定したファイルを入力として与えることができる.ファイルの中身は cat (concatinate)
cat hello_name.txtで指定したファイルの中身を見ることができる.
Ruby 開発周辺情報
参照記事はコチラ
bash + emacs
shell
- command 関連
- command [objects]
- command [options] [objects]
- directory 関連
- open [file] # ファイルを開く
- mkdir [DIR] # ディレクトリの作成 (make directory)
- pwd # カレントディレクトリ(print working directory)
- cd [DIR] # ディレクトリの移動 (change directory)
- cd .. # 一つ上のディレクトリへ移動
- ls -al # ファイルやディレクトリの表示 (list all, long)
- process 関連
- ps, top # process status
- fg, bg # fore, back ground
- kill -9 PID # kill process id
などのコマンドで操作するCLI.(command line interface)
emacs
key-bind が充実しているテキストエディタ.というよりも key-bind での操作が前提のテキストエディタといった方が適している.emacs による一連の編集動作は以下のとおり.
> emacs hoge.org # emacsの起動 # ファイル編集後 c-x c-s # ファイルのセーブ c-x c-c (quit) or c-z (stop) # emacsの終了quit は emacs を終了,stop はプロセスを残して一時終了する.stop の場合は
> fgで再び編集中の emacs を呼び出すことができる.
key-bind について,より詳しい内容は以下の記事に随時追加していきます.
【Memo】Emacs key-bind (Editing)
git
git について,詳しい内容は以下の記事に随時追加していきます.
次回の講義内容 <2020-10-28 Wed>
次回の講義は
だそうです.
- source ~/grad_members_20f/members/e79a93e5b7b1/posts/class/c5_20201021.org
- 投稿日:2020-11-25T19:24:45+09:00
Roman Numerals
Roman Numerals
講義ページリンク
課題
アラビア数字を受け取って,それに対応したローマ数字を返すプログラムの作成ついでに整数(Integer)クラスを拡張する
アラビア数字からローマ数字への変換方法
- 各桁を表すのに使用する文字は,1,5,次の桁の1(10)を表す3つ
- 例えば1桁目では(I(1), V(5), X(10)), 2桁目では10倍した(X(10), L(50), C(100))を用いる
- 各桁では,その桁の値に応じて次のルールに従って文字を並べる
- 1~3: 1の文字を数字分並べる(III)
- 4: 5の文字の左に1の文字(IV)
- 5: 5の文字(V)
- 6~8: 5の文字の右に,数字と5の差の分だけ1の文字を並べる(VIII)
- 9: 次の桁の1の文字の左に1の文字(IX)
- 各桁の文字を並べる(439 => CDXXXIX)
解答例
#!/usr/bin/env ruby # frozen_string_literal: true class Integer def to_roman if !between?(1, 3999) puts "#{self} is not supported in #{__method__}." exit else roman = [] roman_symbols = %w[I V X L C D M] digits.to_a.each_with_index do |n, i| ivx = roman_symbols.slice(2 * i, 3) case n when 1..3 then roman.push(ivx[0] * n) when 4 then roman.push(ivx[0] + ivx[1]) when 5 then roman.push(ivx[1]) when 6..8 then roman.push(ivx[1] + (ivx[0] * (n - 5))) when 9 then roman.push(ivx[0] + ivx[2]) end end end roman.reverse.join end end test_data = [1, 2, 4, 5, 6, 9, 10, 11, 14, 15, 19, 38, 42, 49, 51, 97, 99, 439, 483, 499, 732, 961, 999, 1999, 4000] test_data.each do |n| puts "#{n}\t#{n.to_roman}" end出力
> ruby roman_numerals.rb 1 I 2 II 4 IV 5 V 6 VI 9 IX 10 X 11 XI 14 XIV 15 XV 19 XIX 38 XXXVIII 42 XLII 49 XLIX 51 LI 97 XCVII 99 XCIX 439 CDXXXIX 483 CDLXXXIII 499 CDXCIX 732 DCCXXXII 961 CMLXI 999 CMXCIX 1999 MCMXCIX 4000 is not supported in to_roman.NOTE
- Integerクラス内で
self.digits
にアクセスすると,自身の各桁の値を取得できる
- 上記のコードでは
self.
はrubocopに削除されたのでいらないのかも- 更に
.to_a
で配列として取得できる- 配列に対して
.each_with_index
でpythonのenumerateみたいに数値とインデックスを取得できる- pythonみたいにリスト内包表記とかlambdaとかmapとかが使えるともう少し簡潔に書けるだろうが書き方がわからないのでとりあえずこのまま
- あとqiitaにpostしたらなぜか解答例のソースコードのインデントがおかしくなってる…
- source ~/multiscalesim_toku/grad_members_20f/members/lynd2299/roman_numerals.org
- 投稿日:2020-11-25T19:17:46+09:00
Roman Numerals
Roman Numerals
講義ページリンク
課題
アラビア数字を受け取って,それに対応したローマ数字を返すプログラムの作成ついでに整数(Integer)クラスを拡張する
アラビア数字からローマ数字への変換方法
- 各桁を表すのに使用する文字は,1,5,次の桁の1(10)を表す3つ
- 例えば1桁目では(I(1), V(5), X(10)), 2桁目では10倍した(X(10), L(50), C(100))を用いる
- 各桁では,その桁の値に応じて次のルールに従って文字を並べる
- 1~3: 1の文字を数字分並べる(III)
- 4: 5の文字の左に1の文字(IV)
- 5: 5の文字(V)
- 6~8: 5の文字の右に,数字と5の差の分だけ1の文字を並べる(VIII)
- 9: 次の桁の1の文字の左に1の文字(IX)
- 各桁の文字を並べる(439 => CDXXXIX)
解答例
#!/usr/bin/env ruby # frozen_string_literal: true class Integer def to_roman if !between?(1, 3999) puts "#{self} is not supported in #{__method__}." exit else roman = [] roman_symbols = %w[I V X L C D M] digits.to_a.each_with_index do |n, i| ivx = roman_symbols.slice(2 * i, 3) case n when 1..3 then roman.push(ivx[0] * n) when 4 then roman.push(ivx[0] + ivx[1]) when 5 then roman.push(ivx[1]) when 6..8 then roman.push(ivx[1] + (ivx[0] * (n - 5))) when 9 then roman.push(ivx[0] + ivx[2]) end end end roman.reverse.join end end test_data = [1, 2, 4, 5, 6, 9, 10, 11, 14, 15, 19, 38, 42, 49, 51, 97, 99, 439, 483, 499, 732, 961, 999, 1999, 4000] test_data.each do |n| puts "#{n}\t#{n.to_roman}" end出力
> ruby roman_numerals.rb 1 I 2 II 4 IV 5 V 6 VI 9 IX 10 X 11 XI 14 XIV 15 XV 19 XIX 38 XXXVIII 42 XLII 49 XLIX 51 LI 97 XCVII 99 XCIX 439 CDXXXIX 483 CDLXXXIII 499 CDXCIX 732 DCCXXXII 961 CMLXI 999 CMXCIX 1999 MCMXCIX 4000 is not supported in to_roman.NOTE
- Integerクラス内で
self.digits
にアクセスすると,自身の各桁の値を取得できる
- 上記のコードでは
self.
はrubocopに削除されたのでいらないのかも- 更に
.to_a
で配列として取得できる- 配列に対して
.each_with_index
でpythonのenumerateみたいに数値とインデックスを取得できる- pythonみたいにリスト内包表記とかlambdaとかmapとかが使えるともう少し簡潔に書けるだろうが書き方がわからないのでとりあえずこのまま
- source ~/multiscalesim_toku/grad_members_20f/members/lynd2299/roman_numerals.org
- 投稿日:2020-11-25T19:13:58+09:00
Roman Numerals
Roman Numerals
講義ページリンク
課題
アラビア数字を受け取って,それに対応したローマ数字を返すプログラムの作成ついでに整数(Integer)クラスを拡張する
アラビア数字からローマ数字への変換方法
- 各桁を表すのに使用する文字は,1,5,次の桁の1(10)を表す3つ
- 例えば1桁目では(I(1), V(5), X(10)), 2桁目では10倍した(X(10), L(50), C(100))を用いる
- 各桁では,その桁の値に応じて次のルールに従って文字を並べる
- 1~3: 1の文字を数字分並べる(III)
- 4: 5の文字の左に1の文字(IV)
- 5: 5の文字(V)
- 6~8: 5の文字の右に,数字と5の差の分だけ1の文字を並べる(VIII)
- 9: 次の桁の1の文字の左に1の文字(IX)
- 各桁の文字を並べる(439 => CDXXXIX)
解答例
#!/usr/bin/env ruby # frozen_string_literal: true class Integer def to_roman if !between?(1, 3999) puts "#{self} is not supported in #{__method__}." exit else roman = [] roman_symbols = %w[I V X L C D M] digits.to_a.each_with_index do |n, i| ivx = roman_symbols.slice(2 * i, 3) case n when 1..3 then roman.push(ivx[0] * n) when 4 then roman.push(ivx[0] + ivx[1]) when 5 then roman.push(ivx[1]) when 6..8 then roman.push(ivx[1] + (ivx[0] * (n - 5))) when 9 then roman.push(ivx[0] + ivx[2]) end end end roman.reverse.join end end test_data = [1, 2, 4, 5, 6, 9, 10, 11, 14, 15, 19, 38, 42, 49, 51, 97, 99, 439, 483, 499, 732, 961, 999, 1999, 4000] test_data.each do |n| puts "#{n}\t#{n.to_roman}" end出力
> ruby roman_numerals.rb 1 I 2 II 4 IV 5 V 6 VI 9 IX 10 X 11 XI 14 XIV 15 XV 19 XIX 38 XXXVIII 42 XLII 49 XLIX 51 LI 97 XCVII 99 XCIX 439 CDXXXIX 483 CDLXXXIII 499 CDXCIX 732 DCCXXXII 961 CMLXI 999 CMXCIX 1999 MCMXCIX 4000 is not supported in to_roman.NOTE
- Integerクラス内で
self.digits
にアクセスすると,自身の各桁の値を取得できる
- 上記のコードでは
self.
はrubocopに削除されたのでいらないのかも- 更に
.to_a
で配列として取得できる- 配列に対して
.each_with_index
- source ~/multiscalesim_toku/grad_members_20f/members/lynd2299/roman_numerals.org
- 投稿日:2020-11-25T18:39:32+09:00
ActiveRecordでは present? の代わりに exists? を使おう
小ネタです。
条件に該当するレコードが存在するかを確認したい
ActiveRecordで条件に存在するレコードが存在するかを確認するのに、つい、
Model.where(conditions).present?と書いてしまいがちですが、これはパフォーマンス上の問題が生じる可能性があります。
.present?
は ActiveSupport によってモンキーパッチされたメソッドです。
Mode.where(conditions)
のようなActiveRecord_Relation
クラスのオブジェクトに.present?
を適用するとどうなるか?すると条件に該当するレコードを全てDBから取得して、(Rails上のモデルの)配列として評価することになります。
配列に要素が存在すればtrue
、 しなければfalse
ですね。なぜこれはダメなのか
一見すると問題なさそうですし、実際結果自体は正しいのですが、条件に該当するレコードが1つでも存在することを確認できれば良いわけで、全件を取得する必要はありません。
100万レコードが条件に該当した場合、その100万レコードがDBからピックアップされ、その100万レコード分のデータがRails側に転送され、100万のモデルが作成された上で捨てられる。という壮大な無駄が発生します。結果、いつまでたっても結果が返ってこない。というパフォーマンス上の障害を引き起こしてしまうのです。こういうのはレコード数の少ない開発環境では顕在化しずらく、レコード数の多い本番環境でいきなり顕在化してパニックになることがあります。
では、どうする?
.exists?
メソッドを使いましょう。Model.where(conditions).exists?こちらを使うと、SQLが
exists
式を使うものに代わります。
exists
式は条件に該当するレコードが1件でも存在すればDBがそこで探索を打ち切ってくれるので、無駄に全件を取ってくることはありません。
DBレベルでtrue
またはfalse
で返してくれるのでオーバヘッドが最小で済みます。present? の逆は?
.present?
の逆である.blank?
に対応するメソッドは.empty?
になります。
.empty?
を使えばSQL上はexists
式を使います。ただ、条件に該当するレコードが存在しないことを確認するには、結局全件のチェックが必要になるので両者に速度的な差は少ないかもしれません。
- 投稿日:2020-11-25T18:39:16+09:00
TableExportで好きな位置にExcelやCSV出力ボタンを配置する
はじめに
JQueryプラグイン「TableExport」ではテーブルを簡単にExcel、CSV、テキストファイルなどで出力できます。ただ、出力ボタンの位置は上下で固定っぽくて不便だったので、改善策を備忘録として残しておきます。
TableExport自体の使い方はこちらのサイトが分かりやすいので参考にされてください。
開発環境は以下の通り
- Ruby 2.6.3
- Rails 5.2.4.4
- jQuery 1.12.4
(Ruby on Rails使用してますが、今回の記事ではjQueryのみ取り上げているのであまり関係ないかと思います)
なお、bootstrapを使えばデフォルトでオシャレなボタンにできますが今回は使いません。
問題点
Export to xlsxボタンがとんでもないところにありますね。
普通のテーブルだともう少しマシかもしれませんが、このテーブルは見出し固定のスクロール式で、テーブルを横にスライドするとボタンも一緒に流されてしまうので余計見にくい代物になってしまいます。。
一応オプションでボタンの位置を指定できますが、前述した通り上下の指定しかできないので改善には至りませんでした。$(".table").tableExport({ ... position: "bottom", ... });解決策
至ってシンプルです。
①tableExport()で生成されるボタンを隠して代理ボタンを配置する
②代理ボタンが押されたらtrigger()でもともとのボタンが押されたことにするhtmlファイル... <table id="export-table"> ... </table> <button type="button" id="export-btn">Excel出力</button> ...jqueryファイル... $('#export-table').tableExport({ formats: ["xlsx"], bootstrap: false }); $('#export-table caption').hide(); $('#export-btn').on('click', function(){ $('.table caption button').trigger('click'); }); ...うまくいきました!
もちろんCSVやテキストファイルの出力にも使用できます。おわりに
TableExportはとても簡単に外部ファイルを出力できるプラグインですが、扱っている記事自体がとても少ないので、こういうちょっとした解決策っていうのはもっと増えていくと嬉しいですね。
- 投稿日:2020-11-25T18:37:56+09:00
チャート式 ruby-V (Recursive Fibonacci)
目的
ruby のコードを実際に書いてみよう.今回は第 V 弾.
お題:Fibonacci数列
fib(n) = fib(n-1)+fib(n-2) 0 1 1 2 3 5 8 13 21 ...を recursion (再帰) で求める.
解説
以下のような関数 fib をつくる
- 入力 : n (項の番号)
- 出力 : 第 n 項の値
今回は TDD (Test Driven Development : テスト駆動開発) を意識して解説を書く.
- テストを作る
- red : エラーを出す
- green : エラーをなくす (green)
- refactoring : code を綺麗にする (refactoring)
fib(0) = 0
初項 (0) を関数 fib に渡して, 初項の値 0 が返ってくるようにする.
ではまず, テストをつくって, red.
emacs fibonacci.rbでファイルを作成&オープンし,
p fib(0)と書いて,
ruby fibonacci.rbで実行.もちろん, そんな関数作ってないのでエラーがくる.
そこで, green.
def fib(n) if n==0 return 0 end endこれでひとまずエラーがなくなって, 実行が通る.
次に, refactoring.
前回つくった "assert_equal_final.rb" の assertion を試す.
# 「require './assert_equal_final.rb'」でも良い require './assert_equal_final' assert_equal(0, fib(0))うまくいった.
fib(1) = 1
次は第 1 項に対しての処理.
ではまず, テストをつくって, red.
assert_equal(1, fib(1))もちろん失敗.
じゃあ, green.
n が 1 の時の処理を書き足して,
def fib(n) if n==0 return 0 end if n==1 return 1 end endこれで実行通る.
refactoring
テストの文が重複してきたので,
[[0,0],[1,1]].each do |pair| assert_equal(pair[0], fib(pair[1])) endこうする.もちろん実行通る.
fib(2) = fib(1) + fib(0) = 0+1 = 1
続いては, 第 2 項に対する処理.
ではまず, テストをつくって, red.
[[0,0],[1,1],[2,1]].each do |pair| assert_equal(pair[0], fib(pair[1])) endそうすると,
$ ruby fibonacci.rb expected :: 0 result :: 0 succeeded in assert_equal. expected :: 1 result :: 1 succeeded in assert_equal. expected :: 2 result :: 1 failed in assert_equal.もちろん失敗.
green
じゃあ n が 2 に対する処理を追加.
def fib(n) if n==0 return 0 end if n<=2 return 1 end endあれ, うまくいかない.これはテストの書き方が悪い.
# 「assert_equal(pair[0], fib(pair[1]))」 ではなく assert_equal(pair[1], fib(pair[0]))これで ok.
refactoring
そもそも pair[0], pair[1] が分かりづらくて良くなかった.
[[0,0],[1,1],[2,1]].each do |index, expected| assert_equal(expected, fib(index)) endこうやって, 明示的にするととても分かりやすい.
refactoring
そしてこのあたりで, 「あれ, code ごちゃついてきた」 となる.じゃあ短くしよう.
def fib(n) return 0 if n==0 return 1 if n<=2 endこうすると, 短い上にわかりやすい. 素晴らしい.
fib(3) = fib(2) + fib(1) = 1+1 = 2
さっきと同様に red & green.
code は,
def fib(n) return 0 if n==0 return 1 if n<=2 return 2 end今はとりあえずこれで ok.
refactoring
ここで code を修正.
def fib(n) return 0 if n==0 return 1 if n<=2 return fib(2) + fib(1) endこれで良いよね.
fib(4) = fib(3) + fib(2) = 2+1 = 3
red & green & refactoring.
def fib(n) return 0 if n==0 return 1 if n<=2 return fib(2) + fib(1) return fib(3) + fib(2) endこう書いてみると,
def fib(n) return 0 if n==0 return 1 if n<=2 return fib(n-1) + fib(n) endこうで良いよねって気づく. もっと言うと,
def fib(n) return 0 if n==0 return 1 if n==1 # n<=2ではなく return fib(n-1) + fib(n) endこれで良いよね. そして, fib(4) 以降 (fib(5), fib(6), …) も出来上がり.
まとめ
TDD で良い感じに Fibonacci 数列の code を書けた. 素晴らしい.
今回書いた code の全体
最終的にこうなった. ファイル名は "fibonacci.rb".
require './assert_equal_final' def fib(n) return 0 if n==0 return 1 if n==1 return fib(n-1) + fib(n-2) end if $PROGRAM_NAME == __FILE__ [[0,0],[1,1],[2,1],[3,2],[4,3], [5,5],[6,8],[7,13],[8,21],[9,34]].each do |index, expected| assert_equal(expected, fib(index)) end end参考ページ
チャート式ruby-V(Recursive Fibonacci)
- source ~/Lecture/multiscale_simulation/grad_members_20f/members/gagagagazelle/docs/c5_fibonacci.org
- 投稿日:2020-11-25T18:26:41+09:00
RailsでTimecop/TimeHelpersを使って時刻を変える方法について
この記事は、Happy Elements Advent Calendar 2020の5日目です。
RailsでTimecop/TimeHelpersを使って時刻を変える方法についての記事です。はじめに
ソーシャルゲームでは、イベントが yyyy年mm月dd日に始まるなど、特定の時刻になると発動することが定番です。
これらのようなイベントの動作を確認するために、サーバ側で時刻を変えることができると、動作テストがしやすくなります。
- 例1 12月2日 15:00開始のガチャAの動作確認をするために、サーバの時間を12/2 16時にセットする
- 例2 バグ報告があったので、1ヶ月前のイベントの時間にセットしてバグ調査をする などサーバ側で時刻を変える方法について、以下の3つの方法に絞って調査しました。
- Timecop
- ActiveSupport::Testing::TimeHelpers
- libfaketimeこの記事では、それぞれがどのようなものか、をまとめました。
Timecop
https://github.com/travisjeffery/timecop
こちらはRailsのgemです。
Time/Date/DateTimeクラスのオーバーライドとして実装されているものでした
https://github.com/travisjeffery/timecop/blob/master/lib/timecop/time_extensions.rb調査を進めると、TimeHelpersという物がRailsに組み込まれていることがわかりました。
TimeHelpersは、Timecopより機能としては少なく、時刻を固定させるのみです。
Timecopは、固定の他に、過去や未来に設定した後に時刻が進むなども可能です。TimecopとTimeHelperでは、Timecopの方がリッチな機能である、と言えると思います。
- 標準のTimeHelpersで十分である
- gemを入れたくない
などの場合は、TimeHelpersの利用が選択肢に上がってくると思います。
2020年現在もメンテナンスはされているようです。ActiveSupport::Testing::TimeHelpers
https://edgeapi.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html
Rails4.1以降で標準のものです。
時刻を固定・解除するのみです。libfaketime
https://github.com/wolfcw/libfaketime
こちらはRailsの話ではなく、OSにインストールして動くサービスです。
システムコールを改変するものです
- メリット
- プログラムを変えなくていい
- デメリット
- 導入が少し手間
システムコールとは?
libfaketimeでシステムコールの話が出てきたので、ここではシステムコールについて。
strace というコマンドを使って、コマンドを打つと大量にログが出てきます。これがシステムコールです(fstat, close, read, ...etc)。
libfaketimeは、このシステムコールを書き換えて時刻を変えるので、TimecopやTimeHelpersよりも深い部分で動いていると言えると思います。strace date execve("/bin/date", ["date"], 0x7ffc3bc97870 /* 28 vars */) = 0 brk(NULL) = 0x55b92bdc6000 openat(AT_FDCWD, "/usr/local/lib/faketime/libfaketime.so.1", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0$\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0644, st_size=66512, ...}) = 0 ... read(4, "@2020-6-16 20:30:00\n", 4096) = 20 close(4) = 0 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0 write(1, "Tue Jun 16 20:30:00 JST 2020\n", 29Tue Jun 16 20:30:00 JST 2020 ) = 29 close(1) = 0 close(2) = 0 munmap(0x7f46f7935000, 8) = 0 munmap(0x7f46f7936000, 32) = 0 exit_group(0) = ? +++ exited with 0 +++余談
調査中に、もしTimecopとlibfaketimeを同時に使った場合どうなるのだろう、と思いました。
実験してみたところ、Timecopで設定した時刻がRailsでは得られました。libfaketimeで改変された時間を、さらにTimecopが上書きするという順序になります。
イメージ図は以下の通りです。まとめ
自分が運営中のタイトルでは、開発者の手元では、TimeHelpersを使ってRailsの時刻を変えながらイベントの動作確認などに利用しています。libfaketimeも使えるようになっており、必要であればそちらも利用しています。
こちらの記事では、サーバ側で時刻を変える方法について、Timecop, TimeHelpers, libfaketimeを調査しました。
調査してわかりましたが、どれが優れているというものではありませんでした。
それぞれ、やりたいことの要件に合わせて選択すれば良いと思いました。
もしRailsで時刻を変えたいけど、どうしようと悩んで調べている方がいらっしゃいましたら、
参考にしていただけると幸いです。(注) 記事の中の図は自分で用意しました
参考
https://andycroll.com/ruby/replace-timecop-with-rails-time-helpers-in-rspec/
https://techracho.bpsinc.jp/penguin10/2018_12_25/67780
https://qiita.com/ktrkmk/items/b1361dd43d22dcf5627e
https://qiita.com/Targityen/items/67682d6c80cdcbe1186c終わりに
Happy Elements株式会社 カカリアスタジオでは、
いっしょに【熱狂的に愛されるコンテンツ】をつくっていただけるメンバーを大募集中です!もし弊社にご興味持っていただけましたら、是非一度
下記採用サイトをご覧ください。
https://recruit.happyelements.co.jp/
- 投稿日:2020-11-25T17:49:55+09:00
Railsでタグ機能を実装
はじめに
現在作成しているアプリでタグ機能を実装したのでその実装方法を残しておきます。
Railsにはタグ機能の実装を簡単にしてくれる acts-as-taggable-on というgemがありますが、関連付けの練習も踏まえて自前で実装します。
現在作っているアプリのPK,FKのみを示したER図は以下のようになります。
実行環境
この記事は以下の環境で動作確認しています。
ruby 2.7.1
rails 6.0.3
DB MySQLモデルの作成
Profileモデルは既に作ってあるという前提で進めていきます。
まず、tagモデルとtag_relastionshipモデルを作成します。$ rails g model tag name:string $ rails g model tag_relationship profile:references tag:references複合キーインデックスを張ります。
こうすることにより、同じタグを二回保存できないようにします。XXXXXXXXXXXXXX_create_tag_relationships.rbclass CreateTagRelationships < ActiveRecord::Migration[6.0] def change create_table :tag_relationships do |t| t.references :profile, foreign_key: true t.references :tag, foreign_key: true t.timestamps end add_index :tag_relationships, [:profile_id, :tag_id], unique: true end endタグ名は必ず入力して欲しいので
null:false
にします。XXXXXXXXXXXXXX_create_tags.rbclass CreateTags < ActiveRecord::Migration[6.0] def change create_table :tags do |t| t.string :name, null: false t.timestamps end end endモデルの関連付けとバリデーション
基本的な中間テーブルを用いる多対多の実装です。
中間デーブル経由でタグに紐付くprofileの情報を取得できるように has_many throughも定義します。これに関してはprofileモデルでも同じです。
タグ名はユニークで必ず保持していて欲しいので以下のようなバリデーションにします。tag.rbclass Tag < ApplicationRecord has_many :tag_relationships, dependent: :destroy has_many :profiles, through: :tag_relationships validates :name, uniqueness: true, presence: true endtag_relationship.rbclass TagRelationship < ApplicationRecord belongs_to :profile belongs_to :tag validates :tag_id, presence: true validates :profile_id, presence: true endprofile.rbclass Profile < ApplicationRecord belongs_to :user has_many :tag_relationships, dependent: :destroy has_many :tags, through: :tag_relationships endviewの作成
現在作成しているアプリではプロフィールの新規登録の際にタグも登録して欲しいので
profiles/new.html.erb
で実装します。
タグの部分だけ抜粋して載せます。
f,text_field :tag
とすることでparams[:profile][:tag]でパラメーターを受け取れるようにします。profiles/new.html.erb<div class="input-field col s12"> <i class="material-icons prefix">local_offer</i> <%= f.text_field :tag, placeholder: "タグを複数つけるには' , 'で区切ってください" %> </div>表示する際はeachで配列で保存されているタグを繰り返し表示します。
profiles/show.html.erb<% @user_profile.tags.each do |tag| %> <div class="chip"> <%= tag.name %> <i class="close material-icons">close</i> </div> <% end %>コントローラーの作成
ユーザーとプロフィールは
has_one
を用いて一対一の関係にしているので、buildする際は「インスタンス名.build_アソシエーション名」としています。プロフィール情報と一緒に送られてきたタグを保存できるようにします。
profiles_controller.rbdef new @user_profile = current_user.build_profile end def create @user_profile = current_user.build_profile(profile_params) # profile_paramsはストロングパラメーター tag_list = params[:profile][:tag].split(',') # viewでカンマ区切りで入力してもらうことで、入力された値をsplit(',')で配列にしている。 if @user_profile.save @user_profile.save_tags(tag_list) # save_tagsというクラスメソッドを使って保存している。 flash[:notice] = "プロフィールの設定が完了しました" redirect_to root_url else render 'new' end endsave_tagsメソッドは下記に示します。
profile.rbdef save_tags(profile_tag) profile_tag.each do |tag| new_tag = Tag.find_or_create_by(name: tag) self.tags << new_tag end end「find_or_create_by」メソッドは引数で指定した値があればそれを取得し、なければ作成します。名前の通り、findかcreateするメソッドです。
self.tags << profile_tag ではプロフィールに関連したタグの配列に新たなタグを追加しています。
<< だけでなく、pushメソッドを使っても同じように要素を追加することができます。タグの編集機能
プロフィールを編集する際にタグも変更できるようにします。
viewの一部を抜粋します。
profiles/edit.html.erb<div class="input-field col s12"> <i class="material-icons prefix">local_offer</i> <%= f.text_field :tag, value: @tag_list, placeholder: "タグを複数つけるには' , 'で区切ってください" %> </div>
value: @tag_list
とすることで既存の値を表示します。editアクションではviewで既存の値を表示するために@tag_listを記述します。
pluck関数を使うことによってレシーバのカラムを簡単に取得します。
今回は@user_profile.tags.pluck(:name)
としているのでプロフィールに関連したタグのnameカラムを配列で取得します。
join(',')で取得した配列を「,」で区切った文字列にします。profiles_controller.rbdef edit @user = Profile.find(params[:id]).user @user_profile = @user.profile @tag_list = @user_profile.tags.pluck(:name).join(',') end def update @user = Profile.find(params[:id]).user @user_profile = @user.profile tag_list = params[:profile][:tag].split(',') if @user_profile.update(profile_params) @user_profile.save_tags(tag_list) flash[:notice] = "プロフィールの変更が完了しました" redirect_to root_url else render 'edit' end end今回は繰り返しの処理が単純なのでpluck関数を使わなくても「&:メソッド」を使えばタグの名前を同程度の記述量で取得することができます。
@user_profile.tags.map(&:name).join(',')
しかし、今回の場合、pluckは指定したカラムのみをSQLで取ってくるのでmapより早いと思われます。(間違っていたらご指摘いただければ幸いです)なのでこのままpluckを使用します。save_tagsメソッドを更新でも使えるようにします。
profile.rbdef save_tags(profile_tag) current_tags = self.tags.pluck(:name) unless self.tags.nil? old_tags = current_tags - profile_tag new_tags = profile_tag - current_tags # 古いタグを削除 old_tags.each do |old_tag| self.tags.delete(Tag.find_by(name: old_tag)) end # 新しいタグを追加 new_tags.each do |new_tag| add_tag = Tag.find_or_create_by(name: new_tag) self.tags << add_tag end end文字列の配列でも下記の例のように引き算できます。
a = ["first", "second", "third"]
b = ["first", "third", "forth"]
a - b => ["second"]
b - a => ["forth"]
これを用いて古いタグ、新しいタグを分けてそれぞれ処理します。最後に
これでタグの作成、編集機能は完成です。
まだユーザーに取って良い形とは言えないのでjsを使うなどしてユーザーにとって使いやすいものに改善していこうと思います。参考
pluckメソッドが便利な件について
pluckとmapの違いを調査する
Railsでタグ機能をgemを使わずに実装した際のメモ
- 投稿日:2020-11-25T17:36:36+09:00
Ruby CLIにて、実行部をクラス内でコードする
ロジックをクラス内で実装し、処理はメインメソッドにまとめたいときに使用した書き方です。
Rubyで使い捨てCLIを作成したときにお世話になりました。class SomethingTool def run end end if __FILE__ == $0 something_tool = SomethingTool.new something_tool.run end
if __FILE__ == $0
は、明示的に「ここがメインの処理」と示すために使ってます。
詳しい説明は下記の記事を参考にして下さい。
[Ruby] if FILE == $0 ってなんなの!?
- 投稿日:2020-11-25T17:04:25+09:00
Railsの1対多の作成
本投稿の目的
・Rails学習の議事録です。
学習に使った教材
Udemyの以下2つの教材を参考にまとめました。
・"はじめてのRuby on Rails入門-RubyとRailsを基礎から学びWebアプリケーションをネットに公開しよう"
・"フルスタックエンジニアが教える 即戦力Railsエンジニア養成講座"
○1対多とは?
・紐づいたmodel間での関係の名称
・ex)ツイートmodelとコメントmodle
・この時,ツイート1つに対して複数コメントが可能
・この関係を"1対多"の関係と呼ぶ【説明の簡略のために書き省略記号を使用】
・素となるmodel = model(1)
・紐づくmodel = model(多)
*(コーディング例では任意のmodel名が入る)【1対多の関係におけるmodel関係の名称を2つ示す】
・has many = model(1)から見たmodel(多)の関係
・belongs to = model(多)からみたmodel(1)の関係○model(他)作成後の操作
①model(多)の作成
qiita.rbrails g model model(多) model(1): references【解説】
○model(1): references
⇨ referencesでmodel(1)を紐けるように設定
⇨ これで,model(多)には, model名(1)_id というcolumnが作成される【例:Q&Aアプリケーションのmodelを想定】
qiita.rbrails g model answer questin: references【解説】
⇨ answer model へ question model を紐付ける
⇨ questionのcolumnに answer_id が作成される②model(多)のmigrationファイルへの記述
・model(多)を紐づけで作成しておけば自動記述される
qiita.rbclass Create+model(多) < ActiveRecord::Migration[5.0] def change create_table :model(多)s do |t| t.references :model(1), foreign_key: true t.string :column名1, null: false t.text :column名2, null: false t.timestamps end end end【解説】
○null: faluse
⇨ column値に 空 を受け付けない○t.reference :model(1), foreign_key: true
⇨ model(1)のid にないと,model(1)_idとしてmodel(多)で保存できない③model(多)のdbの作成
rails db:migrate④model(多)のmodelファイルへの記述(自動記述)
・model(多)作成時に,以下が,model(多)のmodelファイルへ自動で記述される
qiita.rbclass model(多) < ApplicationRecord belongs_to :model(1) end【解説】
○belongs_to :model(1)
⇨ (*model(1)名称は単数係)【例:answer modelに紐づくquestion modelの場合】
qiita.rbclass Answer < ApplicationRecord belongs_to :question end○belongs_to :question⇨ 親がmodel(1) で 子がmodel(多)
⇨ (model(多)から見るとmodel(1)は1つに定まる)
⇨ (子供は複数人いるが,親や一位に定まるというイメージ)⑤model(1)のmodelファイルへの記述(手動記述)
・model(1)については,追加で以下の記述を追加する
qiita.rbhas_many :model(多)s, dependent: :destroy【解説】
○has_many :model(多)s
⇨ 一番上の行に記述する
⇨ (*モデル名(多)は複数形)○dependent: :destroy
⇨ model(1)が削除されると紐づいたmodel(多)は自動で消される という設定【例:Answerの素となるQuesitionの場合】
qiita.rbclass Question < ApplicationRecord has_many :answers, dependent: :destroy end⑥rails routesの更新
・config/routes.rb ファイルを開く
・内容を次のように更新 (do 移行が追加で更新する部分)
*(model名は複数形)qiita.rbresources :model(1)s do resources :model(多)s end
- 投稿日:2020-11-25T16:22:21+09:00
マルチスケールシミュレーション特論:第 10 回をまとめてみた
フィボナッチ数列(問題)
本日は Fibonacci 数列についての問題を解く
fib(n) = fib(n-1)+fib(n-2) 0 1 1 2 3 5 8 13 21 ...を recursion(再帰)で求めよ
進め方
前回と同様に テスト駆動開発 で今後の学習を進めて行く
まずは初項から計算を行う
- red: 表示を行うred → p fib(0)エラーがおこる
green: def をしてみる
def fib(n) if n==0 return 0 end endrefactoring: assert_equal.rb の assertion(確認)を試しておく
次は、2 項目を求める
- これは初項と同様に求める
次は 3 項目 = 2 項目 + 1 項目
この処理を逐一行っていく。エラーが現れたら随時処理を行っていく
プログラム(最終版)
上記のようにプログラムを書き進めていくと以下のようなプログラムができます
def fib(n) return 0 if n==0 return 1 if n==1 return fib(n-1) + fib(n-2) end require './assert_equal' # assert_equal.rb は同じディレクトリにある事を想定 [[0,0],[1,1],[2,1],[3,2],[4,3], [5,5],[6,8],[7,13],[8,21]].each do |index, expected| puts assert_equal(expected, fib(index)) endclass 化
次にクラス化について学習を行ったオブジェクト指向という考え方がある。このキーとなる考え方が,
- 隠蔽(capsulation)
- 継承(inheritance)
- 多形(polymorphism)
である
クラス化とは
簡単にまとめると、オブジェクト指向プログラミングにおけるクラス(英:class)とは、オブジェクトを生成するための設計図あるいはひな形に相当するものである
プログラムをクラス化すると
まずは class なしのプログラム
def puts_hello name puts "Hello #{name}." end def gets_name name = ARGV[0] || 'world' return name end次にクラスありのプログラム
class Hello def initialize # インスタンス変数 @name = gets_name(name) puts_hello end def puts_hello puts "Hello #{@name}." end def gets_name name = ARGV[0] || 'world' return name end endインスタンス変数について
- 宣言
変数の初めに「@」をつけることで宣言を行うことができる
- スコープ
インスタンスメソッド内でのみ使用できる変数。インスタンスごとに異なる値を持つことができ、メソッドを超えて参照することができる
- source ~/Downloads/git/grad_members_20f/members/taiseiyo/memos/class10.org
- 投稿日:2020-11-25T16:00:41+09:00
プルダウン型セレクトメニューに、DBから項目を持ってくるには??
はじめに
・セレクトボックス(プルダウン型)を作りたい
・メニュー項目に異なるテーブルの情報を持ってくるには??こうした部分で実際に悩んだので、メモとして残しておきます。
*結論から言うと、collection_selectでうまくいきます!!まずやったこと
1. モデルの関連付け
今回だと、商品モデルとジャンルモデルを紐付けました
product.rbclass Product < ApplicationRecord belongs_to :genre endgenre.rbclass Genre < ApplicationRecord has_many :products, dependent: :destroy end***今回、モデルのアソシエーションを行いましたが、やる必要はなかったです!!***
2. 使用するコントローラで変数を定義
今回の場合、productsコントローラを使用するので、
newアクションに、フォーム部分での受け皿となる@newproductを定義し,
実行したいcreateアクションも定義します。products_controller.rbdef new @newproduct = Product.new end # 商品新規登録 def create @newproduct = Product.new(product_params) @newproduct.save redirect_to リダイレクト先 endプルダウンメニューを作ろう
まず、collection_selectの使い方をみましょう。
以下の記事を参考にしました!!
[Rails 4.x] FormのSelect プルダウンメニューの項目をDBから引っ張ってくる方法collection_selectの文法
<%= f.collection_select :属性名, 表示用の配列データ, :valueとして扱うカラム名, :表示用のカラム名, オプション %>とりあえずcollection_selectを使ってみた
3. メニューの項目をジャンルテーブルのDBから持ってくる。
~admin/products/new/html/erb<%= form_with model: @newproduct local: true do |f| %> <div class="form-group"> <%= f.label :genre_id, 'ジャンル' %> <%= f.collection_select :genre_id, Genre.all, :id, :name, :include_blank => '選択してください', required: true %> </div> <% end %>これでうまくプルダウンメニューを表示できました!!
気になったこと
・表示用の配列データは、モデルの関連付けが行われているから、
Genre.all
を持ってこられるのだろうか?
・属性名のgenre_id
はラベルと共通にすべきなのか??
- 投稿日:2020-11-25T15:56:50+09:00
マルチスケールシミュレーション特論:第 10 回をまとめてみた
フィボナッチ数列(問題)
本日は Fibonacci 数列についての問題を解く
fib(n) = fib(n-1)+fib(n-2) 0 1 1 2 3 5 8 13 21 ...を recursion(再帰)で求めよ
進め方
前回と同様に テスト駆動開発 で今後の学習を進めて行く
まずは初項から計算を行う
- red: 表示を行うred → p fib(0)エラーがおこる
green: def をしてみる
def fib(n) if n==0 return 0 end endrefactoring: assert_equal.rb の assertion(確認)を試しておく
次は、2 項目を求める
- これは初項と同様に求める
次は 3 項目 = 2 項目 + 1 項目
この処理を逐一行っていく。エラーが現れたら随時処理を行っていく
プログラム(最終版)
上記のようにプログラムを書き進めていくと以下のようなプログラムができます
def fib(n) return 0 if n==0 return 1 if n==1 return fib(n-1) + fib(n-2) end require './assert_equal' # assert_equal.rb は同じディレクトリにある事を想定 [[0,0],[1,1],[2,1],[3,2],[4,3], [5,5],[6,8],[7,13],[8,21]].each do |index, expected| puts assert_equal(expected, fib(index)) end
- source ~/Downloads/git/grad_members_20f/members/taiseiyo/memos/class10.org
- 投稿日:2020-11-25T15:56:17+09:00
マルチスケールシミュレーション特論:第 10 回をまとめてみた
フィボナッチ数列(問題)
本日は Fibonacci 数列についての問題を解く
fib(n) = fib(n-1)+fib(n-2) 0 1 1 2 3 5 8 13 21 ...を recursion(再帰)で求めよ
進め方
前回と同様に テスト駆動開発 で今後の学習を進めて行く
まずは初項から計算を行う
- red: 表示を行うred → p fib(0)エラーがおこる
green: def をしてみる
def fib(n) if n==0 return 0 end endrefactoring: assert_equal.rb の assertion(確認)を試しておく
次は、2 項目を求める
- これは初項と同様に求める
次は 3 項目 = 2 項目 + 1 項目
この処理を逐一行っていく。エラーが現れたら随時処理を行っていく
プログラム(最終版)
上記のようにプログラムを書き進めていくと以下のようなプログラムができます
def fib(n) return 0 if n==0 return 1 if n==1 return fib(n-1) + fib(n-2) end require './assert_equal' # assert_equal.rb は同じディレクトリにある事を想定 [[0,0],[1,1],[2,1],[3,2],[4,3], [5,5],[6,8],[7,13],[8,21]].each do |index, expected| puts assert_equal(expected, fib(index)) end
- source ~/Downloads/git/grad_members_20f/members/taiseiyo/memos/class10.org
- 投稿日:2020-11-25T15:55:39+09:00
マルチスケールシミュレーション特論:第 10 回をまとめてみた
フィボナッチ数列(問題)
本日は Fibonacci 数列についての問題を解く
fib(n) = fib(n-1)+fib(n-2) 0 1 1 2 3 5 8 13 21 ...を recursion(再帰)で求めよ
進め方
前回と同様に テスト駆動開発 で今後の学習を進めて行く
まずは初項から計算を行う
- red: 表示を行うred → p fib(0)エラーがおこる
green: def をしてみる
def fib(n) if n==0 return 0 end endrefactoring: assert_equal.rb の assertion(確認)を試しておく
次は、2 項目を求める
- これは初項と同様に求める
次は 3 項目 = 2 項目 + 1 項目
この処理を逐一行っていく。エラーが現れたら随時処理を行っていく
プログラム(最終版)
上記のようにプログラムを書き進めていくと以下のようなプログラムができます
def fib(n) return 0 if n==0 return 1 if n==1 return fib(n-1) + fib(n-2) end require './assert_equal' # assert_equal.rbは同じディレクトリにある事を想定 [[0,0],[1,1],[2,1],[3,2],[4,3], [5,5],[6,8],[7,13],[8,21]].each do |index, expected| puts assert_equal(expected, fib(index)) end
- source ~/Downloads/git/grad_members_20f/members/taiseiyo/memos/class10.org
- 投稿日:2020-11-25T15:54:34+09:00
google recruit
課題
https://qiita.com/daddygongon/items/ba94b0f2a73990fc6a07
問題
{e(自然対数の底)の値で連続する10桁の数のうち,最初の素数} をrubyで求めよ.
解答
ソースコード
#!/usr/bin/env ruby # frozen_string_literal: true napier_number = <<~EOS 2.71828182845904523536028747135266249775\ 7247093699959574966967627724076630353547\ 5945713821785251664274274663919320030599\ 2181741359662904357290033429526059563073\ 81323286279434907632338298807531952510190 EOS digits = 10 def prime?(n) return false if n.even? (3...Math.sqrt(n)).step(2).each do |i| return false if n % i == 0 end true end (2...napier_number.length - digits).each do |i| n = napier_number[i, digits].to_i if prime?(n) puts "#{n} is the first 10 digit prime number." break end end実行結果
(*'-') < ./codes/google_recruit.rb 7427466391 is the first 10 digit prime number.学んだこと
ヒアドキュメント
https://docs.ruby-lang.org/ja/latest/doc/spec=2fliteral.html#here
<<[(-|~)]["'`]識別子["'`] ... 識別子で、文字列を表現することができる。
prime
require 'prime'
することによって、Prime.prime?(n)
で素数判定できる。#!/usr/bin/env ruby # frozen_string_literal: true require 'prime' napier_number = <<~EOS 2.71828182845904523536028747135266249775\ 7247093699959574966967627724076630353547\ 5945713821785251664274274663919320030599\ 2181741359662904357290033429526059563073\ 81323286279434907632338298807531952510190 EOS (2...napier_number.length - 10).each do |i| n = napier_number[i, 10].to_i p n if Prime.prime?(n) end
- source ~/go/src/github.com/TeamNishitani/grad_members_20f/members/iPolyomino/google_recruit.org
- 投稿日:2020-11-25T15:54:10+09:00
マルチスケールシミュレーション特論:第 10 回をまとめてみた
フィボナッチ数列(問題)
本日は Fibonacci 数列についての問題を解く
fib(n) = fib(n-1)+fib(n-2) 0 1 1 2 3 5 8 13 21 ...を recursion(再帰)で求めよ
進め方
前回と同様に テスト駆動開発 で今後の学習を進めて行く
まずは初項から計算を行う
- red: 表示を行うred → p fib(0)エラーがおこる
green: def をしてみる
def fib(n) if n==0 return 0 end endrefactoring: assert_equal.rb の assertion(確認)を試しておく
次は、2 項目を求める
- これは初項と同様に求める
次は 3 項目 = 2 項目 + 1 項目
この処理を逐一行っていく。エラーが現れたら随時処理を行っていく
プログラム(最終版)
上記のようにプログラムを書き進めていくと以下のようなプログラムができます
def fib(n) return 0 if n==0 return 1 if n==1 return fib(n-1) + fib(n-2) end require './assert_equal' [[0,0],[1,1],[2,1],[3,2],[4,3], [5,5],[6,8],[7,13],[8,21]].each do |index, expected| puts assert_equal(expected, fib(index)) end
- source ~/Downloads/git/grad_members_20f/members/taiseiyo/memos/class10.org
- 投稿日:2020-11-25T15:47:18+09:00
第8回
assert_equalを作る
イコールかそうでないかをお知らせしてくれるメソッド.
文字の色付け
成功したかどうかを色で端的に分かった方が良い.
require 'colorize' puts '出力1'.green #緑色に puts '出力2'.red #赤色に puts '出力1'.blue #青色にとりあえずassert_equalとassert_not_equalを作る
#{method}でメソッド名が取れる.
require 'colorize' def assert_equal(expected, result) puts "expected :: #{expected}" puts "result :: #{result}" if expected == result print "succeeded in #{__method__}.\n".green else print "failed in #{__method__}.\n".red end end def assert_not_equal(expected, result) puts "expected :: #{expected}" puts "result :: #{result}" if expected == result print "failed in #{__method__}.\n".red else print "succeeded in #{__method__}.\n".green end end assert_equal(1, 1) assert_equal(1, 2) assert_not_equal(1, 2) assert_not_equal(1, 1)重複部分の整理
assert_equal とassert_not_equalで重複してる部分があるなぁ…
require 'colorize' def puts_vals(expected,result) puts "expected :: #{expected}" puts "result :: #{result}" end def assert_equal(expected, result) puts_vals(expected, result) if expected == result print "succeeded in #{__method__}.\n".green else print "failed in #{__method__}.\n".red end end def assert_not_equal(expected, result) puts_vals(expected, result) if expected == result print "failed in #{__method__}.\n".red else print "succeeded in #{__method__}.\n".green end end assert_equal(1, 1) assert_equal(1, 2) assert_not_equal(1, 2) assert_not_equal(1, 1)と重複部分は別の関数に.
別のスクリプトでassert_equalを使う
その前に
別スクリプトで使いたいのはassert_equal及びassert_not_equal.
assert_equal(1, 1) assert_equal(1, 2) assert_not_equal(1, 2) assert_not_equal(1, 1)の部分は要らない.
if $PROGRAM_NAME == __FILE__ assert_equal(1, 1) assert_equal(1, 2) assert_not_equal(1, 2) assert_not_equal(1, 1) endとすることで,書かれているファイル名と動いているファイル名が一致した時のみ実行させることができる.
使う
先ほどの変更を加えたassert_equal
require 'colorize' def puts_vals(expected,result) puts "expected :: #{expected}" puts "result :: #{result}" end def assert_equal(expected, result) puts_vals(expected, result) if expected == result print "succeeded in #{__method__}.\n".green else print "failed in #{__method__}.\n".red end end def assert_not_equal(expected, result) puts_vals(expected, result) if expected == result print "failed in #{__method__}.\n".red else print "succeeded in #{__method__}.\n".green end end if $PROGRAM_NAME == __FILE__ assert_equal(1, 1) assert_equal(1, 2) assert_not_equal(1, 2) assert_not_equal(1, 1) endをrequireで呼び出して使用する.
require './assert_equal' assert_equal(4, 2 * 2) assert_not_equal('Muku', 'Miku')call_equal.rbを作成し,実行.
> ruby call_equal.rb expected :: 4 result :: 4 succeeded in assert_equal. expected :: Muku result :: Miku succeeded in assert_not_equal.と別スクリプトでも使用することができた.
参考サイト
この記事は以下のサイトを参考に作成しました.
- source ~/grad_members_20f/members/musutafakemaru/8.org
- 投稿日:2020-11-25T15:41:50+09:00
JavaScript基礎まとめ③
1.オブジェクト
Javascriptにおけるオブジェクトは
大きなオブジェクトの中に、またオブジェクトがあり、その中にまたオブジェクト、
プロパティがある。例えば
let human = { men:{ name: "yamada", age : 20, } } console.log(human.men.name) ///yamadaと表示されます///ここでオブジェクト名がhuman、プロパティ名がnameになる。
プロパティを追加、今ある値を変更するときには
let human = { men:{ name: "yamada", age : 20, } } human.age = 25 /// age を変更/// human['address'] = 'Tokyo' ///addressのプロパティを追加///となる。
2.documentオブジェクト
document.getElementById("id名") document.getElementsByClassName("class名") document.querySelectorAll("セレクタ名") document.querySelector("セレクタ名")3.イベント発火
〇〇したら**するの
〇〇したら =イベント
〇〇したら**するの一連の流れをイベント発火という。イベント発火に使う関数はaddEventListenerメソッド。
要素.addEventListener('イベント名', 関数)イベント名は「クリックしたら」とか「カーソルが来たら」とか
それぞれ定義されている。〇〇したら**するの
**するもう少し深堀りすると
例えばカーソルが指定の要素に乗っているときは色が変わり、
要素から外れたときには色が戻るととかは要素.setAttribute(name, value) /// nameのvalue(値)を指定する/// 要素.removeAttribute(name, value) /// nameのvalue(値)をとりのぞく////普段使っているサイトを見ていくとJavaScriptかなり使われていそうだなと
基礎を勉強していくだけでも感じました。間違い等あればコメントお願いいたします!
- 投稿日:2020-11-25T15:37:37+09:00
assert_equal rubular
assert_equal
テスト駆動開発で進めるときに、あるプログラムの処理結果が予測された値と正しいかを確認するために用いられる。
assert_equal(expected, actual)
で書く。#!/usr/bin/env ruby # frozen_string_literal: true def assert_equal(expected, result) return expected == result end p assert_equal(1, 1 + 1)自分で作らずとも、~assert_equal~ できる
class Test::Unit::TestCase
を使うと使える。require 'test/unit' class Dummy < Test::Unit::TestCase def test_assert assert_equal(2, 1 + 1) end endcolorize
ターミナルの出力に色付けするときに使える。
'true'.green
みたいに String に対して適用する。require 'colorize' def assert_equal(expected, result) if expected == result puts 'true'.green else puts 'false'.red end end assert_equal(1, 1)Rubular
正規表現の確認ができるウェブサイトがある。
- source ~/go/src/github.com/TeamNishitani/grad_members_20f/members/iPolyomino/c9_assert_equal.org
- 投稿日:2020-11-25T14:58:53+09:00
Heroku上のRailsアプリにScoutを導入
Herokuの管理画面からアドオンを追加
ダッシュボードから操作する方法と、コマンドラインから操作する方法があります。
アドオンを追加した時点で、環境変数が自動でセットされます。ダッシュボードから操作する場合
- Herokuのダッシュボードにアクセス
- Resourcesタブを開く
- Add-onsの下の検索窓に'Scout'と入力
- Provisionをクリック
コマンドラインから操作する場合
Heroku CLIがインストールされている状態で以下のコマンドを叩く
$ heroku addons:create scout
Gemを追加
Gemfilegem 'scout_apm'$ bundle installこれだけ。