はてなブログでMarkdownで目次が作りたい!

ということで、Qiitaとかみてると目次ってかっこいいなと、思うわけですよ。なので、今回は目次について調べて、実際に使ってみようと思います!

はてなブログを参考に

まず、目次を挿入したい行に[:contents]と記入をする。

[:contents]

その下に見出しをつけてやればできるらしい。

できてる。

#の数で入る場所が変わるぜ

面白い。

参考

staff.hatenablog.com

buildメソッドって?

インスタンスを生成するメソッド。モデルの関連付けでも用いられる。 newメソッドと同じ使い方をするが、モデルの関連付けの際には、暗黙のルールとしてbuildメソッドを使う。

buildの記述方法

全部で3パターン。モデルの同士の関連付けで変わってくる。 1. アソシエーションが1対1 2. アソシエーションが1対多 3. アソシエーションが多対多

1対1の場合

ユーザーが予定を1つ持っている場合として、

class User < ActiveRecord::Base
  has_one :plan
end
class Plan < ActiveRecord::Base
  belongs_to :user
end

このような1対1関係では、build_関連付けのメソッド名となります。

@user = User.new
@plan = @user.build_plan

1対多の場合

ユーザーが予定を複数持っている場合として、

class User < ActiveRecord::Base
  has_many :plans
end
class Plan < ActiveRecord::Base
  belongs_to :user
end

このような1対多関係では、関連付けのメソッド名.buildとなります。

@user = User.new
@plan = @user.plans.build

多対多の場合

多対多の場合中間テーブルを作るため、以下のようにモデルを作成します。

class User < ApplicationRecord
  has_many :group_users
  has_many :groups, through: :group_users
end
class Group < ApplicationRecord
  has_many :group_users
  has_many :users, through: :group_users
end
class GroupUser < ApplicationRecord
  belongs_to :group
  belongs_to :user
end

このような多対多関係では、1対多と同様に関連付けのメソッド名.buildとなります。

@user = User.new
@group = @user.groups.build

buildでも場合分けするので覚えなければ!

参考

techtechmedia.com

form_withって難しい(n回目)

form_withっていろいろな情報があって、何が何やらさっぱりなので、少しまとめて行きたいと思います。たくさん参考にしながらやっていきます。

form_tagとform_for

まず、form_withは第一引数にmodel:かurl:を使います。この使い分けは、

<%= form_with url: "パス" do |form| %>
  フォーム内容
<% end %>
<%= form_with model: モデルクラスのインスタンス do |form| %>
  フォーム内容
<% end %>

なぜ、この2つに分けられているのかというと、もともとform_withform_tagform_forが使われていました。form_tagは保存する必要がない時、form_forは保存する必要があるときに使います。

<%= form_tag('/main', method: :post) do %> 
  <input type="text" name="nickname"> 
  <input type="submit"> 
<% end %>
<%= form_for(@user) do |f| %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>

form_tagform_forで書き方が異なることが分かります。form_forでは、FormBuilderオブジェクトのヘルパーメソッドを使っています。FormBuilderオブジェクトとは、上の例だとform_forというヘルパーメソッドの引数である@userの情報を持っている「f」です。フォームを作るときに便利なヘルパーメソッドを使うことができます。form_forによって作られるオブジェクトということなのかな?text_fieldやsubmitなど便利なヘルパーメソッドを使えます。

form_withとは

form_tagform_forくっつけたらもっと簡単なのになー。モデルでもパスでもどっちも使えたらなー。ということで、form_withが誕生したらしいです。 使い方をもう一度

<%= form_with model: @user do |form| %>
  フォーム内容
<% end %>
<%= form_with url: root_path do |form| %>
  フォーム内容
<% end %>

form_withでmodelオプションを使う場合は、引数にモデルクラスのインスタンスを指定します。モデルクラスのインスタンスとは、保存したいテーブルのクラスのインスタンスのことをいうそうです。よく分かりません。 進めます。usersテーブルに新たにレコードを作成したいので、コントローラーに

