Slide 1

Slide 1 text

How to safely upgrade Rails Rails Upgrade Casual Talks @k0kubun

Slide 2

Slide 2 text

ࣗݾ঺հ • Takashi Kokubun (@k0kubun) • ΫοΫύου ٕज़෦ ։ൃج൫άϧʔϓ • Rails 4.1 -> 4.2 ͷΞοϓάϨʔυΛ్த͔Β୲౰

Slide 3

Slide 3 text

ࠓ೔࿩͢͜ͱ • CookpadͷRailsΞοϓάϨʔυͷྲྀΕ • ϦϦʔεલͷ4ஈ֊ͷಈ࡞֬ೝ • Cookpad͕ૺ۰ͨ͠Rails 4.2ͷόά

Slide 4

Slide 4 text

Cookpadͷ RailsΞοϓάϨʔυͷྲྀΕ Rails 4.1 → 4.2 ͷྫ

Slide 5

Slide 5 text

CIʹRails 4.2༻δϣϒΛ༻ҙ • ·ͣ͸ςετΛ௨͢ • @a_matsuda ͞Μ͕fail࢒Γ5ݸ·ͰݮΒͨ͠ͷΛҾ͖ܧ ͗ɺ࢒ΓΛ௨͢ͷΛ୲౰ • ϦϦʔε͢Δ·Ͱmaster͔Βrebase͠ଓ͚Δrails42ϒϥϯ ν͕ςετΛ௨Δঢ়ଶΛอͭͨΊɺCIʹδϣϒΛ༻ҙ͢Δ • CIαʔόʔͷϦιʔε͕ۭ͍͍ͯΔૣேʹ࣮ߦ͢Δ

Slide 6

Slide 6 text

cherry-pick • σϓϩΠޙͷ໰୊ͷ੾Γ෼͚Λ༰қʹͨ͠ΓɺϨϏϡʔ ͷෛ୲ܰݮͷͨΊϓϧϦΛ෼ׂ͢Δ • 4.1, 4.2྆ํͰಈ͘मਖ਼͸ઌʹग़ͯ͠͠·͏ • ઌʹΞοϓάϨʔυͰ͖Δgem͸ઌʹ΍͓ͬͯ͘

Slide 7

Slide 7 text

cherry-pick fail࢒Γ5ͷ࣌఺ 1308 additions 1087 deletions 650 additions 477 deletions Ϛʔδͨ͠ϓϧϦ ໿൒෼

Slide 8

Slide 8 text

ඇޓ׵ͷҰ࣌త཈੍ • Rails 4.2ͷAuthenticity Tokenͷมߋ͸ϩʔϧόοΫͰ͖ ͳ͍ͷͰɺRails 4.1ͷڍಈʹϞϯΩʔύονͰݻఆ • Masked Authenticity Token ͰຖճϥϯμϜͳtokenΛ ฦ͢Α͏ʹͳΔͷͰɺޙํޓ׵ੑ͕ͳ͍ • Rails 4.2σϓϩΠޙམ͍͔ͪͭͯΒ͜ͷύονΛ֎ͨ͠

Slide 9

Slide 9 text

ඇޓ׵ͷҰ࣌త཈੍ ActiveSupport.on_load(:action_controller) do module ActionController module RequestForgeryProtectionExtension def form_authenticity_token session[:_csrf_token] ||= SecureRandom.base64(32) end end Base.prepend RequestForgeryProtectionExtension end end • Masked Authenticity TokenͷมߋΛ཈੍͢Δύον

Slide 10

Slide 10 text

ಈ࡞֬ೝ • ن໛͕େ͖͘ɺશͯͷӨڹൣғͷ೺Ѳ͕ࠔ೉ͳͷͰɺ • ؔ܎෦ॺ͕ಈ࡞֬ೝͰ͖ΔظؒΛ2िؒఔ౓ઃ͚Δ • ຊ൪ʹ͍ۙ؀ڥͰΤϥʔ͕ग़Δ͔֬ೝ͢Δ • ৄࡉ͸ޙͷεϥΠυͰ

