これまでのあらすじ
このお話は#13の続きです。あらすじおわりっ!!
はい、前回記事の内容が長くなりそうな気がしたので前後編に分けることにしました。前回はマイクロポストのDB周りとちゃんと表示できるのかの確認をやっていきました。今回は実際に投稿できるかどうかみたいなところをやっていきます。
マイクロポストを操作する
まずは、開幕リファクタリングとなります。Applicationコントローラにlogged_in_user
を移します。Usersコントローラに同じ奴があるのでそちらは取り除きます。
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base protect_from_forgery with: :exception include SessionsHelper private # ユーザーのログインを確認する def logged_in_user unless logged_in? store_location flash[:danger] = "Please log in." redirect_to login_url end end end
そうしたら先ほどのやつを利用して以下のようなマイクロポストをつくります。
# app/controllers/microposts_controller.rb class MicropostsController < ApplicationController before_action :logged_in_user, only: [:create, :destroy] before_action :correct_user, only: :destroy def create @micropost = current_user.microposts.build(micropost_params) if @micropost.save flash[:success] = "Micropost created!" redirect_to root_url else @feed_items = [] render 'static_pages/home' end end # マイクロポストを削除 def destroy @micropost.destroy flash[:success] = "Micropost deleted" redirect_to request.referrer || root_url end private # pictureを許可された属性のリストに追加 def micropost_params params.require(:micropost).permit(:content, :picture) end # 正しいユーザーかどうかを確認 def correct_user @micropost = current_user.microposts.find_by(id: params[:id]) redirect_to root_url if @micropost.nil? end end
# app/views/shared/_user_info.html.erb <span><%= pluralize(current_user.microposts.count, "micropost") %></span>
pluralize
が単数・複数分けてくれるはずなんだけど日本語化しているせいか、なんかうまくいかない。Rails3まではロケール無視で色々やってくれるらしい。ほう……。まあ日本語ベースでやっているのであんまり気にしないんですけどね。とりあえずそういう機能があるってことだけ頭の片隅に入れておく。
class StaticPagesController < ApplicationController def home if logged_in? # app/views/shared/_micropost_form.html.erb @micropost <= current_user.microposts.build if logged_in? @micropost = current_user.microposts.build # app/models/user.rb def feed( Micropost.where("user_id = ?", id) ) @feed_items = current_user.feed.paginate(page: params[:page]) end end def help end def about end def contact end end
コメントが自由記述になってしまった。ごちゃごちゃしている割には機能的には前回の復習みたいな内容だから省略しても問題ないと思ってる。
そんでテストはこう。
# test/controllers/microposts_controller_test.rb require 'test_helper' class MicropostsControllerTest < ActionDispatch::IntegrationTest def setup @micropost = microposts(:orange) end test "ログインしていないときの create をリダイレクト" do assert_no_difference 'Micropost.count' do post microposts_path, params: { micropost: { content: "Lorem ipsum" } } end assert_redirected_to login_url end test "ログインしていないときの desroy をリダイレクト" do assert_no_difference 'Micropost.count' do delete micropost_path(@micropost) end assert_redirected_to login_url end test "不正なマイクロポストの destroy をリダイレクト" do log_in_as(users(:michael)) micropost = microposts(:ants) assert_no_difference 'Micropost.count' do delete micropost_path(micropost) end assert_redirected_to root_url end end
# test/integration/microposts_interface_test.rb require 'test_helper' class MicropostsInterfaceTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) end test "micropost に対して" do log_in_as(@user) get root_path assert_select 'div.pagination' # 無効な送信 assert_no_difference 'Micropost.count' do post microposts_path, params: { micropost: { content: "" } } end assert_select 'div#error_explanation' assert_select 'input[type=file]' # 有効な送信 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, params: { micropost: { content: content, picture: picture}} end assert @user.microposts.first.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 test "サイドバーにある micropost " do log_in_as(@user) get root_path assert_match "#{@user.microposts.count} micropost", response.body # まだマイクロポストを投稿していないユーザー other_user = users(:malory) log_in_as(other_user) get root_path assert_match "0 micropost", response.body other_user.microposts.create!(content: "A micropost") get root_path assert_match "1 micropost", response.body end end
注目すべきところを英単語にすると日本語にしても見やすくなるのではと思いそれっぽい文章を書いてみる。まあ素直に英語でテスト書けって話なんですけどね…。そして、日本語ロケールの影響でassert_match
も複数形表示の影響を受けてる…。
画像投稿機能などをつけてみる
これで投稿機能はほぼ実装できたので、今度はgemを使って画像投稿機能を作っていくそうです。利用するgemは以下の通り。細かい仕様についてはrubygemリンク貼っておいたからそこのHomepage参照ください。
carrierwave
carrierwave | RubyGems.org | your community gem host
簡単にアップローダつくれるやつ。
mini_magick
mini_magick | RubyGems.org | your community gem host
画像ファイルリサイズしてくれるやつ
fog
fog | RubyGems.org | your community gem host
Amazon S3につなぐようgem (* とりあえず導入してますが本番環境の整備とかしていないので利用していないです)
このあたりからbundle install
してもうまくいかなくなってきたのでWSL使ってインスコするようにしました。
WSLについて
inujini.hatenablog.com
/mnt/[ドライブ]/[保存先]
みたいにすればWindows側のファイルもいじれるらしい。当初はGUIでの使い道を探してたけど意外にも別の方面で使い道が生まれた。
そんで、それでも以下のようなエラーに見舞われたのでgem 'mini_racer'
で雑に対処しました*1。
(ExecJS::RubyRacerRuntime is not supported. Please replace therubyracer with mini_racer in your Gemfile or use Node.js as ExecJS runtime.):
これでgemの準備ができたら以下操作を行ってアップローダできるそうです。
$ rails generate uploader Picture $ rails generate migration add_picture_to_microposts picture:string $ rails db:migrate
アップローダの作り方はチュートリアルにも簡単に書いてあったりするけども、gemのページにも書いてあったりもする。
GitHub - carrierwaveuploader/carrierwave: Classier solution for file uploads for Rails, Sinatra and other Ruby web frameworks
やっぱりgem使うとコード書かなくなりますね……。
第十三章の感想
本当は一つにまとめて投稿したかったんだけどもやっぱり長くなってしまった。まさかgem
いじるところが鬼門になるとは思わなかった。やっぱりWindowsはダメだな。ここのところ作業的なことばっかりだったからgemいじりは結構やりがいあったけどね……。まあ、内容としてはそんな感じの内容です。
このまま「誰ともつながらないSNS『孤独ったー』」とかにしてリリースしても次章もあるので次章終わらせてからどうするか考える。
次回へ続く。あ、次回最終章です。
*1:なんか他にいい対処方法あればコメントください。