def new
  @user = User.new
end

と記述します。この@userがform_withの引数に指定されるのです。@userが新規に作成された場合(@userになんの情報も入っていない)には、createアクションへ、@userにすでに情報が入っている場合にはeditアクションへ自動的にform_withが振り分けてくれます。

参考

https://pikawaka.com/rails/form_with https://qiita.com/kenkentarou/items/f6b2f033d8b14056ec81

部分テンプレートをrenderするときのcollectionってなに?

部分テンプレートをレンダリングするときに、ローカル変数を渡す時があるけれど、何種類も渡し方があるので、その中に出てくるcollectionについて考えていきます。

前提として、postコントローラー、postモデルが存在し、

def index
  @posts = Post.all
end
<%= post.title %>
<%= post.body %>

とします。

collectionの使い方

まず、collectionをつかわずに、eachを使って繰り返しレンダリングさせると、

<% @posts.each do |post| %>
  <%= render 'post', post: post %>
<% end %>

と表現できます。しかしこれでは毎回レンダリングをするため、負荷がかかってしまいます。 collectionを使うと、

<%= render partial: 'post', collection: @posts %>

と書くことで、内部で要素1つずつを取り出して処理をしてくれるため、何度もレンダリングをしません。負荷がかからないし、早い。また、部分テンプレートに渡る変数名は、partialで指定した値(post)になるので注意が必要。

collectionの省略記法

<%= render @posts %>

とかなり省略して書くことができるが、これが成立するためにはいくつかの決まりがある。

  1. 部分テンプレートが呼び出し元のテンプレートと同じディレクトリ内にある
  2. 部分テンプレートのファイル名がオプションで指定した変数の単数形である
  3. 部分テンプレート内で使用する変数名が、オプションで指定した変数の単数形である

今回でいうと、1は、呼び出し元のindex.html.erbと部分テンプレートの_post.html.erb同じディレクトリ内にあることが必要。2は、オプションで指定した変数名が@postsなので、部分テンプレートは単数形の_post.html.erbであることが必要。3は、オプションで@postsを渡しているので、部分テンプレート内で使用する変数名は、postであることが必要。 上記3つが守られていればかなり短いコードが書ける。

参考 https://b1840943.hatenablog.jp/entry/2018/05/24/221420 https://himakuro.com/rails-render-collection

作成日時を表示しよう!

掲示板の作成日時を制作します。 何も設定を変えずにcreated_atの時間を見ると、UTC(世界標準時)で出てきてしまいます。そのため、いくつか変更や設定をすることがあるので観ていきます。

タイムゾーンの変更

最初にタイムゾーンを日本時間に設定します。

class Application < Rails::Application
  config.time_zone = 'Asia/Tokyo'   # タイムゾーンを日本時間に設定
end

UTCから変更することができましたが、まだまだ進めます。

読みやすいフォーマットへ

日本人の読みやすいフォーマットに変更していきます。 Railsを使っているため、便利に使えるlメソッドを使っていきます。 使い方は、

<%= l board.created_at %>

のように、lを使いたいところの前に置くだけですが、これだけではなんの変化もありません。次に何をするのか。

ロケールの設定

まずは、日本人が読みやすい書式にするため、アプリケーションのロケール:jaに変更します。

ロケールとは、あるネイティブ言語環境の明示的なモデルおよび定義のことです。ロケールの概念は、http://opengroup.org からアクセスできる POSIX 規格に明示的に定義されて含まれています。

class Application < Rails::Application
  config.i18n.default_locale = :ja    # ロケールを日本に設定
end

次に、config/locales/ja.ymlというファイルを作り、

ja:
  time:
    formats:
      default: "%Y/%m/%d %H:%M:%S"

とすることで、日本人向けの書式で日時が表示されます。 さらに、表示するものを短くすることも可能です。

ja:
  time:
    formats:
      default: "%Y/%m/%d %H:%M:%S"
      short: "%m/%d %H:%M"

