新米パパの育児留学

読者です 読者をやめる 読者になる 読者になる

新米パパの育児留学

『育児留学』とは、育児を通して異なる視点を得たり新しいことに挑戦して自己成長に繋げること。育児奮闘中の新米パパが育児を通して得た気づきや感じたこと、育休中に習得したプログラミングに関する話題を発信していきます。

0歳児の赤ちゃんと初めての旅行体験記 授乳、交通手段、宿、持ち物のおすすめ

育児留学 育児留学-育児奮闘記

こんにちは!育休中新米パパのmochikichiです。

先日、 0歳4か月の息子と妻と3人で初めて東京へ旅行をしてきました。

生後、関西から出たことがなかったので、東京訪問は初の遠出だけど大丈夫かなぁ...と、ドキドキでしたがいろいろと準備したのもあって無事に楽しい旅となりました。

赤ちゃんと一緒に遠方へ出かける際に気を付けておきたいことを実体験を元にまとめてみました。

赤ちゃん_遠征_注意点

 

訪問目的

・転職候補先のオフィス視察

・転居予定場所のエリア、物件視察

・託児付きコワーキングスペース体験

 

スケジュール

スケジューリングのポイント

・授乳、おむつ交換のタイミングと場所を常に想定する

 授乳とおむつ交換はいつでもどこでもできる訳ではないので、事前に念入りに調査と計画を実施しました。

 

・スケジュールには余裕を持ちましょう 

 赤ちゃんと一緒だと、普段よりも歩くスピードがゆっくりになったり、ベビーカーで行くとエレベーターが思いの外遠かったりと予想以上に時間がかかる場合があります。余裕を持ったスケジュールを立てたつもりでしたが、途中でうんちをしておむつ交換したりするとバタバタと慌てるのでもっと時間には余裕を持った方が良かったなと思いました。

実際のスケジュール

1日目

8:00 授乳@自宅

