Slide 1

Slide 1 text

ྺ࢙͋ΔϓϩδΣΫτͷͱ͋Δٕज़తෛ࠴Λ 伱ؒϓϩδΣΫτͷ 1VMM3FRVFTUTͰ౗͖ͬͨ͠࿩ 2022.10.21. Kaigi on Rails 2022 @makicamel

Slide 2

Slide 2 text

w!NBLJDBNFM઒ݪສق w3VCZͱϏʔϧɹɹͱ͓ञ͕޷͖ w޷͖ͳ73ήʔϜ w ࣗݾ঺հ ࠓ೔ͷ࿩

Slide 3

Slide 3 text

ٕज़తෛ࠴ ͋Γ·͔͢ʁ

Slide 4

Slide 4 text

ٕज़తෛ࠴ ฦͯ͠·͔͢ʁ

Slide 5

Slide 5 text

ٕज़తෛ࠴ͷฦ٫ •ܭըΛཱͯͯઓུతʹ౗͢ͷ͕ηΦϦʔ •ͱ͸ݴ͑ޙճ͠ɾ์ஔ͞Εͯརଉ͕๲ΒΈ͕ͪ •։࢝͸ൺֱత༰қ •ܧଓɾ׬਱͸೉қ౓ߴ େ͖ͳ

Slide 6

Slide 6 text

Ͱ΋ɺ΍Γ͍ͨ

Slide 7

Slide 7 text

ྺ࢙͋ΔϓϩδΣΫτͷͱ͋Δٕज़తෛ࠴Λ 伱ؒϓϩδΣΫτͷ 1VMM3FRVFTUTͰ౗͖ͬͨ͠࿩

Slide 8

Slide 8 text

ྺ࢙͋ΔϓϩδΣΫτͷͱ͋Δٕज़తෛ࠴Λ 伱ؒϓϩδΣΫτͷ 1VMM3FRVFTUTͰ౗͖ͬͨ͠࿩

Slide 9

Slide 9 text

•7 ೥ؒେ͖͘ҭͬͨ Rails ΞϓϦ •਺ेਓ͕৮ΔϓϩδΣΫτ ྺ࢙͋ΔϓϩδΣΫτ +- -------------------- - +- ------- - +- ------ - +- ------- - +- -------- +- ---- +- ------ + | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +- -------------------- - +- ------- - +- ------ - +- ------- - +- -------- +- ---- +- ------ + | Controllers | 106768 | 84571 | 1182 | 8419 | 7 | 8 | | Jobs | 2532 | 1869 | 96 | 139 | 1 | 11 | | Models | 173665 | 125931 | 834 | 9068 | 10 | 11 | | Mailers | 515 | 444 | 10 | 11 | 1 | 38 | | Libraries | 4464 | 3134 | 37 | 313 | 8 | 8 | | … | … | … | … | … | … | … | +- -------------------- - +- ------- - +- ------ - +- ------- - +- -------- +- ---- +- ------ + | Total | 1112716 | 885175 | 2169 | 18354 | 8 | 46 | +- -------------------- - +- ------- - +- ------ - +- ------- - +- -------- +- ---- +- ------ +

Slide 10

Slide 10 text

•ෳࡶͳઃܭɾ࣮૷ •ਆςʔϒϧɾਆϞσϧɾڊେίϯτϩʔϥɾڊେείʔϓ… •ΦϨΦϨϑϨʔϜϫʔΫ •etc … ૊Έ߹ΘͤͰΑΓෳࡶԽ ٕज़తෛ࠴

Slide 11

Slide 11 text

•։ൃॳظΛࢧ͑ͨΦϨΦϨϑϨʔϜϫʔΫ •ΞϓϦͷ੒௕ʹ͋Θͤͨϝϯς͕͞Εͣෛ࠴Խ •ANDPAD ͷͭΒΈτοϓϥϯΧʔ •2019 ೥ळɿࣾ಺هࣄͰ՝୊ͱ঺հ •2020 ೥य़ɿఫഇͷखॱॻ͕ॻ͔ΕΔ΋ղফ͸ਐ·ͣ CrudController