と、して、

<%= l board.created_at, format: :short %>

としてあげると、月日時分だけの短いものを表示させることも可能です。

参考

https://qiita.com/jnchito/items/831654253fb8a958ec25

present?メソッドとは

present?メソッドとは

present?とは、真偽判定をしてくれるメソッドの1つで、オブジェクトに値が入っていれば真、入っていなければ偽を返してくれます。

その他のメソッドとの違い。

メソッド メソッドの意味
nil? 変数の値がnilまたは値なしで真
empty? 変数の値が空白("")の場合、真
blank? nil?,empty?が真の時、真
present? blank?が偽の時、真

present?の使い方

Rubyでは、nil?とempty?しか標準で使えないが、blank?とpresent?はRailsに搭載されているためRailsでの環境下ではそのまま使用することができる。 * 使い方例

num1 = 10
num2 = ""
num3 = true
num4 = false

num1.present?    # => true
num2.present?    # => false
num3.present?    # => true
num4.present?    # => false

他にも配列やハッシュの判定も行える。

arr = Array["dog", "cat", "rabit", "", "cow", ""]
 
for var in arr do    # varにarrの要素を順に入れるfor文
  p var.present?
end

結果は、

true
true
true
false
true
false

となる。また、これはif文の中でも使うことができる。

arr = Array["dog", "cat", "rabit", "", "cow", ""]

for var in arr do
  if var.present?
    puts var
  else
    puts "値は空です"
  end
end

結果は

dog
cat
rabit
値は空です
cow
値は空です

となります。

参考

https://www.sejuku.net/blog/66030

Post.all.includes(:user).order(created_at: :desc)

includesメソッドとは?

このメソッドはモデル同士の関連付けを事前に取得してN+1問題を解決してくれるメソッド。指定された関連付けが最小限のクエリ回数で読み込まれるようになる。

N+1問題って?

ループ処理の中で、その都度SQLを発行してしまい、大量のSQLが発行されてしまい、パフォーマンスが低下してしまう問題。買い物をするときに商品を1つずつお会計しているようなもの。非常に効率が悪い。 例えば、投稿者(user)と投稿(post)が関連付けられているとします。postは複数あって、userに従属しているので、 userモデル

class User < ApplicationRecord
  has_many :posts
end

postモデル

class Post < ApplicationRecord
  belongs_to :user
end

とそれぞれのモデルに記述します。 次に、各投稿者が投稿したものを出力するプログラムを作成します。

User.all.each do |u|
  post_names = u.posts.pluck(:name).join(",")  # pluckはテーブルから欲しいcolumnだけを情報として取ってくる。
  p "#{u.name}が投稿したのは#{post_names}です。"
end

として、これを実行すると、1回目のSQLでUserのデータを全て取り出したあと、Userのレコード1つ1つをuに代入して、postsテーブルにアクセスしてデータを取り出すため、Userのデータの数分の処理を行うことになります。usersテーブル1回に対して、postsテーブルへのアクセスがN回。これがN+1問題です。 これを解決するためにincludesメソッドを使います。

includesメソッドの使い方

includesメソッドの定義ですが、

モデル名.includes(:関連名)

と書きます。ここでいうと、モデル名がUser、関連名がpostsになります。 ここの関連名はhas_many :postsと書いた:postsになります。

User.all.includes(:posts)

とすると、全ユーザーが持っている投稿を全て、N回もSQLを発行することなく出すことができる。

それでは、タイトルのPost.all.includes(:user).order(created_at: :desc)を考えていきます。 Post.allなので、Postテーブルから全データを持ってきて、その際に付属しているuserも持ってきています。さらに、orderメソッドで並び替えをしています。その基準が作成日時を降順で、というふうになるということです。

参考

https://note.com/kentarotawara/n/nf8b27ba0e5d3 https://pikawaka.com/rails/includes https://qiita.com/massaaaaan/items/4eb770f20e636f7a1361