【jQuery】クリックでテーブルの行をハイライトさせる。
皆さん明けまして(だいぶ経ちますが)おめでとうございます。
本年もまったり更新していこうと思いますので、どうぞよろしくお願い致します。
さて、2019年最初の一発目は、
jQuryです!
最近「勉強してください・・・」と上司にガッカリされましたorz
今回は、クリックしたテーブルの行をハイライトさせてみました。
ポイントはハイライトなので”1行だけ”というところです。
クリックした行全ての色が変わるのを防止します。
ソースコード
今回のコードはCoffeeScriptで書いています。
(基本Railsで書いてるので...)
highlightRow: -> $('.select-row').off 'click' $('.select-row').on 'click', () -> currentTr = $(@).parents('tr') if currentTr.hasClass('selected') currentTr.removeClass('selected') else $('tbody>tr').removeClass('selected') currentTr.addClass('selected')
select-row
というクラス名のボタンをクリックすると、
その行をハイライトし、もう一度クリックすると消えます。
// ハイライト用のスタイル .selected { background-color: #f5f5f5; }
ハイライトをする行にはclass="selected"
を付け、
スタイルシートでselected
にハイライト用のスタイルを適用させます。
ハイライトのON/OFFはこのselected
の有無で切り替えます。
解説
ハイライトOFF
まずは最初からハイライトを消すところまでです。
// 読み込まれた際に一度イベントハンドラーを削除。 $('.select-row').off 'click' $('.select-row').on 'click', () -> // クリックされたselect-rowの親のtrを持ってくる。 currentTr = $(@).parents('tr') // 親のtrが既にselectedを持っていたら(ハイライト状態なら) if currentTr.hasClass('selected') // selectedを削除してハイライトを解除する。 currentTr.removeClass('selected') else // ハイライト用
今回はボタンにselect-row
をつけ、それをクリックすることでハイライトを切り替えます。
なのでスタイルを行全体につけるため、
クリックした時にまずはボタンの親要素であるtr
を取得します。
次に、取得したtr
が既にselected
を持っていたら、
そのクラスを削除します。
これでハイライトを解除します。
ハイライトON
最後にハイライトをONにする部分です。
else
以降を書きます。
. . . else // 一度全trのselectedを削除する。 $('tbody > tr').removeClass('selected') // currentTrにだけselectedを追加。(ハイライト) currentTr.addClass('selected')
currentTr
へのselected
追加だけだと、
どこかをハイライトした状態で別の行のボタンをクリックすると、
そちらの行と前にクリックした行の両方がハイライトしてしまいます。
そのため、一度全部のtr
からselected
を削除します。
改めて対象の行にselected
を追加。
これでその行だけをハイライトすることができます。
まとめ
今まで人の書いたものを真似するだけでしたが、
今回が初めて自分で考えて作る作業となりました。
最初は「全部のtr
からクラスを削除する」ことをしなかったために、
クリックした行全てがハイライトされてしまったり、
$('tbody > tr')
のセレクターの取り方をせず、
「tbody
配下のtr
を一つずすeach
で回してselected
を調べて...」
なんてjQueryの意味がない!なんてことやってました。
結局上司の助言をいただいて完成した形になりましたが、
良い勉強になりました。
今年はjQueryもいっぱい勉強することになりそうです。
皆さま、本年もどうぞご教授のほど、宜しくお願い致します。
【Git】コマンド: いい加減覚えが悪いのでまとめとく。
こんにちは、マリンです。
7月から今の職場でお世話になり始め、はや5ヶ月経ちます。
・・・が、いつも使ってるGitコマンドを全然覚えなくていい加減上司にブチ切れられそうなので、
理解も兼ねてまとめておきます・・・orz
git fetch
ローカルの環境を最新の状態にします。
と言ってもこの時点では作業中のファイルが更新されるわけではありません。
更新されるのは、ローカルにあるorigin/master
です。
リモートにあるmaster
を参照して、ローカルのorigin/master
を更新します。
originとmaster
二つは別物で、両方ともローカルにあるブランチです。
(masterはリモートにもあるブランチですが、リアルタイムで連携してるわけではないです)
origin/master
リモートの状況を追跡するためのブランチ
origin
という名前のリモートの、master
ブランチを追跡していますよ。git fetch
することでこのブランチが最新になる。(連携は手動で。)
master
ただの作業ブランチ(語弊がある??)
issue~
やcreate-user
とか、そんな感じと一緒。git fetch
しただけでは変更されない。
originとmasterについてはこちらの記事がオススメです。
gitのふわっとした知識を調査してみたnekosoftware.wordpress.com
git checkout ブランチ名
対象のブランチに切り替えます。
もしそのブランチがローカルにない場合には、新規に作成して切り替えます。
そして新しいブランチで作業を始める際、
いつもこれとfetch
を組み合わせて使っています。
$git fetch && git checkout ブランチ名
git tr --all
正確には
$git tree --all
です。
最新までのgitのツリー状況を見ることができます。
git merge origin/ブランチ名
先にgit fetch
を出しましたが、あれだけでは作業ディレクトリは最新になりません。
merge
をすることで、初めて現ブランチを最新にできます。
現在いるブランチを指定したブランチの状態に上書きします。
(上書きという表現が正しいか分かりませんが、私は一番しっくりきました。)
ブランチを最新にする一連の流れ
$git fetch $git tr --all $git merge origin/ブランチ名
fetch
でローカルのツリーを最新にtr
でマージするブランチを確認merge
で現在のブランチを最新にする
git pull
職場では使っていませんが、
前述のブランチを最新にする一連の流れをまとめたコマンドです。
手間は省けますが、やはり一つずつ確認してからのが安心な気がします。
git diff
差分を確認するコマンドです。
確認対象は様々に指定できますが、指定がない場合は
インデックス(add後commit前のもの)と作業ディレクトリとの差分を表示します。
それぞれの指定方法はこちらが分かりやすかったです。
まとめ
今回はこんな感じでしょうか。
いつも迷うものをあげたので、commit
とかpush
とかは出していません。
多分コマンド自体の意味より、
origin
とかmaster
とかがよくわかっていなかったから、
これをするとどこに何が反映される?という点でこんがらがっていたんだと思います。
まだ怪しい気がするので、もし間違いがありましたらぜひご指摘ください。
よろしくお願い致します。
【Rails】$rake db:rollbackしたい時の間違えない手順
こんにちは、マリンです。
未だ初心者の域を脱しない私は、よくmigration
周りでやらかします。
一人でやっていた頃は失敗すると
「ロールバックしちゃえ〜」「migrationファイル消しちゃえ〜」
とかやっていましたが、
チームでやっているとそんな横暴は許されません・・・
今回丁度勉強で作っていたサンプルで失敗したので、
ロールバックの正しいやり方?を学びました。
migration周りの注意
そもそもなぜこのあたり注意しなきゃいけないのか?
今更気づいたので一応書いておきます。
migrationファイルを書き換えたり削除した場合、
当然次回$rake db:migrate
した時にテーブル構造が変わってきます。
一人でやっている分には大して支障はないですが、
これをチームでやっているリモートリポジトリなんかにあげちゃったりすると・・・
それをマージした他の方の環境まで変わってしまい、
最悪「コードの辻褄が合わない!」なんてことになりかねません。
ということで、この辺のファイルがどれほど恐ろしいものか気づいた私は、
今後は普段から取り扱いに注意する癖をつけようと肝に銘じました。
rollbackの手順
さて本題です。前述の通りこの辺は取り扱い注意なので、
失敗しない手順を学びました。
現在の状況を確認する
まずはどこまでmigrate
が実行されているかを確認しましょう。
$rake db:version
このコマンドで確認できます。
$ rails db:version Current version: 20171112122350
こんな感じで出てきます。
20171112122350まで実行されていますね。
ロールバック
次に戻したいところまでロールバックします。
[一つ前まで戻す]
$rake db:rollback
[任意のファイルまで戻す]
$rake db:rollback STEP=○
現在地を含めた○個前までなかったことにしてくれます。
(つまり○+1個前のファイルまで実行された状態)
migrateされていないファイルを確認
念のためどのファイルが実行されていないか確認します。
$rake db:abort_if_pending_migrations You have 1 pending migrations: 20171112131249 CreateUsers
20171112131249のUserテーブルが作られていないようです。
ファイルを修正
class CreateUsers < ActiveRecord::Migration[5.1] def change create_table :users do |t| t.references :comment, index: true, foreign_key: true # null: falseを削除 t.string :name t.string :email t.timestamps end end end
今回はCommentテーブルにレコードが何も入っていない状態で
NOT NULLにしてしまったため失敗したので、
null: false
を削除します。
migrate
修正が完了したらマイグレートを実行します。
$rake db:migrate == 20171112131249 CreateUsers: migrating =============================== -- create_table(:users) -> 0.0026s == 20171112131249 CreateUsers: migrated (0.0027s) ========================
これで無事修正完了です。
こちら参考にさせていただきました。
追記
1ヶ所$rails db:version
と書いてしまいましたが、
Rails5の場合これでもいけます。
Rails4以前の場合は$rake
でお願いします。
【Rails】select_tagを使って表示内容を変える
こんにちは、マリンです。
今回はselect_tag
を使ってページの表示内容を変える方法を書こうと思います。
概要
select_tag
で項目を選択し、項目に合わせてページの内容を変える
この時、
- HTTPリクエストはGET
- 「項目.id」を使って関連付けされた「内容」を持ってくる
submit
ボタンなしで切り替えを実現
こんな感じです。
なお、今回はクラスを選択すると生徒一覧が出てくる感じにしようと思います。
View
まずはviews
から。
<%= form_tag classes_path, method: :get do %> <%= select_tag 'classes', options_for_select(class_choices, @class_id), id: 'classes' %> <% end %> <% @students.each do |student| %> <%= student.name %> <% end %> <script> this.class_names.select(); </script>
前3行がセレクトで、中3行が生徒一覧を表示する部分、後3行がJSの呼び出しです。
JSについては最後に記述します。
セレクト部分
<%= form_tag classes_path, method: :get do %> <% end %>
コントローラにselect_tag
の情報を送るためにform_tag
で囲みます。
新規作成とかのページではないのでget
のアクションを使っています。
そのためmethod: :get
を指定してください。
<%= select_tag 'class_id', options_for_select(class_choices, @class_id), id: 'classes' %>
第一引数のclass_id
は、後ほどコントローラにこのセレクトタグの情報を渡す時に使う名前です。
第二引数には選択肢の文字列を指定しますが、
今回はoptions_for_select
を使っています。
このメソッドは、配列などを使って選択肢を生成してくれるメソッドです。
この引数には、helper
にクラス名とid
をとってくるメソッドを定義し、
それを使うことにします。
def class_choices ClassName.all.map{|class_name| [class_name.name, class_name.id]} end
@class_id
は、デフォルトでは選択後に表示名が最初に戻ってしまうので、
それを選んだ項目そそのまま表示させるためのものです。
こちらはコントローラに定義します。
id: 'classes'
は、後ほどJavaScriptに書く、
項目を選択するだけでデータを送れるようにするための処理で使います。
生徒表示一覧部分
<% @students.each do |student| %> <%= student.name %> <% end %>
対して説明はいらないと思いますが、
コントローラで@students
を定義し、
それを元に生徒の名前を羅列しています。
Controllers
次はControllers
です。
def classes # select_tagのデフォルト値に使用 class_first = ClassName.find(1) # select_tagから現在選択されているクラスのid取得 # 未選択時はデフォルトのclass_first @class_id = params[class_id] || class_first # クラスに属する生徒を取得 @students = Student.where(class_id: @class_id) end
@class_id
は未選択時にデフォルトで何を入れるか明示してあげないと、
「IDないんですけど?」と怒られてしまうのできちんと指定してあげましょう。
このid
をセットするところで、select_tag
に付けた名前が使われます。
「viewにあるclass_id
って名前のとこの値をとってきてね。」
という感じです。
最後に、とってきたクラスのid
を元に
関連付けられた生徒の名前を取得し、
これを使って表示をします。
JavaScripts
最後にプラスαで、サブミットボタンを付けなくても中身が切り替わるよう、
coffeeファイルを記述します。
これがないと、いちいちボタンを作って、それを押さないと切り替わりません。
class ClassNamesController select: -> $('#classes).on 'change' () -> $(@).parents('form').submit() return this.class_names = new ClassNamesController
言わずと知れたCoffeeScriptです。
コンストラクタ呼び出しを使っています。(new~
の部分)
これの呼び出しが、最初のviews
に記述した
<script> this.class_names.select(); <script>
です。こうやってメソッドを呼び出すことができるようになるんですね。
ここの部分はいまいち理解仕切れていないので、
参考にさせていただいた記事をご紹介するに留めておきます。
関数の中身です。
$('#classes').on 'change' () -> $(@).parents('form').submit()
「id="classes"
が変更されたら
これ(@=this)の親のform
を送信する。」
という内容ですね。
JS系は完全に勉強不足なので、自滅する前にここでやめておきます。
まとめ
今までselect_tag
はform
の一部としてしか使ったことがなかったですが、
このような使い方もよく見かけるのでとても良い勉強になりました。
ユーザービリティなども考えると、このJSのコードもいろいろなケースで
使えそうだなと思います。
余談ですが、今回この記事を書くにあたって自分でサンプルを作ってやってみましたが、
仕事と同じようにやってもやはりうまくいかずそれでまた一つ勉強できたりしたので、
手を動かすことの大切さを改めて実感しました。
【CSS】セレクタの指定方法まとめ
こんにちは、マリンです。
今更ながらセレクタの指定方法の認識が曖昧だったことに気づいたので、
忘れないうちにまとめておくことにしました。
こちらを参考にさせていただきました。
基本
ユニバーサルセレクタ
ページ内の全ての要素を指定するセレクタ。
* { }
タイプセレクタ
ページ内の要素を指定するセレクタ。
body
やul
、p
などのタグ。
要素名 { }
IDセレクタ
/* 全ての指定ID属性 */ #属性値 { } /* 指定要素下のID属性 */ 要素名#属性値 { }
Classセレクタ
/* 全ての指定class属性 */ .属性値 { } /* 指定要素下のclass属性 */ 要素名.属性値 { }
複数セレクタ
セレクタ1, セレクタ2, セレクタ3, ... { }
応用
子供セレクタ
親子関係の子要素を指定する場合。
親要素 > 子要素 { }
子孫セレクタ
子要素、孫要素などの子孫要素を指定する場合。
/* 半角スペース区切り */ 親要素 子孫要素 { }
隣接(兄弟)セレクタ
隣接要素と対象要素が直接隣接している時に指定する場合。
両方とも同一親要素の子にあたり、
先の要素が「兄」、次が「弟」になるため、
隣接兄弟セレクタとも言う。
隣接要素 + 対象要素
属性セレクタ
属性や属性値を特定して要素を指定する場合のあれこれ。(idやclassも含まれる)
属性を指定する
/* 指定属性が設定されている要素 */ 要素名[属性名] { } p[title] { }
指定属性に特定の値が設定されている要素
要素名[属性名="値"] { } p[id="main"] { }
属性の値に指定の値が設定されている要素
「class属性の値に"main"が含まれているdiv要素」のように指定したい時。
要素名[属性名~="値"] { } div[class~="main"] { }
属性値が一致する要素
「lang属性の値で"en"と一致、または"en-~"で始まるものと一致するもの」のように指定したい時。
要素名[属性名|= "値"] { } /* 全体でlang属性の値が"en"または"en-~"のもの*/ *[lang|="en"] { }
指定の属性に特定の値が全て設定されているもの
「class属性の値に"foo"と"bar"の両方が設定されているもの」のように指定したい時。
属性値属性値 { } /* classにcontentsとmainが両方あるもの */ .contents.main { }
【Rails】paramsがなんなのかやっとわかった!
こんにちは、マリンです。
Railsでform
とか使っていれば当然params
って出てきますよね。
恥ずかしながら、このparams
の認識が違っていたために職場でかなり苦労しました。
やっと見えてきたのでまとめようと思います。
*内容に間違いや補足などございましたら、是非ともご指摘ください!
paramsとは?
params
メソッドとは、URLから送られてくる情報を受け取るメソッドです。
初っ端ですが、私の認識はここが間違っていました。
DBのレコードが持つ情報やカラムに紐付いた情報を表していると思っていました。
なんでこんな誤解が生まれたかはちょっと謎ですが・・・
まぁ、教材を流し読みしたせいだと思います。
とにかく、param
はURLからの情報を受け取るメソッド。
このことがわかれば、これまで職場で???となっていた全ての現象の辻褄が合いました。
paramsで受け取れるもの
formの値
まずは言わずと知れたform
から送られてくる値ですね。
<%= form_for @user do |f| %> <%= f.text_field :name %> <% end %>
@user = User.find_by(name: params[:name])
form_for
で入力された:name
を元にユーザーを探し出してます。
ここまでは良かったのですが、これがform_tag
に成った時に一気に躓きました。
<%= form_tag hoge_hoge_path do %> <%= password_field_tag 'password_text', ' ' %> <% end %>
@password = params[:password_text]
ただ入力されたパスワードを変数に入れてるだけなんですけど、
私はparams
で扱えるのがDBのカラムにあるものだけだと思っていたので、
ここで混乱するわけですね。
「password_textなんてカラムないけど!?」と。
なんともお恥ずかしい話です。
何はともあれ、URLからの値を受け取るので当然このように使用することが可能です。
クエリパラメータ
クエリパラメータとはURLに付け加えられたページの情報です。
http://hogehoge/hugahuga/hello?name=marin
この?
以降がクエリパラメータです。
params
ではこの値も受け取ることができます。
この場合はlink_to
からの値ということになると思います。
<%= link_to "marin", hogehoge_hugahuga_path(name: 'marin')
@user = User.find_by(name: params[:name])
こんな感じでしょうか。
番外 〜ストロングパラメータ〜
なんか悪い人からの攻撃に対応するために扱う値を制限するってやつですね。
チュートリアルとかでもやってるんですが、多分ここが私の誤解の原点ではないかと思います。
params.require(:user).permit(:id, :name, :email)
こんな感じのやつですね。
users
テーブルのid``name``email
は扱えますよと言っています。
(多分ここでテーブルに関連する値しかparams
は使えないと勘違いしたのではと)
大体の場合は
def hugahuga @user = params(user_params) end private def user_params params.require(:user).permit(:id, :name, :email) end
という感じで使うのではないでしょうか?
まとめ
そういえば、form
ではhidden_field
なんてのに渡した値を取得する場面もありました。
自分のどこが理解できていなかったのか?何を間違えているのか?
それがわかれば本当はもっと簡単にコードが読めるのかもしれません。。。
わからない時には一度立ち止まって、
つまづいている部分がどこなのかを見極めるのも大事ですね。
【Rails】なんか変なとこのヘルパー読み込んでるんだけど??〜config.action_controller.include_all_helpers〜
こんにちは、マリンです。
昨日こんなことがありました。
「staffのネームスペースでuserのhelper読み込んでるんです・・・」
その時に教えていただいた対処法をご紹介します。
概要
app/helpers/user/pages_helper.rbに
hoge
と言うメソッドがあった。同じ処理を行いたいのでapp/helpers/staff/pages_helper.rbにも
hoge
と言うメソッドを書いた。app/controllers/staff/staffs_controller.rbからネームスペースstaffの
hoge
を呼び出した。(つもり)なぜかネームスペースuserの
hoge
が呼ばれてしまう!?
こういった経緯で自己解決できずに相談しました。
原因
Railsのcontrollerでは、デフォルトで全部のhelperを読み込むようになっているそうです。
なので意図しないファイルを読み込んでいる場合は、
キチンとネームスペース内のものだけを読み込むように設定しないといけないとのこと。
対処方法
config/application.rbファイルに以下を記述します。
config.action_controller.include_all_helpers = false
これはデフォルトで全てのヘルパーを読み込むようになっているのを、
「やめて〜〜!!」
と言っています。
これでネームスペースに則ったヘルパーのみを読み込んでくれるようになるということです。
基礎を勉強するだけではわからないこと、
気付けなかったこと、ぶち当たらなかった壁をたくさん経験できて、
やはり一歩踏み出して良かったな。
と感じる今日この頃です。