テックエキスパート5日目までを終えて一言言いたい
テックエキスパート5日目終了しました。ここまでテックエキスパートやってきましたが、諸々言いたいことがあるのでつらつら書かせていただきます。
教材が良い?何言っちゃってんの?
まずやはり教材の質については「分かりづらい」の一言に尽きると思っています。
結構長々と日本語で説明しているのですが、その日本語が分かりづらく「で、結局どういうこと?w」みたいなのがとても多いです。
なので、テックエキスパート以外のところ(Qittaやprogateなど)でちょこちょこ確認するタイミングも出てきてしまいます。
問題の難易度がおかしい
またテックエキスパートの教材内では結構な数の問題が出てくるのですが、その問題の難易度がおかしいです。笑
例えばまだ習ってもいないコードが平然と出てきたり、progateで10問くらいに分けて出されるような問題をさらっと1題の中に詰め込んできたり・・・
たしかに密度が濃くていいんですが、全問難しいので精神的ストレスがすごいですね。笑
カリキュラムの時間設定が適当すぎる
テックエキスパートでは60日間でカリキュラムを終えられるように、項目ごとに目安の時間というのがあって、それをもとに進捗を管理しています。
しかし問題なのが、1つ1つの問題の目安時間が適当すぎることです笑
例えば普通にやっていったら5時間くらいかかるカリキュラムの目安時間が2時間と書かれている一方、30分くらいで終わる問題の目安時間が2時間と書かれていたり・・なかなか酷いです。(特に前者が多い)
なので、カリキュラムを進める際には前倒しで進めていかないとRailsあたりで詰みます(目安より絶対に時間がかかる)。
これで60日で終わりますといっているのは、なかなか酷いなあと思っています。しかも週60時間で組んでいるといいつつ、ほぼ全員毎日10時間以上やっています。そうしないと終わらないからですね。
これからテックエキスパートに来ようと思っている方は「週70時間勉強」と思ってきた方が良いと思います。(まあ結構集中できるのでそこまで苦ではありません!)
あと、困ったりエラーが出たりした時にすぐにメンターに質問できるのはめちゃくちゃ助かりますね。
5日目までの備忘録
さてここからは備忘録コーナーです。めちゃくちゃ覚えることが多いので、整理するのも一苦労ですね。
redirect_toメソッドについて
redirect toはコントローラーアクション内で自動的にページを切り替える機能を持ちます。使い方に若干注意が必要かなと思っています。
アクションにリダイレクトする場合
redirect_to :action :index(アクション名)
URLにリダイレクト
redirect_to '/url/index'
redirect_to 'http://www.google.co.jp/''
before_action
コントローラーにbefore_action:メソッド名を入れることで、他のアクションが実行される前にメソッドを実行することができる。
また、before_actionを実行したくない場合はbefore_action:メソッド名, only:[:メソッド名、:メソッド名]とする。exceptも使える。
既存のテーブルにカラムを追加したい場合
$ rails g migration Addカラム名To追加先テーブル名 追加するカラム名:型
とすることで、既存のテーブルにカラムを追加することができる。例えばnameテーブルにnicknameというカラムを追加するのであれば、
$rails g migration AddNicknameToName name:string
のように記載する。このあとマイグレーションファイルをrake db:migrateする必要があるので注意
スネークケースとキャメルケース
プログラムに単語の区切りを認識させる場合スネークケースとキャメルケースがある。
キャメルケース
UserNicknameTable
スネークケース
User_nickname_table
参考記事:http://pg-kura.hatenablog.com/entry/20120118/1326892870
form_tagを使ったフォーム作成時の基本形
この基本形は忘れがちなので備忘録。なおインプットには様々なインプットタグがあるのでそれはこの後列挙する。
<% form_tag('パス', method: :HTTPメソッド名) do %>
<input type="text" name="contents">
テキストボックス系
<% end %>
form_forタグについて
form_tagと似たものにform_forタグというものがあります。これは特定のモデルを編集・追加するためのフォームを生成するヘルパーメソッドです。
※ヘルパーメソッドについては昨日の記事の中で言及しています。
form_forの基本形
<%= form_for(モデルクラスのインスタンス) do |f| %>
<% end %>
モデルクラスのインスタンスを持つので
多くの場合コントローラーでインスタンスは
定義しているはず。
def new
@user=User.new
end
<<%= form_for (@user) do |f| %>
ここに色々入る(中身)
<% end %>
モデルクラスのインスタンスはネストしている場合はその分必要
もし仮にテーブルをネストしている場合にはモデルクラスのインスタンスはその分記載する必要があります。
def new
@user=User.new
@name=Name.new
end
<<%= form_for (@user, @new) do |f| %>
ここに色々入る(中身)
<% end %>
form_forタグの中身
form_for内では「f.htmlタグ名:カラム名」で入力フォームを作る。例えばf.text_field :textみたいな感じ。
<<%= form_for (@user) do |f| %>
f.text_field :name
<% end %>
で、これはHTMLで書くとこんな感じになります。
<input id="モデル名_name" name="モデル名[name]" type="text" size="モデルで設定したsize">
送られた情報はparamsで受け取れる
例のごとく、このform_forで送られた情報もparamsで受け取ることができます。仮に以下のように情報が送られた場合を考えます。
<%= form_for(@user) do |f| %>
<%= f.text_field :name %>
<%= f.text_area :nickname %>
<% end %>
この時paramsには以下のように情報が送信されます。キーが引数(インスタンスのモデル名)になり、バリューがカラム名として入力した値になる点に注意が必要です。(つまり二重構造)
params={} →例のごとくハッシュの形
ここにこう入る
params={@user: {name:"入力値", nickname:"入力値"}}
この二重構造の値でストロングパラメーターを定義するにはrequireメソッドを使う
上記のようにparamsが二重構造となっている場合、通常のように params.permit(:name, :nickname)とはできない。なぜならparamsのキーとなっているのがインスタンスのモデル名だから。(ここで言うと@user)
そんな時に使うのがrequireメソッド。
params.require(:モデル名).permit(:カラム名)で入力した構造を取得することが可能。今回の場合だと以下になる。
params.require(:user).permit(:name, :nickname)
from_forタグの使い方まとめ
使い方をまとめると以下のイメージ。一部引用:https://qiita.com/jumpyoshim/items/ee5af466ef7959567174
def new
@review = Review.new
end
def create
Review.create(create_params)
render action: :new #表示したいビューを表示
end
private
def create_params
params.require(:review).permit(:text, :name)
end
こっからビューファイル
<%= form_for(@review) do |f| %>
<%= f.text_field :text %>
<%= f.text_area :name %>
<% end %>
form_tagとform_forどっち使うの問題
これに関しては、基本的にモデルの有無で判断する模様。モデルがある場合は特定のテーブルに何かを追加・または編集するのでform_for。
反対にモデルがない場合(例えば検索窓)などの場合は、何もモデルはなくそのままアクションに行くはずなので、そういった場合はform_tagを使う。
めちゃどうでもいいけどmaxlengthメソッド
maxlengthメソッドはtext_fieldというヘルパーメソッドに使うことのできるもの。
<%= f.text_field :text , maxlength:”5″ %>みたいな感じで使う。送信された瞬間5文字までにカットされる。
mergeメソッド
mergeメソッドは2つのハッシュを1つに統合する時に使う方法。
hash1 = {name: "1の内容"}
hash2 = {user: "ああああ", name: "いいい"}
a=hash1.merge(hash2)
→a={name1:"1の内容", :user"あああ", :name"いいいい"}
configure_permitted_parameters:deviseのお話
Railsでログイン機能を簡単に実装できるdeviseでは、ストロングパラメーター(params.permit)でメアドとパスワードのみ受け入れる設定になっているため、他のキーを送っても受け付けられない。
それを改善するのがconfigure_permitted_parameters。
設定方法はapplication_controllerでbefore_actionにconfigure_permitted_parametersメソッドを設定する。
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
end
参考記事:https://qiita.com/yoshimitsu41/items/ba5487e18278822828a3
current_user deviseのヘルパーメソッド
deviseを導入するとcurrent_userというヘルパメソッドを利用可能。これにより、現在ログイン中のユーザー情報をインスタンスとして取得可能。
※モデル名にUser以外を使用している場合、メソッドの『user』部分を書き換える必要があるので注意。→モデル名がnameならば、 current_nameになる。
このcurrent_userは仮にid1のユーザーがログインしている場合、 current_user = User.find(1)と同義。
current_user.name など current_user.カラム名でログインユーザーの情報も取得可能。
whereメソッド
whereメソッドはActiveRecordの1種で、モデル名.where(出したい条件)とすることで任意のデータベースから任意の条件を指定し、条件に当てはまるレコードをすべて取得することができる。
ちなみにこの時のインスタンス配列型で取得することになるので注意。
使い方
User.where(:name "aaa")
なおこの時SQL的には以下のような命令が走るそうです。
# SELECT "users".* FROM "users" WHERE "users"."name" = "aaa"
params[:id]でid情報が受け取れる件
例えば user= User.find_by(id:params[:id])みたいにすることで、送られてきたid番号のユーザーを求めることができます。
なぜこれができるかというとparamsにはGETリクエストのクエリなどのパラメータを取得できるという性質を持っているから。(ちなみにPOSTリクエストのデータを取得できるというのはDay3の記事で記載しました)
そしてその情報はハッシュ形式で保存されます。 params={}ですね。
で、どういう仕組みかというと
routingで以下のようなgetメソッド
get 'user/:id' => 'user#show'
この時ページにアクセスすると以下のようなurlになる
user/1.co.jpみたいな
paramsはこのgetリクエスト(つまり1を出せ)というのをハッシュの形で取得できる。
なのでこの時params={id:1}という感じにデータが保存されている。
user=User.find(id:params[:id])とすると
Userインスタンスのidがget idで求められたidのユーザーを探すという風にできる。
もう少し別の言い方をすると、
get が/user/:id というHTTPリクエストを送る。と同時にパスに含まれる:id情報は自動的にparams={}の中に格納され、コントローラーに送られる。で、コントローラーで呼び出したい場合はメソッドで 変数=params[:id]とすると呼び出すことができる。
アソシエーション
アソシエーションはモデル間(テーブル)の関連付けのこと。例えばよくあるのがuserテーブルにユーザー情報があり、記事テーブルに1つ1つの記事が入っている。
これらのテーブルは本来であればユーザー情報と記事情報(誰が書いたか)が関連付けされているべきです。
で、この間連付けを行うのがアソシエーション。
その時に重要なワードが1対多の関係。例えばユーザーテーブルのユーザー情報1に対して記事は1以上あるはずです。
その場合1(ユーザー)対記事(多)と言う風に考えることができます。
で、この状態のことをhasmanyの関係(1対多でもいいけど)と言います。この関係をアソシエーションするのです。そうすることによってテーブル間での関連付けがなされ、簡単に情報を取り出すことができるようになります。
モデルは1人1つ1つずつしかアクセスできないが、アソシエーションを組むことで複数のデータベースをまたいでデーtを取得できる
クライアント→ルーティング→コントローラーに→モデルを使いデータベースにアクセス→データをモデルから受け取りコントローラーがビューに返していく
アソシエーションのやり方
1の方のモデルファイルに has_many :〇〇(多の方のモデル名)と記載。例えば1の方がuserモデルだとすると
Userのモデルファイルに 「has_many :articles」と記載。manyなので複数形にすることに注意。
続いて多の方のモデルファイルに「belongs_to :○○(1の方の名前)」と記載。ここではbelings_to :user
以上でOKです。アソシエーションを定義するとモデルを跨いだデータの呼び出しを簡単にできます。
アソシエーションがなかったら
user=User.find(1)
Article.where(user_id :user.id)
アソシエーションがあったら
user=User.find(1)
User.articles
※この時、従属関係(多の方)にあるやつを複数形にすることに注意n+1
N+1問題
n +1問題はデータベースからデータを取り出す時に大量のSQLが実行され重くなると言うこと。
原因は例えば先ほどのuserテーブルとarticleテーブルがある場合で考えると以下のようなケースです。
<userテーブル>
・ユーザーの情報が入っている
<articleテーブル>
・articleの情報が入っているこのarticle情報をeachメソッドを使ってインデックスみたいな感じで表示する場合、SQLの流れとしては以下のような流れとなる。(ちなみにこの時、userとarticleはアソシエーションを組んでいるものとする)
SQLがeachメソッドに従い、全てのarticleを吐き出す。そのあとに1つ1つのarticleに対してユーザーテーブルからユーザー情報を取ってくる。
こんな状態です。例えるならスーパーで商品を持ってきたけど、1つ1つ価格を価格表で調べてレジを打つみたいな感じですかね。そうなると当然時間がかかるので大問題ということです。
解決策はincludesメソッド(他にもあるけど)
@article = Article.includes(:user)
このようにすることで、articleを拾ってくる際にユーザーテーブルも一緒に見てくれるのでN+1問題が起きなくなります。
テーブルからカラムを削除する方法
テーブルからカラムを消したい時ってありますよね?そんな時はターミナルで下記のように打ちましょう。
rails g migration Removeカラム名From削除元テーブル名。で、そのあとは例のごとくrake db:migrateすればOK。
patchメソッド
情報のアップデートを行う際に利用するメソッド。これと同じようなものにputメソッドというのもある。
※役割としてはブラウザからサーバーに情報を送信し、サーバー内の情報を置き換える。
HTTPメソッドのdeleteはdestroy アクションを動かす
ルーティングで delete ‘user/:id => ‘users#destroy として削除ボタンなどに設定すればdestroyメドッドが働いてdeleteできますよという話ですね。
これも:id部分はparamsで受けることができます。
destroyメソッド
ActiveRecord一つ。変数.destroyなどでレコードを削除することができる。
Day5まとめ
ということでDay5終了です。なんとなく今までの知識の点が線になりつつあり、若干楽しくなってきました。
これからもどんどん知識をアップデートしていきたいですね。