8:30~14:30 関西⇒東京移動(電車+ぷらっとこだま)(11:30 授乳@新幹線

14:30 ホテル荷物預け、授乳@ホテル

15:00~18:00 物件視察

18:30 お風呂

19:00 授乳@ホテル、こども就寝

(21:30,1:30,5:00 授乳@ホテル

2日目

8:00 こども起床、授乳@ホテル

9:00~11:00 吉祥寺エリア視察

11:30~16:30 託児付きコワーキングスペース体験(11:30,15:00 授乳@コワーキングスペース

18:30 お風呂

19:00 授乳@ホテル、こども就寝

(21:30,1:30,5:00 授乳@ホテル

3日目

7:30 こども起床、授乳@ホテル

8:00~9:30 清澄白河モーニングコーヒー、おさんぽ

9:30~10:30 居住エリア視察

10:30 授乳@ホテル

11:00~12:00 オフィス視察

13:00~18:00 東京⇒関西移動(ぷらっとこだま+電車)(15:00 授乳@新幹線

18:30 お風呂

19:00 授乳@自宅、こども就寝

交通手段

飛行機、新幹線、自家用車など様々ですが、授乳とおむつ交換をどうするかが重要です。

今回は、低価格かつ比較的混雑しない「ぷらっとこだま」を選択しました。

ぷらっとこだま|JR東海ツアーズ

ぷらっとこだまの注意点

授乳

多目的室を授乳室として利用できます。ただし、多目的室は普段はカギがかかっており利用できません。乗務員に授乳したいと伝えると開けてくれます。

今回はあまり混雑していなかったのですぐに使えましたが、多目的室はぷらっとこだまに1室しかないので先に授乳中の方がいたり、体調が悪くなった人が休憩するスペースとして利用するなど名前の通り多目的に利用され、利用できない可能性もあるので、念のため授乳ケープを持参しておいた方が良いでしょう。

おむつ交換

おむつ交換台は上記の多目的室または多目的トイレに設置されているため安心です。しかし、こちらも混雑時は他の方とラップする可能性があるので早め早めの対応を心掛けた方が良いでしょう

服装

3月下旬でまだ外は寒かったので温かい服装をしていましたが、車内は暑かったため、途中で服を脱がせて薄着に着替えさせました。すぐに体温調整できるように脱ぎ着しやすい服装が良いでしょう。

おもちゃ 

寝ている間は問題ないですが、起きていて長時間座っていると飽きてきて機嫌が悪くなり泣き出しました。その時にお気に入りのおもちゃであやしてあげるとゴキゲンになりました。それでもダメな時は、デッキに出て気分転換も効果的でした。

宿

赤ちゃんにとって快適な場所を選びましょう。

ファミリー向けのホテルを選ぶと広くて使いやすいのですが、どうしても値段が高くなってしまうので、TripAdvisor (トリップアドバイザー) の口コミを元にビジネスホテルを探しました。

今回利用したホテルはこちら。すごくよかったです。

「ホテルマイステイズ浅草橋」

アクセス

移動に便利な駅近くがいいなと思い、駅から徒歩5分圏内で探しました。飲み屋街など騒がしい場所は避けました。慣れない土地での移動は予想以上に疲れてしまったので、今回利用したホテルは駅から徒歩1分でかなり助かりました。

設備

ベッド

赤ちゃんもできるだけ普段の睡眠と似た環境が安心できると思います。私たちは普段から"クイーンサイズのベッド"で3人で川の字になって寝ているので"クイーンサイズのベッド"があるホテルを選びました。

赤ちゃん_ホテル_クイーン

おふろ

調査時にはあまり意識していませんでしたが、よくあるビジネスホテルの狭いユニットバスではなく、身体を洗う広いスペースがあり、こどもと一緒におふろに入るのがすごく快適でした。ビジネスホテルでも、クイーンなど大きめの部屋にするとおふろの洗い場も広い部屋があるかもしれません。 

持ち物リスト

今回の旅で持参したものを紹介します。

・おむつ 12枚×3日=36枚 

 ⇒不安だったので多めに持って行きました。6枚くらい余りましたが多めに持って行って正解でした。

・おしりふきシート 1袋

・おむつ交換用シート

・使用済みおむつ用ごみ袋 10枚

 ⇒移動中などのおむつ処理は臭いが困るので、以下の臭いが気にならない防臭袋を持っていくと臭いが全然気にならず重宝しました。

【驚異の防臭袋 BOS(ボス)Sサイズ大容量200枚入り 赤ちゃん用おむつ処理袋】

・ハイター、洗剤(小分け)

 ⇒うんち漏れで服が汚れた時用に持っていきました。実際に漏れて汚れたので持って行って良かった。。。

・服 5枚

・肌着 5セット

・パッチ 1枚(寒いとき用)

・靴下 3セット

・ガーゼ 5枚

・スタイ 5枚

・バスチェアー

 ⇒ポンプ内臓で空気で膨らませられるバスチェアーを持っていきました。空気を抜くとかさばらないので便利です。

【リッチェル ふかふかベビーチェア(エアーポンプ内蔵)】

・バスタオル

⇒ベッドで寝かす時に使用しました。

・せっけん

・帽子

・抱っこひも

・授乳ケープ

母子手帳

・保険証

・おもちゃ

⇒息子のお気に入りの「オーボール」を持っていきました。これで遊ぶとゴキゲンなのでかなり助かりました。

【オーボール ベーシック】

まとめ

いろいろと心配になりますが、備えあれば患いなし!

みなさんも事前にシミュレーションをしてかわいい赤ちゃんと一緒にステキな旅をお楽しみください。

Ruby on Rails いいね(like)機能拡張 (railsチュートリアル)

プログラミング プログラミング-Rails_チュートリアル

目的

Ruby on Rails チュートリアル 5.0(第4版)で実装したサンプルアプリケーション(+検索機能拡張版)を元に、いいね機能を拡張します。

完成版アプリケーション

実際に検索機能を拡張したアプリケーションを見てみたい方はこちら。

https://fathomless-shore-36670.herokuapp.com/about

開発環境

Rails 5.0

・cloud9

実装

最終的なソースコードと確認画面

[View]

[microposts/_micropost.html.erb]

<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content">
    <%= micropost.content %>
    <%= image_tag micropost.picture.url if micropost.picture? %>    
  </span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
    <% if current_user?(micropost.user) %>
      <%= link_to "delete", micropost, method: :delete,data: { confirm: "You sure?" } %>
    <% end %>
  </span>
  <!--like拡張機能-->
  <%= render partial: 'likes/like', locals: { micropost: micropost, likes: @likes } %>
</li>

[likes/_like.html.erb]

<% if micropost.like_user(current_user.id) %>
  <%= button_to micropost_like_path(likes, micropost_id: micropost.id), method: :delete, id: "like-button", remote: true do %> 
    <%= image_tag("icon_red_heart.png") %>
    <span>
      <%= micropost.likes_count %>
    </span>
  <% end %>
<% else %>
  <%= button_to micropost_likes_path(micropost),id: "like-button", remote: true do %>  
    <%= image_tag("icon_heart.png") %>
    <span>
      <%= micropost.likes_count %>
    </span>
  <% end %>
<% end %>

[Controller]

[users_controller.rb]

class UsersController < ApplicationController
(中略)
  def show
    @user = User.find(params[:id])
    # 検索拡張機能として.search(params[:search])を追加    
    @microposts = @user.microposts.paginate(page: params[:page]).search(params[:search])
    # like拡張機能
    @likes = Like.where(micropost_id: params[:micropost_id])
  end
(中略)
end

[static_pages_controller.rb]

class StaticPagesController < ApplicationController
  def home
    if logged_in?
      @micropost  = current_user.microposts.build
      # 検索拡張機能として.search(params[:search])を追加 
      @feed_items = current_user.feed.paginate(page: params[:page]).search(params[:search])
      # like拡張機能
      @likes = Like.where(micropost_id: params[:micropost_id])
    end
  end
(中略)
end

[likes_controller.rb]

class LikesController < ApplicationController
  def create
    @like = Like.create(user_id: current_user.id, micropost_id: params[:micropost_id])
    @likes = Like.where(micropost_id: params[:micropost_id])
  end

  def destroy
    like = Like.find_by(user_id: current_user.id, micropost_id: params[:micropost_id])
    like.destroy
    @likes = Like.where(micropost_id: params[:micropost_id])
  end
end

[Model]

[models/micropost.rb]
class Micropost < ApplicationRecord
  belongs_to :user
  has_many :likes, dependent: :destroy
  default_scope -> { order(created_at: :desc) }
  mount_uploader :picture, PictureUploader
  validates :user_id, presence: true
  validates :content, presence: true, length: { maximum: 140 }
  validate  :picture_size
(中略)
  # like拡張機能
  def like_user(user_id)
    likes.find_by(user_id: user_id)
  end

  private
(中略)
end

[models/like.rb]
class Like < ActiveRecord::Base
  belongs_to :micropost, counter_cache: :likes_count
  belongs_to :user
end

[JS]

[likes/create.js.erb]
$("#like-buttons").html("<%= j(render partial: 'like', locals: { micropost: micropost, likes: @likes, like: @like}) %>");

[likes/destroy.js.erb]
$("#like-buttons").html("<%= j(render partial: 'like', locals: { micropost: micropost, likes: @likes }) %>");

[Routes]

[routes.rb]
Rails.application.routes.draw do
  get 'password_resets/new'

  get 'password_resets/edit'

  root   'static_pages#home'
  get    '/help',    to: 'static_pages#help'
  get    '/about',   to: 'static_pages#about'
  get    '/contact', to: 'static_pages#contact'
  get    '/signup',  to: 'users#new'
  post   '/signup',  to: 'users#create'  
  get    '/login',   to: 'sessions#new'
  post   '/login',   to: 'sessions#create'
  delete '/logout',  to: 'sessions#destroy'
  resources :users do
    member do
      get :following, :followers
    end
  end
  resources :account_activations, only: [:edit]
  resources :password_resets,     only: [:new, :create, :edit, :update]
  resources :relationships,       only: [:create, :destroy]

#like機能拡張用に指定
  resources :microposts do
    resources :likes, only: [:create, :destroy]
  end

end

【Usersページ】 f:id:mochikichi321:20170408065023p:plain

【Homeページ】 f:id:mochikichi321:20170408065030p:plain

実装ステップ

STEP1 現状把握

まず、現時点での[View],[Controller],[Model]及び[Routes]はこのようになっている。

[View]

[microposts/_micropost.html.erb]

<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content">
    <%= micropost.content %>
    <%= image_tag micropost.picture.url if micropost.picture? %>    
  </span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
    <% if current_user?(micropost.user) %>
      <%= link_to "delete", micropost, method: :delete,
                                       data: { confirm: "You sure?" } %>
    <% end %>
  </span>

#ここへlike拡張機能追加予定

</li>

[Controller]

[users_controller.rb]

class UsersController < ApplicationController
(中略)
  def show
    @user = User.find(params[:id])
    # 検索拡張機能として.search(params[:search])を追加    
    @microposts = @user.microposts.paginate(page: params[:page]).search(params[:search])
  end
(中略)
end

[static_pages_controller.rb]

class StaticPagesController < ApplicationController
  def home
    if logged_in?
      @micropost  = current_user.microposts.build
      # 検索拡張機能として.search(params[:search])を追加 
      @feed_items = current_user.feed.paginate(page: params[:page]).search(params[:search])
    end
  end
(中略)
end

[Model]

[models/micropost.rb]

class Micropost < ApplicationRecord
  belongs_to :user
  has_many :likes, dependent: :destroy
  default_scope -> { order(created_at: :desc) }
  mount_uploader :picture, PictureUploader
  validates :user_id, presence: true
  validates :content, presence: true, length: { maximum: 140 }
  validate  :picture_size
(中略)
end

[Routes]

[routes.rb]

Rails.application.routes.draw do
  get 'password_resets/new'

  get 'password_resets/edit'

  root   'static_pages#home'
  get    '/help',    to: 'static_pages#help'
  get    '/about',   to: 'static_pages#about'
  get    '/contact', to: 'static_pages#contact'
  get    '/signup',  to: 'users#new'
  post   '/signup',  to: 'users#create'  
  get    '/login',   to: 'sessions#new'
  post   '/login',   to: 'sessions#create'
  delete '/logout',  to: 'sessions#destroy'
  resources :users do
    member do
      get :following, :followers
    end
  end
  resources :account_activations, only: [:edit]
  resources :password_resets,     only: [:new, :create, :edit, :update]
  resources :microposts,          only: [:create, :destroy]
  resources :relationships,       only: [:create, :destroy]
end

STEP2 likesテーブルを作成

ターミナルでlikesテーブルを作成。カラムはinteger型でuser_idとmicropost_idを追加。

$ rails g model Like user_id:integer micropost_id:integer                                       

作成したLikeモデルに以下を記載。

[models/like.rb]

class Like < ActiveRecord
  belongs_to :micropost, counter_cache: :likes_count
  belongs_to :user
end

counter_cahce: :likes_countは、子モデル(リレーションされているlike)の数を親モデルのカラム(micropostのlikes_count)に保存を意味する。なので、likes_countカラムをMicropostテーブルに追加する。

counter_cahceとは?

STEP3 Micropostテーブルにlikes_countカラムを追加

Micropostテーブルにinteger型のlikes_countというカラムを追加する。

$ rails g migration add_likes_count_to_microposts likes_count:integer

$ rails db:migrate

さらに同モデルファイルに以下を記載する。

[models/micropost.rb]

class Micropost < ApplicationRecord
  belongs_to :user
  has_many :likes, dependent: :destroy
(中略)
  def like_user(user_id)
   likes.find_by(user_id: user_id)
  end

  private
(中略)
end

like_userメソッドは指定のユーザーが既にマイクロポストにいいねしているかを確認するメソッド。

STEP4:ルーティング設定

resourcesを使いmicropostsとlikesの構造を規定。

[routes.rb]

Rails.application.routes.draw do
  get 'password_resets/new'

  get 'password_resets/edit'

  root   'static_pages#home'
  get    '/help',    to: 'static_pages#help'
  get    '/about',   to: 'static_pages#about'
  get    '/contact', to: 'static_pages#contact'
  get    '/signup',  to: 'users#new'
  post   '/signup',  to: 'users#create'  
  get    '/login',   to: 'sessions#new'
  post   '/login',   to: 'sessions#create'
  delete '/logout',  to: 'sessions#destroy'
  resources :users do
    member do
      get :following, :followers
    end
  end
  resources :account_activations, only: [:edit]
  resources :password_resets,     only: [:new, :create, :edit, :update]
#削除
  resources :relationships,       only: [:create, :destroy]

#like機能拡張用に指定
  resources :microposts do
    resources :likes, only: [:create, :destroy]
  end

end

STEP5 likesコントローラーのアクションを定義

likes controllerを作成し、そのファイルに以下を記載する。

[likes_controller.rb]

class LikesController < ApplicationController
  def create
    @like = Like.create(user_id: current_user.id, micropost_id: params[:micropost_id])
    @likes = Like.where(micropost_id: params[:micropost_id])
  end

  def destroy
    like = Like.find_by(user_id: current_user.id, micropost_id: params[:micropost_id])
    like.destroy
    @likes = Like.where(micropost_id: params[:micropost_id])
  end
end

likeを増やしたり消したりするlikeとその後の合計like数を表示するための@likesを定義。

合わせて、usersコントローラーとstatic_pagesコントローラーにも@likesを定義。

[users_controller.rb]

class UsersController < ApplicationController
(中略)
  def show
    @user = User.find(params[:id])
    # 検索拡張機能として.search(params[:search])を追加    
    @microposts = @user.microposts.paginate(page: params[:page]).search(params[:search])
    # like拡張機能
    @likes = Like.where(micropost_id: params[:micropost_id])
  end
(中略)
end

[static_pages_controller.rb]

class StaticPagesController < ApplicationController
  def home
    if logged_in?
      @micropost  = current_user.microposts.build
      # 検索拡張機能として.search(params[:search])を追加 
      @feed_items = current_user.feed.paginate(page: params[:page]).search(params[:search])
      # like拡張機能
      @likes = Like.where(micropost_id: params[:micropost_id])
    end
  end
(中略)
end

STEP6 like部分テンプレートを作る

今回はいいねボタンを部分テンプレートを使って作る。

STEP3で定義したlike_userメソッドを使用し、指定ユーザーがマイクロポストにいいねしているかを判断し、表示を切り分ける。いいねしていたら赤色のハート、いいねしていなければ灰色のハートを表示。

likesのモデルファイルでcounter_cacheの記述があるので、micropost.likes_countとするだけでそのマイクロポストに結びつくlike数が表示される。

どちらのアクションのパスもremote: trueの記述をしてajaxを使いアクションを実行する。

icon_red_heard.pngがいいね後の赤色のハート、icon_heart.pngがいいね前の灰色のハート。画像を準備して"assets/images"フォルダの中にそれぞれ保存をしておく。

[画像サンプル]

f:id:mochikichi321:20170408070249p:plain

f:id:mochikichi321:20170408070253p:plain

[likes/_like.html.erb]

<% if micropost.like_user(current_user.id) %>
  <%= button_to micropost_like_path(likes, micropost_id: micropost.id), method: :delete, id: "like-button", remote: true do %> 
    <%= image_tag("icon_red_heart.png") %>
    <span>
      <%= micropost.likes_count %>
    </span>
  <% end %>
<% else %>
  <%= button_to micropost_likes_path(micropost),id: "like-button", remote: true do %>  
    <%= image_tag("icon_heart.png") %>
    <span>
      <%= micropost.likes_count %>
    </span>
  <% end %>
<% end %>

like部分テンプレートを表示したい箇所に挿入する。

[microposts/_micropost.html.erb]

<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content">
    <%= micropost.content %>
    <%= image_tag micropost.picture.url if micropost.picture? %>    
  </span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
    <% if current_user?(micropost.user) %>
      <%= link_to "delete", micropost, method: :delete,
                                       data: { confirm: "You sure?" } %>
    <% end %>
  </span>
  <!--like拡張機能-->
  <%= render partial: 'likes/like', locals: { micropost: micropost, likes: @likes } %>

</li>

STEP7 JSファイルを作る

ajaxを使ってページ遷移をせずにいいねを増やしたり消したりするjavascriptファイルを作る。

[likes/create.js.erb]

$("#like-buttons").html("<%= j(render partial: 'like', locals: { micropost: micropost, likes: @likes, like: @like}) %>");

[likes/destroy.js.erb]

$("#like-buttons").html("<%= j(render partial: 'like', locals: { micropost: micropost, likes: @likes }) %>");

以上で簡易like機能の実装が完了。

参考

http://qiita.com/YuitoSato/items/94913d6a349a530b2ea2

プログラミング未経験から2か月でエンジニアへ転職したノウハウを知りたい方の相談も受け付けております。

関連記事

mochikichi.hatenablog.com

男性の育休取得に対する周囲の反応あるある まとめ

育児留学 育児留学-育児休業

こんにちは!エンジニアを目指す育休中新米パパのmochikichiです。

男性で育児休業を取っていると周りの方々から様々な反応があるのでご紹介します。

 

男性の育休周囲の反応

反応事例

 

以下は「育休を取ります/育休を取っています」と話した時の反応。 

 

「え?どういうこと!?」 #会社の直属の上司(30代男性)

 ⇒"男性が育休を取る"ということがあまりにも無縁すぎてプチパニック状態。

 

「そんなに休暇取れるっていいね。」 #友人(20代男性)

⇒遊びじゃねーよ。

 

「なんで男性が育休を取る必要があるの?」 #会社の上司など多数

父親だから。

 

「男性が育休取っても育休中ってヒマでしょ?」 #病院の助産師(40代女性)

 ⇒これは結構驚いた一言。男性は育児には力になれないという思い込みから。助産師から聞くとは。。。

 

「里帰りして両親に見てもらったらいいんじゃないの?」 #会社の同僚(40代男性)

 ⇒里帰りをしないという選択もあるんです。

 

「俺も取りたいけど、復帰後会社の椅子がなくなりそう。」 #親戚(30代男性)

 ⇒本当になくなるなら辞めてしまったらいい。

 

「いいな~大企業は。俺の会社なんて育休制度ないし~。」 #友人(20代男性)など多数

⇒法律で定められていてだれでも取れます。(※下記参照)

 

「何か家庭の事情でもあるの?」 #会社の同僚(40代男性)

⇒事情がないと取っちゃダメなの? 

 

「おっ!流行りの "イクメン" だね~!(ひやかし)」 #会社の同僚など多数

 ⇒一番ウザいやつ。無視です、無視。

 

「給料は?生活費大丈夫なの??」 #親

⇒心配するかと思うけど育児休業給付金があります。

 

「素晴らしいね!その経験は絶対将来活きてくるよ!私は育児をやり切ったという経験があったから強くなれた。男性もその経験をできないのは勿体ない!主人にももっと育児をさせてあげれば良かった。」 #コワーキングスペースマネージャー(30代女性)

⇒一番響いた言葉。

 

「俺も取りたかったなぁ~。子供が小さいとき出張ばっかりで成長をほとんど見れなかったし。」 #会社の先輩(30代男性)など多数

⇒意外と多い、後悔系。

 

「うちの夫にもとってほしい」 #友人(30代女性)

⇒ お母さんは頑張ってますよ、お父さん。

 

「主人の周りの訪日外国人はみんな育休取ってて、主人も勧められたって」 #友人(30代女性)

⇒外国人からすると当たり前なんだ。。

 

「ありがとう。一緒に子育てできるのは幸せ。」 #妻

⇒一番成長する時期を一緒に見守れることが幸せ。大変なことも一緒に乗り越えることで夫婦、家族の絆は深まる。

 

育休制度の法律

育児休業とは、子どもを養育する労働者が取得できる休業のことで、法律によって認められた制度であり、就業規則への記載が義務づけられています。

第五条

労働者は、その養育する一歳に満たない子について、その事業主に申し出ることにより、育児休業をすることができる。育児休業、介護休業等育児又は家族介護を行う労働者の福祉に関する法律 第5条より)

万一、就業規則に記載がない場合でも、事業主は労働者からの育休の申し出を拒否することはできません。

 

第六条

事業主は、労働者からの育児休業申出があったときは、当該育児休業申出を拒むことができない。

育児休業、介護休業等育児又は家族介護を行う労働者の福祉に関する法律 第6条より)

 

男性の育休周囲の反応

まとめ

いくつか紹介しましたが、周囲の反応は様々です。残念ながら今の世の中では賛同する声ばかりではないのが実態です。その事実をわかったうえでも、育休を取得することでかけがえのない貴重な経験ができたと思っています。詳細は別途発信します。

重要なのは、夫婦間で育児に対してしっかりと向き合い、話し合いをして自分たちの意思で決めることです。

育休を取りたいけど不安で踏み出せない方がいらっしゃれば、一歩踏み出すことを応援します。

 

男性の育休取得に対して"こんな意見を言われた/聞いた"という皆さんの意見をお待ちしています。お気軽にコメントください。

 

男性の育休取得に対する相談も受け付けております。

 

MediumのPublicationを始めました。交流の場として活用ください。

medium.com

Ruby on Rails 検索機能拡張 (railsチュートリアル)

プログラミング プログラミング-Rails_チュートリアル

目的

Ruby on Rails チュートリアル 5.0(第4版)で実装したサンプルアプリケーションを元に、検索機能を拡張します。

完成版アプリケーション

実際に検索機能を拡張したアプリケーションを見てみたい方はこちら。

https://fathomless-shore-36670.herokuapp.com/about

開発環境

Rails 5.0

・cloud9

実装

1.indexページにユーザ検索機能を実装する

最終的なソースコードと確認画面

[View]

[users/index.html.erb]

<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>

<!--  検索拡張機能  -->
<p>user search</p>
<%= form_tag(users_path) do %>
  <%= text_field_tag :search %>
  <%= submit_tag 'Search', :name => nil %>
<% end %>

<ul class="users">
  <%= render @users %>
</ul>
<%= will_paginate %>

[Controller]

[users_controller.rb]

class UsersController < ApplicationController
(中略)
  def index
    @users = User.where(activated: true).paginate(page: params[:page]).search(params[:search])
  end
(中略)
end

[Model]

[models/user.rb]

class User < ApplicationRecord
(中略)
  def self.search(search) #ここでのself.はUser.を意味する
    if search
      where(['name LIKE ?', "%#{search}%"]) #検索とnameの部分一致を表示。User.は省略
    else
      all #全て表示。User.は省略
    end
  end
  
  private
(中略)
end

[確認画面]

[検索前] f:id:mochikichi321:20170326111010p:plain

[検索後] f:id:mochikichi321:20170326111015p:plain

実装ステップ

手順を知りたい方向け。

STEP1

まず、現時点でのindexページ及びusers_controllerはこのようになっている。

[users/index.html.erb]

<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>

#ここへ検索拡張機能追加予定

<ul class="users">
  <%= render @users %>
</ul>
<%= will_paginate %>

[users_controller.rb]

class UsersController < ApplicationController
(中略)
  def index
    @users = User.where(activated: true,).paginate(page: params[:page])
  end
(中略)
end

f:id:mochikichi321:20170326111218p:plain

STEP2

フォームを作成。パスはusers#indexの"users_path"を指定。 text_field_tagのシンボルは任意なので":search"とする。

[users/index.html.erb]

<%= form_tag(users_path) do %>
  <%= text_field_tag :search %>
  <%= submit_tag 'Search' %>
<% end %>

submitボタンを押すとエラーが出る。 f:id:mochikichi321:20170326111415p:plain

STEP3

ブラウザからソースコードを確認すると、以下の通りとなっており、method=“post"となっていることがわかる。

<form action="/users" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input type="hidden" name="authenticity_token" value="ncc66/h8qa7NC/78Rxyk0UA0UdCNhOReJockKrID+IkNAjgA9gORJ+1KwJiPTT7kRS7zvELfwm1ZeH0gLmSa/g==" />
  <input type="text" name="search" id="search" />
  <input type="submit" name="commit" value="Search" data-disable-with="Search" />
</form>

STEP4

method=“get"へ指定。

[users/index.html.erb]

<%= form_tag(users_path, method: :get) do %>
  <%= text_field_tag :search %>
  <%= submit_tag 'Search' %>
<% end %>

STEP5

users_controllerのindexアクションにsearchを追加。

[users_controller.rb]

class UsersController < ApplicationController
(中略)
  def index
    #条件分岐
    @users = if params[:search]
      #searchされた場合は、原文+.where('name LIKE ?', "%#{params[:search]}%")を実行
      User.where(activated: true).paginate(page: params[:page]).where('name LIKE ?', "%#{params[:search]}%")
    else
      #searchされていない場合は、原文そのまま
      User.where(activated: true).paginate(page: params[:page])
    end
  end
(中略)
end

これで検索機能は実装された。

STEP6

searchフォームに:searchを加える。

[users/index.html.erb]

<%= form_tag(users_path) do %>
  <%= text_field_tag :search %>
  <%= submit_tag 'Search' %>
<% end %>

STEP7

URLに以下が含まれるが消す。

“commit=Search”

[users/index.html.erb]

<%= form_tag(users_path) do %>
  <%= text_field_tag :search %>
  <%= submit_tag 'Search', :name => nil %>
<% end %>

STEP8

リファクタリングし、モデルへ移行。

[users_controller.rb]

class UsersController < ApplicationController
(中略)
  def index
    @users = User.where(activated: true).paginate(page: params[:page]).search(params[:search])
  end
(中略)
end

[models/user.rb]

class User < ApplicationRecord
(中略)
  def self.search(search) #ここでのself.はUser.を意味する
    if search
      where(['name LIKE ?', "%#{search}%"]) #検索とnameの部分一致を表示。#User.は省略
    else
      all #全て表示。#User.は省略
    end
  end
  
  private
(中略)
end

STEP9

何の検索ができるのかをわかりやすくするために"user search"をform上部に追加

[users/index.html.erb]

<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>

<!--  検索拡張機能  -->
<p>user search</p>
<%= form_tag(users_path) do %>
  <%= text_field_tag :search %>
  <%= submit_tag 'Search', :name => nil %>
<% end %>

2.userプロフィールページにマイクロポスト検索機能を実装する

最終的なソースコードと確認画面

[View]

[users/show.html.erb]

<% provide(:title, @user.name) %>
<div class="row">
(中略)
  <div class="col-md-8">
    <%= render 'follow_form' if logged_in? %>
    <% if @user.microposts.any? %>
      <h3>Microposts (<%= @user.microposts.count %>)</h3>

      <!--検索拡張機能  -->
      <p>content serch</p>
      <%= form_tag user_path, :method => 'get' do %>
        <p>
          <%= text_field_tag :search, params[:search] %>
          <%= submit_tag "Search", :name => nil %>
        </p>
      <% end %>
      
      <ol class="microposts">
        <%= render @microposts %>
      </ol>
      <%= will_paginate @microposts %>
    <% end %>
  </div>
</div>

[Controller]

[users_controller.rb]

class UsersController < ApplicationController
(中略)
  def show
    @user = User.find(params[:id])
    # 検索拡張機能として.search(params[:search])を追加    
    @microposts = @user.microposts.paginate(page: params[:page]).search(params[:search])
  end
(中略)
end

[Model]

[models/micropost.rb]

class Micropost < ApplicationRecord
(中略)
  def self.search(search) #ここでのself.はMicropost.を意味する
    if search
      where(['content LIKE ?', "%#{search}%"]) #検索とcontentの部分一致を表示。Micropost.は省略。
    else
      all #全て表示。Micropost.は省略。
    end
  end

  private
(中略)
end

[確認画面]

[検索前] f:id:mochikichi321:20170326111930p:plain

[検索後] f:id:mochikichi321:20170326111936p:plain

実装ステップ

基本的には「1.indexページにユーザ検索機能を実装する」と同様のステップ。 [Model]のwhere([‘content LIKE ?’, “%#{search}%”])が"name"から"content"になっている点に注意。

3.Homeページにマイクロポスト検索機能を実装する

最終的なソースコードと確認画面

[View]

[static_pages/home.html.erb]

<% if logged_in? %>
  <%= render 'static_pages/user_logged_in' %>
<% else %>
  <%= render 'static_pages/user_not_logged_in' %>
<% end %>

[static_pages/_user_logged_in.html.erb]

<div class="row">
(中略)
  <div class="col-md-8">
    <h3>Micropost Feed</h3>

    <!--検索拡張機能  -->
    <p>content serch</p>
    <%= form_tag root_path, :method => 'get' do %>
      <p>
        <%= text_field_tag :search, params[:search] %>
        <%= submit_tag "Search", :name => nil %>
      </p>
    <% end %> 
    <%= render 'shared/feed' %>
  </div>
</div>

[Controller]

[static_pages_controller.rb]

class StaticPagesController < ApplicationController
  def home
    if logged_in?
      @micropost  = current_user.microposts.build
      # 検索拡張機能として.search(params[:search])を追加 
      @feed_items = current_user.feed.paginate(page: params[:page]).search(params[:search])
    end
  end
(中略)
end

[Model]

「2.userプロフィールページにマイクロポスト検索機能を実装する」から変更なし。

[models/micropost.rb]

class Micropost < ApplicationRecord
(中略)
  def self.search(search) #ここでのself.はMicropost.を意味する
    if search
      where(['content LIKE ?', "%#{search}%"]) #検索とcontentの部分一致を表示。Micropost.は省略。
    else
      all #全て表示。Micropost.は省略。
    end
  end

  private
(中略)
end

[確認画面]

[検索前] f:id:mochikichi321:20170326112226p:plain

[検索後] f:id:mochikichi321:20170326112233p:plain

実装ステップ

基本的には「1.indexページにユーザ検索機能を実装する」と同様のステップ。

4.リファクタリング

上記で検索機能を3つのviewページへ追加しました。 共通する部分が多いのでリファクタリングします。

[users/_search.html.erb]

<p><%= yield(:search_name) %></p>
<%= form_tag(yield(:path), method: :get) do %>
  <%= text_field_tag :search, params[:search] %>
  <%= submit_tag 'Search', :name => nil %>
<% end %>

[users/index.html.erb]

<% provide(:title, 'All users') %>
<% provide(:search_name, 'user search') %>
<% provide(:path, users_path) %>
<h1>All users</h1>

<%= will_paginate %>

<ul class="users">
  <%= render 'users/search' %>  <-- searchパーシャル呼出 -->
  <%= render @users %>
</ul>

<%= will_paginate %>

[users/show.html.erb]
<% provide(:title, @user.name) %>
<% provide(:search_name, 'content search') %>
<% provide(:path, user_path) %>
<div class="row">
(中略)
  <div class="col-md-8">
    <%= render 'follow_form' if logged_in? %>
    <% if @user.microposts.any? %>
      <h3>Microposts (<%= @user.microposts.count %>)</h3>
      <%= render 'users/search' %>   <-- searchパーシャル呼出 -->
      <ol class="microposts">
        <%= render @microposts %>
      </ol>
      <%= will_paginate @microposts %>
    <% end %>
  </div>
</div>

[static_pages/_user_logged_in.html.erb]

<% provide(:search_name, 'content search') %>
<% provide(:path, root_path) %>
  <div class="row">
(中略)
    <div class="col-md-8">
      <h3>Micropost Feed</h3>
      <%= render 'users/search' %>  <-- searchパーシャル呼出 -->  
      <%= render 'shared/feed' %>
    </div>
  </div>

参考

Simple Search Form in Rails 5

プログラミング未経験から2か月でエンジニアへ転職したノウハウを知りたい方の相談も受け付けております。

関連記事

mochikichi.hatenablog.com

【第14章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ

プログラミング プログラミング-Rails_チュートリアル

Ruby on Rails Tutorial最新版の演習と解答です。

f:id:mochikichi321:20170206212242p:plain

目的

Ruby on Rails チュートリアル 5.0(第4版)を学習中です。

学習を進める中で演習問題の解答がなかった(*1,2)ので、自分なりにまとめていくこととしました。

アウトプットし、自分の理解を深めることを目的としています。 もし、記載内容に誤りがあった場合はコメントいただけると幸いです。

(*1)著者による有償版の解答はあるようです。正式な解答をご希望の方はこちらを参照ください。

Learn Web Development with Rails: Michael Hartl's Ruby on Rails Tutorial | Softcover.io

(*2)旧版に関する解答はありましたが、最新版 5.0(第4版)に関しては検索しても出てきませんでした。

プログラミングを学習し始めたきっかけについてはこちら

mochikichi.hatenablog.com

演習問題と解答

演習14.1.1

演習14.1.1.1

<問題> 図 14.7のid=1のユーザーに対してuser.following.map(&:id)を実行すると、結果はどのようになるでしょうか? 想像してみてください。ヒント: 4.3.2で紹介したmap(&:method_name)のパターンを思い出してください。例えばuser.following.map(&:id)の場合、idの配列を返します。

<解答> [2,7,8,10]

演習14.1.1.2

<問題> 図 14.7を参考にして、id=2のユーザーに対してuser.followingを実行すると、結果はどのようになるでしょうか? また、同じユーザーに対してuser.following.map(&:id)を実行すると、結果はどのようになるでしょうか? 想像してみてください。

<解答> user.following [user_id:1, name:Michael Hartl, email:mhartl@example.com] user.following.map(&:id) [1]

演習14.1.2

演習14.1.2.1

<問題> コンソールを開き、表 14.1のcreateメソッドを使ってActiveRelationshipを作ってみましょう。データベース上に2人以上のユーザーを用意し、最初のユーザーが2人目のユーザーをフォローしている状態を作ってみてください。

<解答>

>> user=User.first
  User Load (1.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-02-23 23:09:36", updated_at: "2017-02-23 23:09:36", password_digest: "$2a$10$JZHMQYjhJjqvbfW8QGWJ6.UEWjfuhbi1r8GL3/apYKv...", remember_digest: nil, admin: true, activation_digest: "$2a$10$ozX2hLov2jSJ6FpCku7vHO5Ys9EUjY1ZAGzcKQcw938...", activated: true, activated_at: "2017-02-23 23:09:36", reset_digest: nil, reset_sent_at: nil>

>> other_user=User.second
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
=> #<User id: 2, name: "Jamey Windler MD", email: "example-1@railstutorial.org", created_at: "2017-02-23 23:09:37", updated_at: "2017-02-23 23:09:37", password_digest: "$2a$10$HbJ9qu3236xnHHulFCbmweSa3bThCR5XIG2MX2z8yry...", remember_digest: nil, admin: false, activation_digest: "$2a$10$fLt.yeQ3C2hABfXORioyPOHd0X.zNBGyFjIDuRAhqra...", activated: true, activated_at: "2017-02-23 23:09:37", reset_digest: nil, reset_sent_at: nil>

>> user.active_relationships.create(followed_id: other_user.id)                                                                             
   (0.1ms)  SAVEPOINT active_record_1
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  SQL (0.5ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 2], ["created_at", 2017-02-24 12:29:46 UTC], ["updated_at", 2017-02-24 12:29:46 UTC]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2017-02-24 12:29:46", updated_at: "2017-02-24 12:29:46">

演習14.1.2.2

<問題> 先ほどの演習を終えたら、active_relationship.followedの値とactive_relationship.followerの値を確認し、それぞれの値が正しいことを確認してみましょう。

<解答> 演習14.1.2.1参照。

演習14.1.3

演習14.1.3.1

<問題> リスト 14.5のバリデーションをコメントアウトしても、テストが成功したままになっていることを確認してみましょう。(以前のRailsのバージョンでは、このバリデーションが必須でしたが、Rails 5から必須ではなくなりました。今回はフォロー機能の実装を優先しますが、この手のバリデーションが省略されている可能性があることを頭の片隅で覚えておくと良いでしょう。)

<解答> 動作確認のみなので省略。

演習14.1.4

演習14.1.4.1

<問題> コンソールを開き、リスト 14.9のコードを順々に実行してみましょう。

<解答>

>> michael=User.first
  User Load (1.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-02-23 23:09:36", updated_at: "2017-02-23 23:09:36", password_digest: "$2a$10$JZHMQYjhJjqvbfW8QGWJ6.UEWjfuhbi1r8GL3/apYKv...", remember_digest: nil, admin: true, activation_digest: "$2a$10$ozX2hLov2jSJ6FpCku7vHO5Ys9EUjY1ZAGzcKQcw938...", activated: true, activated_at: "2017-02-23 23:09:36", reset_digest: nil, reset_sent_at: nil>

>> archer=User.second
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
=> #<User id: 2, name: "Jamey Windler MD", email: "example-1@railstutorial.org", created_at: "2017-02-23 23:09:37", updated_at: "2017-02-23 23:09:37", password_digest: "$2a$10$HbJ9qu3236xnHHulFCbmweSa3bThCR5XIG2MX2z8yry...", remember_digest: nil, admin: false, activation_digest: "$2a$10$fLt.yeQ3C2hABfXORioyPOHd0X.zNBGyFjIDuRAhqra...", activated: true, activated_at: "2017-02-23 23:09:37", reset_digest: nil, reset_sent_at: nil>

>> michael.following?(archer)
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ?  [["follower_id", 1], ["id", 2], ["LIMIT", 1]]
=> false

>> michael.follow(archer)
   (0.1ms)  SAVEPOINT active_record_1
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  SQL (0.5ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 2], ["created_at", 2017-02-24 12:58:52 UTC], ["updated_at", 2017-02-24 12:58:52 UTC]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2017-02-24 12:58:52", updated_at: "2017-02-24 12:58:52">

>> michael.following?(archer)
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ?  [["follower_id", 1], ["id", 2], ["LIMIT", 1]]
=> true

>> michael.unfollow(archer)
  Relationship Load (0.3ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT ?  [["follower_id", 1], ["followed_id", 2], ["LIMIT", 1]]
   (0.1ms)  SAVEPOINT active_record_1
  SQL (0.4ms)  DELETE FROM "relationships" WHERE "relationships"."id" = ?  [["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2017-02-24 12:58:52", updated_at: "2017-02-24 12:58:52">

>> michael.following?(archer)
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ?  [["follower_id", 1], ["id", 2], ["LIMIT", 1]]
=> false

演習14.1.4.2

<問題> 先ほどの演習の各コマンド実行時の結果を見返してみて、実際にはどんなSQLが出力されたのか確認してみましょう。

<解答>

 SQL (0.4ms)  DELETE FROM "relationships" WHERE "relationships"."id" = ?

演習14.1.5

演習14.1.5.1

<問題> コンソールを開き、何人かのユーザーが最初のユーザーをフォローしている状況を作ってみてください。最初のユーザーをuserとすると、user.followers.map(&:id)の値はどのようになっているでしょうか?

<解答>

>> user=User.first
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-02-23 23:09:36", updated_at: "2017-02-23 23:09:36", password_digest: "$2a$10$JZHMQYjhJjqvbfW8QGWJ6.UEWjfuhbi1r8GL3/apYKv...", remember_digest: nil, admin: true, activation_digest: "$2a$10$ozX2hLov2jSJ6FpCku7vHO5Ys9EUjY1ZAGzcKQcw938...", activated: true, activated_at: "2017-02-23 23:09:36", reset_digest: nil, reset_sent_at: nil>

>> user2=User.second
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
=> #<User id: 2, name: "Jamey Windler MD", email: "example-1@railstutorial.org", created_at: "2017-02-23 23:09:37", updated_at: "2017-02-23 23:09:37", password_digest: "$2a$10$HbJ9qu3236xnHHulFCbmweSa3bThCR5XIG2MX2z8yry...", remember_digest: nil, admin: false, activation_digest: "$2a$10$fLt.yeQ3C2hABfXORioyPOHd0X.zNBGyFjIDuRAhqra...", activated: true, activated_at: "2017-02-23 23:09:37", reset_digest: nil, reset_sent_at: nil>

>> user3=User.third
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 2]]
=> #<User id: 3, name: "Micaela Crona", email: "example-2@railstutorial.org", created_at: "2017-02-23 23:09:37", updated_at: "2017-02-23 23:09:37", password_digest: "$2a$10$ng2IzsKTNkOxB5zteVxszuNRdr8YB56vvfLn5aCKNvd...", remember_digest: nil, admin: false, activation_digest: "$2a$10$FYKD7pHxhchKv662YYqIAuvQpuY1HRDHOsoHWtQrt1D...", activated: true, activated_at: "2017-02-23 23:09:37", reset_digest: nil, reset_sent_at: nil>

>> user2.active_relationships.create(followed_id: 1)                                                                                        
   (0.1ms)  SAVEPOINT active_record_1
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  SQL (0.4ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 2], ["followed_id", 1], ["created_at", 2017-02-24 13:12:55 UTC], ["updated_at", 2017-02-24 13:12:55 UTC]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 2, followed_id: 1, created_at: "2017-02-24 13:12:55", updated_at: "2017-02-24 13:12:55">

>> user3.active_relationships.create(followed_id: 1)                                                                                        
   (0.1ms)  SAVEPOINT active_record_1
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  SQL (0.3ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 3], ["followed_id", 1], ["created_at", 2017-02-24 13:13:08 UTC], ["updated_at", 2017-02-24 13:13:08 UTC]]
   (0.0ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 2, follower_id: 3, followed_id: 1, created_at: "2017-02-24 13:13:08", updated_at: "2017-02-24 13:13:08">

>> user.followers.map(&:id)
  User Load (0.3ms)  SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 1]]
=> [2, 3]

演習14.1.5.2

<問題> 上の演習が終わったら、user.followers.countの実行結果が、先ほどフォローさせたユーザー数と一致していることを確認してみましょう。

<解答>

>> user.followers.count
   (0.2ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 1]]
=> 2

演習14.1.5.3

<問題> user.followers.countを実行した結果、出力されるSQL文はどのような内容になっているでしょうか? また、user.followers.to_a.countの実行結果と違っている箇所はありますか? ヒント: もしuserに100万人のフォロワーがいた場合、どのような違いがあるでしょうか? 考えてみてください。

<解答>

>> user.followers.count
   (0.2ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 1]]
=> 2

>> user.followers.to_a.count
=> 2

演習14.2.1

演習14.2.1.1

<問題> コンソールを開き、User.first.followers.countの結果がリスト 14.14で期待している結果と合致していることを確認してみましょう。

<解答> 動作確認のみなので省略。

演習14.2.1.2

<問題> 先ほどの演習と同様に、User.first.following.countの結果も合致していることを確認してみましょう。

<解答> 動作確認のみなので省略。

演習14.2.2

演習14.2.2.1

<問題> ブラウザから /users/2 にアクセスし、フォローボタンが表示されていることを確認してみましょう。同様に、/users/5 では [Unfollow] ボタンが表示されているはずです。さて、/users/1 にアクセスすると、どのような結果が表示されるでしょうか?

<解答> /users/1では、follow/unfollowボタンは表示されない。

演習14.2.2.2

<問題> ブラウザからHomeページとプロフィールページを表示してみて、統計情報が正しく表示されているか確認してみましょう。

<解答> 動作確認のみなので省略。

演習14.2.3

演習14.2.3.1

<問題> ブラウザから /users/1/followers と /users/1/following を開き、それぞれが適切に表示されていることを確認してみましょう。サイドバーにある画像は、リンクとしてうまく機能しているでしょうか?

<解答> 動作確認のみなので省略。

演習14.2.3.2

<問題> リスト 14.29のassert_selectに関連するコードをコメントアウトしてみて、テストが正しく red に変わることを確認してみましょう。

<解答> 動作確認のみなので省略。

演習14.2.4

演習14.2.4.1

<問題> ブラウザ上から /users/2 を開き、[Follow] と [Unfollow] を実行してみましょう。うまく機能しているでしょうか?

<解答> 動作確認のみなので省略。

演習14.2.4.2

<問題> 先ほどの演習を終えたら、Railsサーバーのログを見てみましょう。フォロー/フォロー解除が実行されると、それぞれどのテンプレートが描画されているでしょうか?

<解答> 両方とも、"users/show.html.erb"

演習14.2.5

演習14.2.5.1

<問題> ブラウザから /users/2 にアクセスし、うまく動いているかどうか確認してみましょう。

<解答> 動作確認のみなので省略。

演習14.2.5.2

<問題> 先ほどの演習で確認が終わったら、Railsサーバーのログを閲覧し、フォロー/フォロー解除を実行した直後のテンプレートがどうなっているか確認してみましょう。

<解答> フォロー :relationships/create.js.erb フォロー解除 :relationships/destroy.js.erb

演習14.2.6

演習14.2.6.1

<問題> リスト 14.36のrespond_toブロック内の各行を順にコメントアウトしていき、テストが正しくエラーを検知できるかどうか確認してみましょう。実際、どのテストケースが落ちたでしょうか?

<解答> createアクションの"format.html { redirect_to @user }“をコメントアウトした場合、 "should_follow_a_user_the_standard_way"がエラー。

createアクションの"format.html { redirect_to @user }“,"format.js"をコメントアウトした場合、 "should_follow_a_user_the_standard_way"と "should_follow_a_user_with_Ajax"がエラー。

destroyアクションの"format.html { redirect_to @user }“をコメントアウトした場合、 "should_unfollow_a_user_the_standard_way"がエラー。

destroyアクションの"format.html { redirect_to @user }“,"format.js"をコメントアウトした場合、 "should_unfollow_a_user_the_standard_way"と "should_unfollow_a_user_with_Ajax"がエラー。

演習14.2.6.2

<問題> リスト 14.40のxhr: trueがある行のうち、片方のみを削除するとどういった結果になるでしょうか? このとき発生する問題の原因と、なぜ先ほどの演習で確認したテストがこの問題を検知できたのか考えてみてください。

<解答> “format.js"のみをコメントアウトしてもエラーは発生しない。

演習14.3.1

演習14.3.1.1

<問題> マイクロポストのidが正しく並んでいると仮定して (すなわち若いidの投稿ほど古くなる前提で)、図 14.22のデータセットでuser.feed.map(&:id)を実行すると、どのような結果が表示されるでしょうか? 考えてみてください。ヒント: 13.1.4で実装したdefault_scopeを思い出してください。

<解答> [10,9,7,5,4,2,1]

演習14.3.3

演習14.3.3.1

<問題> Homeページで表示される1ページ目のフィードに対して、統合テストを書いてみましょう。リスト 14.49はそのテンプレートです。

<解答>

[test/integration/following_test.rb]

require 'test_helper'

class FollowingTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
    log_in_as(@user)
  end
  .
  .
  .
  test "feed on Home page" do
    get root_path
    @user.feed.paginate(page: 1).each do |micropost|
      assert_match CGI.escapeHTML(micropost.content), response.body
    end
  end
end

演習14.3.3.2

<問題> リスト 14.49のコードでは、期待されるHTMLをCGI.escapeHTMLメソッドでエスケープしています (このメソッドは11.2.3で扱ったCGI.escapeと同じ用途です)。このコードでは、なぜHTMLをエスケープさせる必要があったのでしょうか? 考えてみてください。ヒント: 試しにエスケープ処理を外して、得られるHTMLの内容を注意深く調べてください。マイクロポストの内容が何かおかしいはずです。また、ターミナルの検索機能 (Cmd-FもしくはCtrl-F) を使って「sorry」を探すと原因の究明に役立つはずです。

<解答> エスケープ処理を外すと、HTML中に"I’m sorry.“があるが、"I'm sorry."となる。

関連記事

【第1章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第2章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第3章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第4章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第5章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第6章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第7章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第8章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第9章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第10章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第11章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第12章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第13章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

Rails 検索機能拡張 (rails tutorial) - 新米パパの育児留学

プログラミング未経験から2か月でエンジニアへ転職したノウハウを知りたい方の相談も受け付けております。

転職祝い金50万円のIT・WEB業界特化型転職サービス"Nexstar"を実際に使ってみた

プログラミング プログラミング-転職

facebook_転職_アプリ_nexstar

Nexstarとは

Nexstarとは、 ITベンチャー企業である株式会社オープンキャリアが提供する、Facebookアプリを用いたIT・WEB業界に特化した転職支援サービスである。

 

株式会社オープンキャリア(open-carrer)(*1)は、2014年に設立されたITベンチャー企業に特化した人材紹介会社であり、東証マザーズ上場の株式会社アイモバイルから誕生した。株式会社アイモバイル(*2)は、インターネット広告システムの構築・配信を主力事業としており、ふるさと納税サイト「ふるなび」等を運営するIT業界において一定の地位と信頼を築いている会社である。

 

(*1)ITベンチャー企業に特化した人材紹介 | open-career

(*2)アイモバイル(i-mobile) 国内最大級のアドネットワーク広告 PC/スマートフォン広告(スマホ広告・アイコン広告・インターステーシャル広告・ウォール広告・レクタングル広告) android iphone広告

 

Nexstarの4つの特徴

Facebookアプリを用いたIT・WEB業界に特化した転職支援サービスであるが、類似サービスとしては「Switch.(*3)」がある。基本的には同様の機能を有していると考えてもらって問題ないが、「Switch.」にはない大きな特徴があるのでそこを含めて以下で説明する。

(*3)Facebookを使った新感覚スカウト型転職サイトSwitch.

1.転職祝い金、50万円!

facebook_転職_アプリ_nexstar_祝い金

ここが最大の特徴である。転職祝い金としてAmazonギフト券や現金数万円というサービスは多くあるが、「50万円(*4)」という金額には驚きだ。

転職が決まったら引越しや生活環境の変化等支出が多くなるのでこれは非常に嬉しい。

自分の行きたい企業がNexstarにあれば間違いなくNexstarから申し込んで臨時ボーナスをもらった方がお得だ。

 (*4)理論年収400万円以上の採用でお祝い金50万円、400万円未満の採用の場合はお祝い金30万円

2.簡単1クリック無料登録

facebook_転職_アプリ_nexstar_簡単登録

そして、登録が簡単だ。登録ボタンを押してFacebookとの連携を認証すればすぐにサービスを開始できる。もちろん、スカウトを受けるためにはプロフィールを充実していった方が好ましいが、まずは登録してみてどのような企業が掲載されていてどのような使い勝手かを「体験」したいのであれば「1クリック」で登録完了する。

 ※Facebookに勝手に投稿されるようなことはないので安心できる。

登録はこちら↓

3.カジュアルメッセージ

facebook_転職_アプリ_nexstar_カジュアルメッセージ

興味を持った企業に自分からチャット形式で気軽に質問できる。チャット機能は、メールのように「〇〇株式会社〇〇様 この度は...」といったかしこまった形式ではなく「いつでも気軽に聞きたいことだけ聞ける」ので導入しているサービスは増えてきており人気の問い合わせツールだ。

※「Switch.」にはチャット機能があるが、「マッチング成立後」となっている。「応募する」となるとかなり重い印象を受けた。

 

4.無料の転職サポート

facebook_転職_アプリ_nexstar_無料の転職サポート

IT・WEB業界経験を持った専門コンサルタントに「転職相談・キャリアの悩み・市場動向」などをチャットで無料相談できる。無料で気軽に何度でも相談できるのでありがたい。

 

実際に使ってみた

上記のような特徴を持っており、すごく興味深いサービスだったので実際に使ってみた。

 

まず1クリック登録をし、どのような企業からの求人があるのかを覗いてみた。

 

以下は一例だが、サイバーエージェントのようなもはやベンチャーではないような大きな企業から、スタートアップのSansanなど個人的に興味を惹かれる企業が並んでいた。(2017年2月現在) 

facebook_転職_アプリ_nexstar_企業一覧

プロフィール情報を充実させてみると約1週間で7社からスカウトが到来。

facebook_転職_アプリ_nexstar_スカウト

その中から、Nexstarの母体でもあるアイモバイルに詳しく聞いてみることに。

チャットでコンタクトを取ると数時間で返答があった。お気軽!

facebook_転職_アプリ_nexstar_チャットでコンタクト

続いてNexstarへ市場動向を問い合わせ。丁寧に返答してくれた。

facebook_転職_アプリ_nexstar_問い合わせ回答

まとめ

実際に使ってみた感想。

・登録は本当に1クリックでできて簡単。

・シンプルなユーザーインターフェースで使いやすい。

・自分の興味ある企業にチャットで気軽に質問できて使いやすい。

・求人企業の数はまだ多くはないが、面白いベンチャー企業が集まりつつある。今後の拡大に更に期待できる。

 

ワンクリックで簡単に登録できるのでまずは"お試し"で登録してみてはどうだろうか。

縁のある企業が見つかれば晴れてお祝い金50万円GET!!

登録はこちら↓

プログラミング未経験から2か月でエンジニアへ転職したノウハウを知りたい方の相談も受け付けております。

【第13章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ

プログラミング プログラミング-Rails_チュートリアル

Ruby on Rails Tutorial最新版の演習と解答です。

f:id:mochikichi321:20170206212242p:plain

目的

Ruby on Rails チュートリアル 5.0(第4版)を学習中です。

学習を進める中で演習問題の解答がなかった(*1,2)ので、自分なりにまとめていくこととしました。

アウトプットし、自分の理解を深めることを目的としています。 もし、記載内容に誤りがあった場合はコメントいただけると幸いです。

(*1)著者による有償版の解答はあるようです。正式な解答をご希望の方はこちらを参照ください。

Learn Web Development with Rails: Michael Hartl's Ruby on Rails Tutorial | Softcover.io

(*2)旧版に関する解答はありましたが、最新版 5.0(第4版)に関しては検索しても出てきませんでした。

プログラミングを学習し始めたきっかけについてはこちら

mochikichi.hatenablog.com

演習問題と解答

演習13.1.1

演習13.1.1.1

<問題> RailsコンソールでMicropost.newを実行し、インスタンスを変数micropostに代入してください。その後、user_idに最初のユーザーのidを、contentに “Lorem ipsum” をそれぞれ代入してみてください。この時点では、 micropostオブジェクトのマジックカラム (created_atとupdated_at) には何が入っているでしょうか?

<解答>

>> micropost=Micropost.new
=> #<Micropost id: nil, content: nil, user_id: nil, created_at: nil, updated_at: nil>

>> micropost.user_id=1
=> 1
>> micropost.content="Lorem ipsum"
=> "Lorem ipsum"

>> micropost
=> #<Micropost id: nil, content: "Lorem ipsum", user_id: 1, created_at: nil, updated_at: nil>

マジックカラムは"nil"

演習13.1.1.2

<問題> 先ほど作ったオブジェクトを使って、micropost.userを実行してみましょう。どのような結果が返ってくるでしょうか? また、micropost.user.nameを実行した場合の結果はどうなるでしょうか?

<解答>

>> micropost.user
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-02-20 10:41:54", updated_at: "2017-02-20 10:41:54", password_digest: "$2a$10$/kQ3M3tCRo9fdhf4dvYBBezX19bWZk2SJeSkovfkJgB...", remember_digest: nil, admin: true, activation_digest: "$2a$10$gxTIacN4NX5iNR0/H3WayuLkrh7ZGJzsoJG3hSu1WAt...", activated: true, activated_at: "2017-02-20 10:41:54", reset_digest: nil, reset_sent_at: nil>

>> micropost.user.name
=> "Example User"

演習13.1.1.3

<問題> 先ほど作ったmicropostオブジェクトをデータベースに保存してみましょう。この時点でもう一度マジックカラムの内容を調べてみましょう。今度はどのような値が入っているでしょうか?

<解答>

>> micropost.save
   (0.1ms)  begin transaction
  SQL (0.4ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", 2017-02-23 07:52:35 UTC], ["updated_at", 2017-02-23 07:52:35 UTC]]
   (13.0ms)  commit transaction
=> true

マジックカラムには上記の実行日時が入る。

演習13.1.2

演習13.1.2.1

<問題> Railsコンソールを開き、user_idとcontentが空になっているmicropostオブジェクトを作ってみてください。このオブジェクトに対してvalid?を実行すると、失敗することを確認してみましょう。また、生成されたエラーメッセージにはどんな内容が書かれているでしょうか?

<解答> 動作確認のみなので省略。

演習13.1.2.2

<問題> コンソールを開き、今度はuser_idが空でcontentが141文字以上のmicropostオブジェクトを作ってみてください。このオブジェクトに対してvalid?を実行すると、失敗することを確認してみましょう。また、生成されたエラーメッセージにはどんな内容が書かれているでしょうか?

<解答> 動作確認のみなので省略。

演習13.1.3

演習13.1.3.1

<問題> データベースにいる最初のユーザーを変数userに代入してください。そのuserオブジェクトを使ってmicropost = user.microposts.create(content: “Lorem ipsum”)を実行すると、どのような結果が得られるでしょうか?

<解答>

>> user=User.first
  User Load (1.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-02-20 10:41:54", updated_at: "2017-02-20 10:41:54", password_digest: "$2a$10$/kQ3M3tCRo9fdhf4dvYBBezX19bWZk2SJeSkovfkJgB...", remember_digest: nil, admin: true, activation_digest: "$2a$10$gxTIacN4NX5iNR0/H3WayuLkrh7ZGJzsoJG3hSu1WAt...", activated: true, activated_at: "2017-02-20 10:41:54", reset_digest: nil, reset_sent_at: nil>

>> micropost = user.microposts.create(content: "Lorem ipsum")
   (0.1ms)  begin transaction
  SQL (2.1ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", 2017-02-23 08:21:53 UTC], ["updated_at", 2017-02-23 08:21:53 UTC]]
   (13.0ms)  commit transaction
=> #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2017-02-23 08:21:53", updated_at: "2017-02-23 08:21:53">

演習13.1.3.2

<問題> 先ほどの演習課題で、データベース上に新しいマイクロポストが追加されたはずです。 user.microposts.find(micropost.id)を実行して、本当に追加されたのかを確かめてみましょう。また、先ほど実行したmicropost.idの部分をmicropostに変更すると、結果はどうなるでしょうか?

<解答>

>> user.microposts.find(micropost.id)
  Micropost Load (0.3ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? AND "microposts"."id" = ? LIMIT ?  [["user_id", 1], ["id", 2], ["LIMIT", 1]]
=> #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2017-02-23 08:21:53", updated_at: "2017-02-23 08:21:53">

>> user.microposts.find(micropost)
DEPRECATION WARNING: You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`. (called from irb_binding at (irb):4)
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? AND "microposts"."id" = ? LIMIT ?  [["user_id", 1], ["id", 2], ["LIMIT", 1]]
=> #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2017-02-23 08:21:53", updated_at: "2017-02-23 08:21:53">

micropost.idの部分をmicropostに変更するとidを指定するよう要求される

演習13.1.3.3

<問題> user == micropost.userを実行した結果はどうなるでしょうか? また、user.microposts.first == micropost を実行した結果はどうなるでしょうか? それぞれ確認してみてください。

>> user == micropost.user
=> true

>> user.microposts.first == micropost
  Micropost Load (0.4ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."id" ASC LIMIT ?  [["user_id", 1], ["LIMIT", 1]]
=> false

micropost id:2なので、user.microposts.first != micropost

演習13.1.4

演習13.1.4.1

<問題> Micropost.first.created_atの実行結果と、Micropost.last.created_atの実行結果を比べてみましょう。

<解答>

>> Micropost.first.created_at
  Micropost Load (1.7ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" DESC LIMIT ?  [["LIMIT", 1]]
=> Thu, 23 Feb 2017 08:21:53 UTC +00:00

>> Micropost.last.created_at
  Micropost Load (0.4ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" ASC LIMIT ?  [["LIMIT", 1]]
=> Thu, 23 Feb 2017 07:52:35 UTC +00:00

演習13.1.4.2

<問題> Micropost.firstを実行したときに発行されるSQL文はどうなっているでしょうか? 同様にして、Micropost.lastの場合はどうなっているでしょうか? ヒント: それぞれをコンソール上で実行したときに表示される文字列が、SQL文になります。

<解答>

>> Micropost.first
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" DESC LIMIT ?  [["LIMIT", 1]]
=> #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2017-02-23 08:21:53", updated_at: "2017-02-23 08:21:53">

>> Micropost.last
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" ASC LIMIT ?  [["LIMIT", 1]]
=> #<Micropost id: 1, content: "Lorem ipsum", user_id: 1, created_at: "2017-02-23 07:52:35", updated_at: "2017-02-23 07:52:35">

Micropost.firstはDESC Micropost.lastはASC

演習13.1.4.3

<問題> データベース上の最初のユーザーを変数userに代入してください。そのuserオブジェクトが最初に投稿したマイクロポストのidはいくつでしょうか? 次に、destroyメソッドを使ってそのuserオブジェクトを削除してみてください。削除すると、そのuserに紐付いていたマイクロポストも削除されていることをMicropost.findで確認してみましょう。

<解答> 動作確認のみなので省略。

演習13.2.1

演習13.2.1.1

<問題> 7.3.3で軽く説明したように、今回ヘルパーメソッドとして使ったtime_ago_in_wordsメソッドは、Railsコンソールのhelperオブジェクトから呼び出すことができます。このhelperオブジェクトのtime_ago_in_wordsメソッドを使って、3.weeks.agoや6.months.agoを実行してみましょう。

<解答> 動作確認のみなので省略。

演習13.2.1.2

<問題> helper.time_ago_in_words(1.year.ago)と実行すると、どういった結果が返ってくるでしょうか?

<解答>

>> helper.time_ago_in_words(1.year.ago)
=> "about 1 year"

演習13.2.1.3

<問題> micropostsオブジェクトのクラスは何でしょうか? ヒント: リスト 13.23内のコードににあるように、まずはpaginateメソッド (引数はpage: nil) でオブジェクトを取得し、その後classメソッドを呼び出してみましょう。

<解答>

>> user=User.first
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-02-23 11:51:52", updated_at: "2017-02-23 11:51:52", password_digest: "$2a$10$ZN5cjKOsES4dYHA/QRijX.4wJG.cFLhUkciP2cYhROy...", remember_digest: nil, admin: true, activation_digest: "$2a$10$e7ScgLHWk1IcYzvOXRt08.KOV.YZ/z.h9QI1imwG3Ez...", activated: true, activated_at: "2017-02-23 11:51:52", reset_digest: nil, reset_sent_at: nil>

>> microposts = user.microposts.paginate(page: nil)
  Micropost Load (0.3ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ? OFFSET ?  [["user_id", 1], ["LIMIT", 30], ["OFFSET", 0]]
=> #<ActiveRecord::AssociationRelation []>

>> microposts.class
=> Micropost::ActiveRecord_AssociationRelation

演習13.2.2

演習13.2.2.1

<問題> (1..10).to_a.take(6)というコードの実行結果を推測できますか? 推測した値が合っているかどうか、実際にコンソールを使って確認してみましょう。

<解答>

>> (1..10).to_a.take(6)
=> [1, 2, 3, 4, 5, 6]

演習13.2.2.1

<問題> 先ほどの演習にあったto_aメソッドの部分は本当に必要でしょうか? 確かめてみてください。

<解答> 不要。

演習13.2.2.1

<問題> Fakerはlorem ipsum以外にも、非常に多種多様の事例に対応しています。Fakerのドキュメント (英語) を眺めながら画面に出力する方法を学び、実際に大学名や電話番号、Hipster IpsumやChuck Norris facts (参考: チャック・ノリスの真実) を画面に出力してみましょう。(訳注: もちろん日本語にも対応していて、例えば沖縄らしい用語を出力するfaker-okinawaもあります。ぜひ遊んでみてください。)

<解答> 動作確認のみなので省略。

演習13.2.3

演習13.2.3.1

<問題> リスト 13.28にある2つの’h1’行をコメントアウトしてみて、テストが green から redに変わることを確認してみましょう。

<解答> 動作確認のみなので省略。 ※実際にコメントアウトするのは"リスト 13.24"の'h1'の中の2行。

演習13.2.3.2

<問題> リスト 13.28にあるテストを変更して、will_paginateが少なくとも1度(※)は表示されていることをテストしてみましょう。ヒント: 表 5.2を参考にしてください。

※英文版を確認してみると"only once"となっており、"1度のみ"でした。おそらく誤訳かと思われます。 原文は以下。 https://www.railstutorial.org/book/user_microposts#sec-profile_micropost_tests Update Listing 13.28 to test that will_paginate appears only once. Hint: Refer to Table 5.2.

<解答>

[users_profile_test.rb]

require 'test_helper'

class UsersProfileTest < ActionDispatch::IntegrationTest
  include ApplicationHelper

  def setup
    @user = users(:michael)
  end

  test "profile display" do
    get user_path(@user)
    assert_template 'users/show'
    assert_select 'title', full_title(@user.name)
    assert_select 'h1', text: @user.name
    assert_select 'h1>img.gravatar'
    assert_match @user.microposts.count.to_s, response.body
    assert_select 'div.pagination', count:1   <---注目
    @user.microposts.paginate(page: 1).each do |micropost|
      assert_match micropost.content, response.body
    end
  end
end

演習13.3.1

演習13.3.1.1

<問題> なぜUsersコントローラ内にあるlogged_in_userフィルターを残したままにするとマズイのでしょうか? 考えてみてください。

<解答> コードが重複するため。

演習13.3.2

演習13.3.2.1

<問題> Homeページをリファクタリングして、if-else文の分岐のそれぞれに対してパーシャルを作ってみましょう。

<解答>

[home.html.erb]

<% if logged_in? %>
  <%= render 'static_pages/user_logged_in' %>
<% else %>
  <%= render 'static_pages/user_not_logged_in' %>
<% end %>

[_user_logged_in.html.erb]

  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      <section class="micropost_form">
        <%= render 'shared/micropost_form' %>
      </section>
    </aside>
  </div>

[_user_not_logged_in.html.erb]

  <div class="center jumbotron">
    <h1>Welcome to the Sample App</h1>

    <h2>
      This is the home page for the
      <a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a>
      sample application.
    </h2>

    <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
  </div>

  <%= link_to image_tag("rails.png", alt: "Rails logo"),
              'http://rubyonrails.org/' %>

演習13.3.3

演習13.3.3.1

<問題> 新しく実装したマイクロポストの投稿フォームを使って、実際にマイクロポストを投稿してみましょう。Railsサーバーのログ内にあるINSERT文では、どういった内容をデータベースに送っているでしょうか? 確認してみてください。

<解答>

 INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "aaa"], ["user_id", 1], ["created_at", 2017-02-24 01:41:51 UTC], ["updated_at", 2017-02-24 01:41:51 UTC]]

演習13.3.3.2

<問題> コンソールを開き、user変数にデータベース上の最初のユーザーを代入してみましょう。その後、Micropost.where(“user_id = ?”, user.id)とuser.microposts、そしてuser.feedをそれぞれ実行してみて、実行結果がすべて同じであることを確認してみてください。ヒント: ==で比較すると結果が同じかどうか簡単に判別できます。

<解答> 動作確認のみなので省略。

演習13.3.4

演習13.3.4.1

<問題> マイクロポストを作成し、その後、作成したマイクロポストを削除してみましょう。次に、Railsサーバーのログを見てみて、DELETE文の内容を確認してみてください。

<解答> 動作確認のみなので省略。

演習13.3.4.2

<問題> redirect_to request.referrer || root_urlの行をredirect_back(fallback_location: root_url)と置き換えてもうまく動くことを、ブラウザを使って確認してみましょう (このメソッドはRails 5から新たに導入されました)。

<解答> 動作確認のみなので省略。

演習13.3.5

演習13.3.5.1

<問題> リスト 13.55で示した4つのコメント (「無効な送信」など) のそれぞれに対して、テストが正しく動いているか確認してみましょう。具体的には、対応するアプリケーション側のコードをコメントアウトし、テストが redになることを確認し、元に戻すと greenになることを確認してみましょう。

<解答> 動作確認のみなので省略。

演習13.3.5.2

<問題> サイドバーにあるマイクロポストの合計投稿数をテストしてみましょう。このとき、単数形 (micropost) と複数形 (microposts) が正しく表示されているかどうかもテストしてください。ヒント: リスト 13.57を参考にしてみてください。

<解答>

[microposts_interface_test.rb]

require 'test_helper'

class MicropostsInterfaceTest < ActionDispatch::IntegrationTest

(中略)

  test "micropost sidebar count" do
    log_in_as(@user)
    get root_path
    assert_match "#{@user.microposts.count} microposts", response.body   <---注目
    # まだマイクロポストを投稿していないユーザー
    other_user = users(:malory)
    log_in_as(other_user)
    get root_path
    assert_match "0 microposts", response.body
    other_user.microposts.create!(content: "A micropost")
    get root_path
    assert_match "1 micropost", response.body   <---注目
  end
end

演習13.4.1

演習13.4.1.1

<問題> 画像付きのマイクロポストを投稿してみましょう。もしかして、大きすぎる画像が表示されてしまいましたか? (心配しないでください、次の13.4.3でこの問題を直します)。

<解答> 動作確認のみなので省略。

演習13.4.1.2

<問題> リスト 13.63に示すテンプレートを参考に、13.4で実装した画像アップローダーをテストしてください。テストの準備として、まずはサンプル画像をfixtureディレクトリに追加してください (コマンド例: cp app/assets/images/rails.png test/fixtures/)。リスト 13.63で追加したテストでは、Homeページにあるファイルアップロードと、投稿に成功した時に画像が表示されているかどうかをチェックしています。なお、テスト内にあるfixture_file_uploadというメソッドは、fixtureで定義されたファイルをアップロードする特別なメソッドです16。ヒント: picture属性が有効かどうかを確かめるときは、11.3.3で紹介したassignsメソッドを使ってください。このメソッドを使うと、投稿に成功した後にcreateアクション内のマイクロポストにアクセスするようになります。

<解答>

[microposts_interface_test.rb]

require 'test_helper'

class MicropostsInterfaceTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end

  test "micropost interface" do
    log_in_as(@user)
    get root_path
    assert_select 'div.pagination'
    assert_select 'input[type="file"]'   <---注目
    # 無効な送信
    post microposts_path, micropost: { content: "" }
    assert_select 'div#error_explanation'
    # 有効な送信
    content = "This micropost really ties the room together"
    picture = fixture_file_upload('test/fixtures/rails.png', 'image/png')
    assert_difference 'Micropost.count', 1 do
      post microposts_path, micropost: { content: content, picture: picture }   <---注目
    end
    assert assigns(:micropost).picture?   <---注目
    follow_redirect!
    assert_match content, response.body
    # 投稿を削除する
    assert_select 'a', text: 'delete'
    first_micropost = @user.microposts.paginate(page: 1).first
    assert_difference 'Micropost.count', -1 do
      delete micropost_path(first_micropost)
    end
    # 違うユーザーのプロフィールにアクセス (削除リンクがないことを確認)
    get user_path(users(:archer))
    assert_select 'a', text: 'delete', count: 0
  end

(中略)

end

演習13.4.2

演習13.4.2.1

<問題> 5MB以上の画像ファイルを送信しようとした場合、どうなりますか?

<解答> エラーが出る。

演習13.4.2.2

<問題> 無効な拡張子のファイルを送信しようとした場合、どうなりますか?

<解答> エラーが出る。

演習13.4.3

演習13.4.3.1

<問題> 解像度の高い画像をアップロードし、リサイズされているかどうか確認してみましょう。画像が長方形だった場合、リサイズはうまく行われているでしょうか?

<解答> 確認は省略。長方形の場合は、長い辺が400pxとなるようにリサイズされる。

演習13.4.3.2

<問題> 既にリスト 13.63のテストを追加していた場合、この時点でテストスイートを走らせるとエラーメッセージが表示されるようになるはずです。このエラーを取り除いてみましょう。ヒント: リスト 13.68にある設定ファイルを修正し、テスト時はCarrierWaveに画像のリサイズをさせないようにしてみましょう。

<解答> リスト 13.68参照。

演習13.4.4

演習13.4.4.1

<問題> 本番環境で解像度の高い画像をアップロードし、適切にリサイズされているか確認してみましょう。長方形の画像であっても、適切にリサイズされていますか?

<解答> 動作確認のみなので省略。

関連記事

【第1章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第2章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第3章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第4章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第5章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第6章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第7章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第8章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第9章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第10章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第11章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第12章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

【第14章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ - 新米パパの育児留学

Ruby on Rails 検索機能拡張 (rails tutorial) - 新米パパの育児留学

プログラミング未経験から2か月でエンジニアへ転職したノウハウを知りたい方の相談も受け付けております。