Slide 12

Slide 12 text

class UsersController < ApplicationController before_action :new_one, only: [:new, :create] def new; end def create if @user.save create_success_response_to else create_error_response_to end end def new_one @user = scope.new(one_params) end def create_success_response_to respond_to do |format| format.html { flash[:notify_success] = "࡞੒͠·ͨ͠" redirect_to { action: :index } } format.json { render json: @user.to_json } end end def create_error_response_to respond_to do |format| format.html { flash[:notify_error] = "࡞੒Ͱ͖·ͤΜͰͨ͠" # … ͜͏ৼΔ෣͏ 2 ߦॻ͚ͩ͘Ͱ class UsersController < ApplicationController include CrudController crud_controller User, [:new, :create] end

Slide 13

Slide 13 text

•include ͢ΔͱΫϥεϝιου crud_controller ͕ੜ͑Δ •ΞΫγϣϯϝιουΛΑ͠ͳʹఆٛͯ͘͠ΕΔ •search_one, scope ͳͲΑ͠ͳʹϝιου͕ੜ͑Δ •ϝιουΛΦʔόʔϥΠυͯ͠ϨεϙϯεΛΧελϜͰ͖Δ CrudController

Slide 14

Slide 14 text

•λΠϓ਺ܹݮʂ •΂ΜΓʂʂ …΄Μͱ͏ʹʁ ͔ΜͨΜ

Slide 15

Slide 15 text

ͭΒΈྫ

Slide 16

Slide 16 text

ɹϝιουఆ͕ٛͳ͍ͷʹͳΜ͔ಈ͘ʂʁ ҉໧తͳϝιουఆٛ class UsersController < ApplicationController crud_controller User, [:new, :create] end

Slide 17

Slide 17 text

ɹ͜ͷ @user ͸ҰମͲ͔͜Βʂʁ ҉໧తͳίʔϧόοΫ௥Ճ class UsersController < ApplicationController crud_controller User, [:new, :create] def create if @user.save create_success_response_to else create_error_response_to end end end

Slide 18

Slide 18 text

ϝιουίʔϧ෼ࢄ ɹશ෦ಡ·ͳ͍ͱΘ͔Βͳ͍ 💀 class UsersController < ApplicationController include Common::UsersController include ActionState include ActionForm include ActionUpdate include ActionApi def set_redirect_path @create_redirect_path = users_path end end module Common::UsersController extend ActiveSupport::Concern included do crud_controller User, [:edit, :update] before_action :set_redirect_path end end

Slide 19

Slide 19 text

ɹCrudController ͷίʔυಡ΋͏ͱͨ͠ΜͰ͚͢Ͳ 
 ɹϝλϓϩΑ͘Θ͔Γ·ͤΜ… ϝλϓϩ def define_create_error_response_to(_clazz, _table_name, model_name) define_method :create_error_response_to do respond_to do |format| format.html { flash[:notify_error] = "࡞੒Ͱ͖·ͤΜͰͨ͠" create_error_response_to_html } format.json { create_error_response_to_json } end end define_method :create_error_response_to_html do render self.class.instance_variable_get(:@_create_error_action) || :new end define_method :create_error_response_to_json do render json: { errors: instance_variable_get("@#{model_name}").errors.full_messages }, status: 422 end end

Slide 20

Slide 20 text

ෳࡶ •όάΛੜΈ΍͍͢ •ίʔϧόοΫॱংʹґଘ͕ൃੜ͢Δ •੬ऑੑΛੜΈ΍͍͢ঢ়ଶ •CrudController ֶशίετ͕ߴ͍ •ϝλϓϩͰՄಡੑ͕௿͍ •ೝ஌ίετ͕ߴ͍ •ϝιουͷΦʔόʔϥΠυͰ࣮ࡍͷఆ͕ٛΘ͔ΓͮΒ͍ •Fat controller ͱ૊Έ߹Θ͞ΔͱΑΓΩπ͍

Slide 21

Slide 21 text

େྔ •ར༻ίϯτϩʔϥ͸ 300 ऑ

Slide 22

Slide 22 text

ྺ࢙͋ΔϓϩδΣΫτͷͱ͋Δٕज़తෛ࠴Λ 伱ؒϓϩδΣΫτͷ 1VMM3FRVFTUTͰ౗͖ͬͨ͠࿩

Slide 23

Slide 23 text

౗͖͠ΔͨΊʹ •εΫϦϓτԽ •มߋϦεΫΛݮΒ͢ •νʔϜઓʹ͢Δ •ϞνϕʔγϣϯΛอͭ

Slide 24

Slide 24 text

౗͖͠ΔͨΊʹ •εΫϦϓτԽ •มߋϦεΫΛݮΒ͢ •νʔϜઓʹ͢Δ •ϞνϕʔγϣϯΛอͭ

Slide 25

Slide 25 text

εΫϦϓτԽ •ख࡞ۀͷఫഇ͸ແཧ •࣌ؒͱࠜؾͱूதྗ͕ඞཁ •͋͘·Ͱ伱ؒ࣌ؒͷऔΓ૊Έ •ఫഇखॱॻ͕ॻ͚ΔͳΒεΫϦϓτԽͰ͖Δ

Slide 26

Slide 26 text

ɹॻ͍ͨ

Slide 27

Slide 27 text

εΫϦϓτ 1. crud_controller .*ΞΫγϣϯ໊ ΛؚΉϑΝΠϧΛநग़ 2. 1 ͷ͏ͪରԠ͢Δςετ͕͋ΔϑΝΠϧΛநग़ 3. ίϯτϩʔϥϑΝΠϧΛจࣈྻͱͯ͠ಡΈࠐΈɺ 
 ϝιουͷಈతఆٛΛ੩తఆٛʹมߋ 4. 3 Ͱมߋͨ͠จࣈྻΛίϯτϩʔϥϑΝΠϧʹॻ͖໭͢ 5. rubocop -a ͯ͠ίϛοτΛੵΉ جຊ͸͜Ε͚ͩ

Slide 28

Slide 28 text

εΫϦϓτ 1. crud_controller .*ΞΫγϣϯ໊ ΛؚΉϑΝΠϧΛநग़ όοΫΫΦʔτͰ 
 ίϚϯυ࣮ߦ

Slide 29

Slide 29 text

1. 1 ͷ͏ͪରԠ͢Δςετ͕͋ΔϑΝΠϧΛநग़ 2. 1 ͷ͏ͪରԠ͢Δςετ͕͋ΔϑΝΠϧΛநग़ εΫϦϓτ ίϯτϩʔϥͷ 
 Ϋϥε໊Λऔಘ

Slide 30

Slide 30 text

1. 1 ͷ͏ͪରԠ͢Δςετ͕͋ΔϑΝΠϧΛநग़ 2. 1 ͷ͏ͪରԠ͢Δςετ͕͋ΔϑΝΠϧΛநग़ εΫϦϓτ ΫϥεʹରԠ͢Δ spec ͕͋Δ 
 ίϯτϩʔϥΛબͿ

Slide 31

Slide 31 text

1. 1 ͷ͏ͪରԠ͢Δςετ͕͋ΔϑΝΠϧΛநग़ 2. 1 ͷ͏ͪରԠ͢Δςετ͕͋ΔϑΝΠϧΛநग़ 3. ίϯτϩʔϥϑΝΠϧΛจࣈྻͱͯ͠ಡΈࠐΈɺ 
 ϝιουͷಈతఆٛΛ੩తఆٛʹมߋ εΫϦϓτ File.read ͯ͠ 
 จࣈྻͱͯ͠ѻ͏

Slide 32

Slide 32 text

1. 1 ͷ͏ͪରԠ͢Δςετ͕͋ΔϑΝΠϧΛநग़ 2. 1 ͷ͏ͪରԠ͢Δςετ͕͋ΔϑΝΠϧΛநग़ 3. ίϯτϩʔϥϑΝΠϧΛจࣈྻͱͯ͠ಡΈࠐΈɺ 
 ϝιουͷಈతఆٛΛ੩తఆٛʹมߋ εΫϦϓτ จࣈྻΛ੾ΓషΓ

Slide 33

Slide 33 text

2. 1 ͷ͏ͪରԠ͢Δςετ͕͋ΔϑΝΠϧΛநग़ 3. .rb ϑΝΠϧΛจࣈྻͱͯ͠ಡΈࠐΈɺ 4. 3 Ͱมߋͨ͠จࣈྻΛίϯτϩʔϥϑΝΠϧʹॻ͖໭͢ εΫϦϓτ File.write Ͱ্ॻ͖

Slide 34

Slide 34 text

3. .rb ϑΝΠϧΛจࣈྻͱͯ͠ಡΈࠐΈɺ 4. 3 Ͱมߋͨ͠จࣈྻΛ .rb ϑΝΠϧʹॻ͖໭͢ 5. rubocop -a ͯ͠ίϛοτΛੵΉ εΫϦϓτ

Slide 35

Slide 35 text

εΫϦϓτԽ ΧελϜ Cop Λ࡞ͬͯ 
 autocorrect ͢Δͷ΋ྑͦ͞͏

Slide 36

Slide 36 text

ܧଓతͳෛ࠴ฦ٫ •伱ؒ࣌ؒͰߦ͑ΔΑ͏ʹ͢Δ •ίϚϯυΛଧ͚ͭͩͰ diff ͷ࡞੒͕׬ྃ •͓खܰ •ॻ͍ͨ௨Γಈ͘ •ूதྗෆཁ MTG લʹ 10 ෼ 
 ۭ͍ͨ࣌ͱ͔

Slide 37

Slide 37 text

ܧଓతͳෛ࠴ฦ٫ GitHubActions ͳͲͰ 
 PR ͷ࡞੒·Ͱ 
 ࣗಈԽ͢Δͷ΋Αͦ͞͏

Slide 38

Slide 38 text

•εΫϦϓτʹ͢Δͱ࡞ۀखॱΛ๨ΕΒΕΔ •͍ͭͰ΋΍ΊΒΕΔ •ຊۀ͕๩͘͠ͳͬͨ࣌ •͍ͭͰ΋࠶։Ͱ͖Δ •ϋʔυϧ͕௿͍ ࣮ࡍ్தͰ 
 1 ೥ऑ์ஔͨ͠ ܧଓతͳෛ࠴ฦ٫

Slide 39

Slide 39 text

౗͖͠ΔͨΊʹ •εΫϦϓτԽ •มߋϦεΫΛݮΒ͢ •νʔϜઓʹ͢Δ •ϞνϕʔγϣϯΛอͭ

Slide 40

Slide 40 text

มߋϦεΫΛݮΒ͢ •ϘʔΠεΧ΢τɾϧʔϧ ϘʔΠεΧ΢τɾϧʔϧcϓϩάϥϚ͕஌Δ΂͖ͷ͜ͱ 
 IUUQTϓϩάϥϚ͕஌Δ΂͖ͷ͜ͱDPNΤοηΠϘʔΠεΧ΢τϧʔϧ lj✣ǟƎw㢟ŧx҆ٳƵҗźƂơơƎżƮŶƋƒa 
 NJǵƵ೑Ű೛ƬżƑƋ๝ŻŲƬŧa 
 ഠ߶֥Ǝ൳ŴೆƯůƂŧŶƋƊżb 
 ⅅŮƬᾖƉƥwźƉƒƍƬƍŧŶƋxƍƑƊżb

Slide 41

Slide 41 text

•ϘʔΠεΧ΢τɾϧʔϧΛकΒͳ͍ ϘʔΠεΧ΢τɾϧʔϧcϓϩάϥϚ͕஌Δ΂͖ͷ͜ͱ 
 IUUQTϓϩάϥϚ͕஌Δ΂͖ͷ͜ͱDPNΤοηΠϘʔΠεΧ΢τϧʔϧ lj✣ǟƎw㢟ŧx҆ٳƵҗźƂơơƎżƮŶƋƒa 
 NJǵƵ೑Ű೛ƬżƑƋ๝ŻŲƬŧa 
 ഠ߶֥Ǝ൳ŴೆƯůƂŧŶƋƊżb 
 ⅅŮƬᾖƉƥwźƉƒƍƬƍŧŶƋxƍƑƊżb มߋϦεΫΛݮΒ͢

Slide 42

Slide 42 text

มߋͷؔ৺ࣄΛগͳ͘อͭ

Slide 43

Slide 43 text

crud_controller User, [:update] 
 ͢Δͱ search_one ͕ੜ͑Δ Πϯελϯεม਺ͷηοτ͸ 
 update ಺͕Αͦ͞͏ class UsersController < ApplicationController crud_controller User, [:update] before_action :search_one, only: [:update] before_action :update_required def update if @user.update(one_params) # ... else # ... end end def search_one @user = scope.find(params[:id]) end def update_required raise UnauthorizedError unless @user.can_update? end end มߋͷؔ৺ࣄΛগͳ͘อͭ

Slide 44

Slide 44 text

search_one ΛΠϯϥΠϯʹͨ͠ ●ɹ● class UsersController < ApplicationController crud_controller User, [:update] before_action :update_required def update @user = scope.find(params[:id]) if @user.update(one_params) # ... else # ... end end def update_required raise UnauthorizedError unless @user.can_update? end end มߋͷؔ৺ࣄΛগͳ͘อͭ

Slide 45

Slide 45 text

@user ͕ nil ʹͳͬͯΤϥʔʹͳͬͨ class UsersController < ApplicationController crud_controller User, [:update] before_action :update_required def update @user = scope.find(params[:id]) if @user.update(one_params) # ... else # ... end end def update_required raise UnauthorizedError unless @user.can_update? end end มߋͷؔ৺ࣄΛগͳ͘อͭ 💀

Slide 46

Slide 46 text

•ίʔυ඼࣭ʹؔ৺͕͋Δਓ΄Ͳ͍ͭͰͰ௚ͯ͠͠·͍͕ͪ •ؔ৺ࣄ͕૿͑Δͱόάͷࠞೖʹؾ͖ͮʹ͘͘ͳΔ ࣍ͷมߋͰ௚ͦ͏ มߋͷؔ৺ࣄΛগͳ͘อͭ

Slide 47

Slide 47 text

มߋϦεΫΛݮΒ͢

Slide 48

Slide 48 text

มߋϦεΫΛݮΒ͢ ো֐Λىͨ͜͠

Slide 49

Slide 49 text

มߋϦεΫΛݮΒ͢ ͔ͨ͠ʹมߋྔ͸ 
 ଟ͔͚ͬͨͲ ςετ͕͋ͬͨͷʹ 
 Ͳ͏ͯ͠

Slide 50

Slide 50 text

ِӄੑςετ expect ͕ͳͯ͘ݕ஌Ͱ͖ͳ͔ͬͨ RSpec.describe 'PUT /users/:id' do # … it do put user_url(user), params: params end end Կ΋ςετͯ͠ͳ͍ʂʂʂ

Slide 51

Slide 51 text

ِӄੑςετ •ʮςετ͕͋Δ != ςετ͍ͯ͠Δʯঢ়ଶͩͬͨ •expectation ͷͳ͍ it Λݕ஌͢ΔΧελϜ Cop Λ࡞ͬͨ NBLJDBNFMFNQUZ@FYBNQMF@DPQ 
 IUUQTHJUIVCDPNNBLJDBNFMFNQUZ@FYBNQMF@DPQ "EEA34QFD/P&YQFDUBUJPO&YBNQMFACZSLBNVSBu1VMM3FRVFTU 
 IUUQTHJUIVCDPNSVCPDPQSVCPDPQSTQFDQVMM @r7kamura ͞ΜͷύονͰ 
 rubocop-rspec ʹऔΓࠐ·Ε 
 2.13.0 ͔Βར༻Ͱ͖·͢

Slide 52

Slide 52 text

•PR Λখ͘͢͞Δͷ͸جຊ •ϨϏϡʔ͠΍͘͢͢ΔͨΊ มߋྔΛগͳ͘อͭ

Slide 53

Slide 53 text

•ػցతͳมߋ΋ PR Λ෼ׂ͢΂͖͔ʁ •҆શੑͱίετͷόϥϯε •ࠓճ͸҆શੑΛͱͬͨ •ো֐͸ϞνϕʔγϣϯΛԼ͛Δ มߋྔΛগͳ͘อͭ ςετ͕ͳ͍ॴ΋͋Γ 
 ࣌ʑख࡞ۀ΋͋ͬͨͷͰ

Slide 54

Slide 54 text

•҆શͳมߋΛ્֐͢ΔཁҼΛ஍ಓʹഉআ͢Δ •ϨϏϡʔΞϒϧʹ͢Δ •ؔ৺ࣄΛগͳ͘อͭ •มߋΛগͳ͘อͭ •ِӄੑͷςετΛ๷͙ มߋϦεΫΛݮΒ͢

Slide 55

Slide 55 text

౗͖͠ΔͨΊʹ •εΫϦϓτԽ •มߋϦεΫΛݮΒ͢ •νʔϜઓʹ͢Δ •ϞνϕʔγϣϯΛอͭ

Slide 56

Slide 56 text

νʔϜઓʹ͢Δ •🙅 ίʔυ඼࣭ʹؔ৺͕ߴ͍ਓʹϨϏϡʔґཔ •🙆ίʔυͷΦʔφʔͬΆ͍νʔϜʹϨϏϡʔґཔ •ෛ࠴ฦ٫͕ʮίʔυ඼࣭ʹؔ৺͕ߴ͍ͱݟΒΕ͍ͯΔਓʯͷ 
 ؔ৺ࣄʹͳΔ •ෛ࠴ΛʮΈΜͳͷؔ৺ࣄʯʹ͢Δ

Slide 57

Slide 57 text

νʔϜઓʹ͢Δ rake λεΫʹͯ͠୭Ͱ΋औΓ૊ΊΔΑ͏ʹ͢Δ

Slide 58

Slide 58 text

νʔϜઓʹ͢Δ •ϝϯόʔ͕खΛڍ͛ͯ͘Εͯ 2 ਓͰऔΓ૊Ή͜ͱʹ •ϨϏϡʔ͕ര଎ͰճΔ •ਐΊํͷվળ΋ఏҊͯ͘͠Εͯഒ଎Ͱఫഇ͕ਐΉ •ਓͱҰॹʹ΍Δͱָ͍͠

Slide 59

Slide 59 text

౗͖͠ΔͨΊʹ •εΫϦϓτԽ •มߋϦεΫΛݮΒ͢ •νʔϜઓʹ͢Δ •ϞνϕʔγϣϯΛอͭ

Slide 60

Slide 60 text

ϞνϕʔγϣϯΛอͭ •๞͖Δ •׆ಈͷҙٛʹٙ໰Λ࣋ͪ࢝ΊΔ ΋͏ࠔ͍ͬͯΔਓ 
 ͍ͳ͍ͷͰ͸ʁ

Slide 61

Slide 61 text

ϞνϕʔγϣϯΛอͭ •ਐḿΛݟ͑ΔԽ͢Δ •Կ % ऴΘ͔ͬͨ ਺ࣈ͸ڧ͍

Slide 62

Slide 62 text

ϞνϕʔγϣϯΛอͭ •๙Ίͯ΋Β͏

Slide 63

Slide 63 text

๙Ίͯ΋Β͏

Slide 64

Slide 64 text

๙Ίͯ΋Β͏ ڵຯؔ৺Λ 
 ࣋ͬͯ͘ΕͯͨΜͩͳ͊ ։ൃຊ෦ࣗຫେձͰ 
 CrudController ఫഇ׬ྃΛࣗຫͨ࣌͠ͷ൓Ԡ

Slide 65

Slide 65 text

👋

Slide 66

Slide 66 text

·ͱΊ ҆શʹɾָ͘͠Ͱ͖Δํ๏Λ୳͢ ܧଓੑ

Slide 67

Slide 67 text

)BQQZ)BDLJOH

Slide 68

Slide 68 text

͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