Slide 11

Slide 11 text

cookpad.com ͷϦϦʔε • લ೔໷͔ΒίʔυϑϦʔζ • ӨڹΛখ͘͢͞ΔͨΊɺޕલ7࣌ग़ࣾɾ8࣌σϓϩΠ • ͳΔ΂͘τϥϑΟοΫ͕௿͍࣌ؒଳʹσϓϩΠ͍ͨ͠ ͕ɺؔ܎ऀશһʹਂ໷ͷग़ࣾΛཁٻ͢Δ΄ͲͰ͸ͳ͍

Slide 12

Slide 12 text

ෳ਺ϒϥϯνӡ༻ • ಉ͡ϦϙδτϦʹ cookpad.com ΛؚΉ8ͭͷΞϓϦ͕ಉډ ͍ͯ͠Δ͕ɺҰ౓ʹશ෦ϦϦʔε͠ͳ͍ • 8ͭͷΞϓϦ: ؅ཧը໘, όον, API, ϫʔΧʔ, ... • ໿1ि͔͚ؒͯஈ֊తʹσϓϩΠ͢Δ • શͯRails 4.2ʹҠߦ͢Δ·Ͱ͸Rails 4.1༻ͷrails41ϒϥϯν Λ࡞ΓmasterͷมߋΛόοΫϙʔτ͠ଓ͚Δ

Slide 13

Slide 13 text

σϓϩΠޙͷ؂ࢹ • ҎԼͷ2ͭΛ؂ࢹ͢Δ • Sentry: Τϥʔ • ࣗࣾ੡ϞχλϦϯάπʔϧ: ϨεϙϯελΠϜ

Slide 14

Slide 14 text

σϓϩΠޙͷ؂ࢹ ϨεϙϯελΠϜ Τϥʔ

Slide 15

Slide 15 text

ΞοϓάϨʔυϑϩʔͷ·ͱΊ • ςετΛ௨͠CIʹδϣϒΛ༻ҙ͢Δ • ϓϧϦͷ෼ׂ΍ඇޓ׵ͷ཈੍ʹΑΓมߋͷཻ౓Λখ͘͢͞Δ • 2िؒಈ࡞֬ೝ • ෳ਺ͷΞϓϦΛ1ि͔͚ؒͯஈ֊తʹϦϦʔε͢Δ • σϓϩΠޙɺϨεϙϯελΠϜͱΤϥʔΛ؂ࢹ

Slide 16

Slide 16 text

ϦϦʔεલͷ4ஈ֊ͷಈ࡞֬ೝ

Slide 17

Slide 17 text

1. ։ൃ༻ͷݕূ؀ڥͰͷ֬ೝ • ։ൃ༻ͷDBΛࢀর͢Δݕূ؀ڥʹRails 4.2ͷϒϥϯνΛ σϓϩΠ • ΞοϓάϨʔυؔ܎ͳ͘΋ͱ΋ͱ೚ҙͷϒϥϯνΛ೚ҙ ͷαϒυϝΠϯʹσϓϩΠͰ͖ΔΑ͏ʹͳ͍ͬͯΔ • ྫ: https://rails42.staging.ʙ/ • ͜ͷ؀ڥͰ֤෦ॺʹಈ࡞֬ೝΛґཔ

Slide 18

Slide 18 text

2. ຊ൪؀ڥͰͷखಈ֬ೝ • Rails 4.2༻ͷϒϥϯνΛσϓϩΠͨ͠ຊ൪؀ڥΛ༻ҙ • Webͷ৔߹ • ಛผͳΫοΩʔΛ࣋ͭ৔߹ͷΈͦͷ؀ڥʹϓϩΩγ͞Ε ΔΑ͏ʹͯ͠खಈͰಈ࡞֬ೝ • ϞόΠϧΞϓϦ༻APIͷ৔߹ • ಛผͳϦΫΤετϔομʔΛ࣋ͭ৔߹ͷΈϓϩΩγ

Slide 19

Slide 19 text

