コミュ障だから明日が僕らをよんだって返事もろくにしなかった

何かを創る人に憧れたからブログをはじめたんだと思うよ

社会のボトムズがRailsに手を出す #13-2

これまでのあらすじ

このお話は#13の続きです。あらすじおわりっ!!

前回記事
inujini.hatenablog.com



はい、前回記事の内容が長くなりそうな気がしたので前後編に分けることにしました。前回はマイクロポストの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

そうしたら先ほどのやつを利用して以下のようなマイクロポストをつくります。
f:id:andron:20190122222659p:plain

# 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

f:id:andron:20190125024951p:plain

アップローダの作り方はチュートリアルにも簡単に書いてあったりするけども、gemのページにも書いてあったりもする。
GitHub - carrierwaveuploader/carrierwave: Classier solution for file uploads for Rails, Sinatra and other Ruby web frameworks

やっぱりgem使うとコード書かなくなりますね……。



第十三章の感想

本当は一つにまとめて投稿したかったんだけどもやっぱり長くなってしまった。まさかgemいじるところが鬼門になるとは思わなかった。やっぱりWindowsはダメだな。ここのところ作業的なことばっかりだったからgemいじりは結構やりがいあったけどね……。まあ、内容としてはそんな感じの内容です。

このまま「誰ともつながらないSNS『孤独ったー』」とかにしてリリースしても次章もあるので次章終わらせてからどうするか考える。


次回へ続く。あ、次回最終章です。

*1:なんか他にいい対処方法あればコメントください。