2. ຊ൪؀ڥͰͷखಈ֬ೝ *OUFSOFU "QBDIF SBJMT SBJMT ௨ৗͷΫοΩʔ foocookie=1 • Webͷ৔߹ consoleͰద౰ʹ $.cookie('foocookie', 1) CSPXTFS

Slide 20

Slide 20 text

2. ຊ൪؀ڥͰͷखಈ֬ೝ • ϞόΠϧΞϓϦ༻APIͷ৔߹ *OUFSOFU "QBDIF SBJMT SBJMT .PCJMF "QQ NJUNQSPYZ ϦΫΤετϔομʹ X-Foo=1 Λ͚ͭΔ X-Foo=1 ී௨ͷϦΫΤετ

Slide 21

Slide 21 text

3. Kage • https://github.com/cookpad/kage • ͋ΔαʔόʔʹདྷͨϦΫΤετΛRails 4.2ΛσϓϩΠͨ͠΋ͷʹ΋ྲྀ ͠ɺDBͳͲ΁ͷॻ͖ࠐΈ͸཈ࢭ͢Δ • MySQLͳΒBLACKHOLEɺmemcached ͳͲ͸ִ཭͢Δ • Τϥʔͷ༗ແ΍ύϑΥʔϚϯεΛ֬ೝ͢Δ • tail -f production.log • nginxͷϨεϙϯελΠϜ΍unicornͷϦιʔε࢖༻ྔ

Slide 22

Slide 22 text

3. Kage *OUFSOFU "QBDIF SBJMT ,BHF SBJMT ಉ͡ϦΫΤετ Ϩεϙϯε͸ࣺͯΔ Ϣʔβʔʹฦ͢

Slide 23

Slide 23 text

4. Production Test • CI੒ޭޙࣗಈతʹσϓϩΠ͞ΕΔɺ΄΅ຊ൪ͷ؀ڥ • ΞοϓάϨʔυؔ܎ͳ͍ͭ͘Ͱ΋͜͜Ͱಈ࡞֬ೝΛ͔ͯ͠ ΒσϓϩΠ͢Δ

Slide 24

Slide 24 text

Cookpad͕ૺ۰ͨ͠Rails 4.2ͷόά

Slide 25

Slide 25 text

Encoding::UndefinedConversionError • ϚϧνόΠτจࣈྻ͔ͭ൒֯ͷ"%"ΛؚΉϑΝΠϧ໊ͷϑ ΝΠϧΛΞοϓϩʔυͨ͠ࡍʹग़ΔϨΞͳΤϥʔ • Rails 4.1 → 4.2 ΞοϓάϨʔυ࣌ʹ།Ұग़ͨΤϥʔ • ຊՈʹ @eagletmt ͕ϓϧϦΛ౤͛ɺ4.2.4ʹऔΓࠐ·Εͨ • https://github.com/rails/rails/pull/21131

Slide 26

Slide 26 text

Encoding::UndefinedConversionError

Slide 27

Slide 27 text

undefined method `unpack' for nil:NilClass • Rails 4.2.4ͱRuby 2.0.0ͷ૊Έ߹ΘͤͰͷΈൃੜ͢ΔΤϥʔ • Ruby 2.0.0ͩͱ ERB::Util.url_encode ಺ͷgsubͷϒϩο ΫͰ $& Λࢀর͢Δ͕ɺAS::SafeBuffer ͩͱಈ͔ͳ͍ • ຊՈʹ @k0kubun ͕ϓϧϦΛ౤͛ɺ4.2.5ʹऔΓࠐ·Εͨ • https://github.com/rails/rails/pull/21402

Slide 28

Slide 28 text

undefined method `unpack' for nil:NilClass

Slide 29

Slide 29 text

·ͱΊ • Ұ౓ʹσϓϩΠ͞ΕΔมߋΛখ͘͢͞Δ • ͳΔ΂͘ଟ͘ͷखͰɺͳΔ΂͘ຊ൪ʹ͍ۙ؀ڥͰಈ࡞֬ೝ • ΫοΫύουͰૺ۰ͨ͠Rails 4.2ͷόά͸ຊՈͰमਖ਼ࡁ