Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Simplicity on Rails -- RDB, REST and Ruby

Simplicity on Rails -- RDB, REST and Ruby

Kaigi on Rails 2023の登壇資料です。

https://kaigionrails.org/2023/talks/moro/

実世界のRailsアプリケーションをシンプルに保つための方法を、Railsが提供する機能群をもとに考察します。

実世界の、特に仕事で開発するRailsアプリへの要求は様々のものがあり、Railsの豊富な機能群をもっても日々苦労して開発しているかと思います。 そんな中でも、Railsが得意とするような設計に落とし込むことで、複雑な要求をシンプルな実装で実現できると感じています。

本講演では、Railsが提供する機能のうち、「RDB」「REST」「Ruby」という要素を軸に、実世界の要求をシンプルに実装するための考え方を紹介します。

MOROHASHI Kyosuke

October 27, 2023
Tweet

More Decks by MOROHASHI Kyosuke

Other Decks in Programming

Transcript

  1. “ • : • 時 存在 、存在 <登録> •名前 持

    。 • 扱 「時」 扱 「時」 違 、 瞬間 刻印 、 
 有効 存在 期間 表現 。 • : •繰 返 ⾏ ⾏為。 時起 <記録> •例) ⼊荷、発注、etc •時刻 ( ) 持 。 •多 場合、 使 ⾏ •名前 ( ⾃体 ⾏為 名前 ) 持 %#ઃܭษڧձ λϫʔζΫΤετࣾ࿨ాলೋ͞ΜΛઌੜʹΉ͔͑ͨษڧձͷϝϞ 
 IUUQTHJTUHJUIVCDPNTVOBPU
  2. ྫ,BJHJͷΤϯςΟςΟ conferences id name location start_at end_at *timestamps users id

    name *timestamps registrations id conference_id user_id *timestamps
  3. “ ⾃体 独⽴ 
 扱 場合 、中間 join 使 has_many

    :through 
 設定 。 
 
 何 特別 必要 
 場合 、join 不要 has_and_belongs_to_many 
 使 ⽅ 。 3BJMTΨΠυ"DUJWF3FDPSEͷؔ࿈෇͚ 
 IBT@NBOZUISPVHIͱIBT@BOE@CFMPOHT@UP@NBOZͷͲͪΒΛબͿ͔ IUUQTSBJMTHVJEFTKQBTTPDJBUJPO@CBTJDTIUNM
  4. ΠϕϯτΤϯςΟςΟΛݟग़ͯ͠ɺ࢖͏ w ΠϕϯτΤϯςΟςΟΛݟग़͠ɺUISPVHIͰࢦఆͯ͠ଟରଟͷؔ܎Λ࡞Δ w ࣮ੈքͷαʔϏεͰ͸ɺ͜ͷΠϕϯτΤϯςΟςΟ͕Ͱ͖Δ͜ͱ͕ɺ 
 ॏཁͳίϯόʔδϣϯϙΠϯτʹͳ͍ͬͯΔ͜ͱ΋ଟ͍ w ྫΧϯϑΝϨϯεࢀՃొ࿥αΠτʹ͓͚Δʮొ࿥ʯ w

    ΧϯϑΝϨϯεͱϢʔβʔ͸ɺ୯ʹଟରଟͳͷͰͳ͘ʮొ࿥͍ͯ͠Δʯؔ܎͕͋Δͷͩ w ͦͯͦ͠ͷׂʹɺ׳Εͳ͍ͱൃݟͮ͠Β͍ w ࿩ऀ͸ɺӋੜষ༸ʮָʑ&3%Ϩοεϯʯ ᠳӭࣾ  Ͱֶͼ·ͨ͠ɻIUUQTXXXTFTIPQDPNQSPEVDUEFUBJM
  5. ొ࿥ͨ͠ίτSFHJTUSBUJPOT class User < ApplicationRecord has_many :registrations has_many :conferences, through:

    :registrations end class Registration < ApplicationRecord belongs_to :user belongs_to :conference end conferences id name location start_at end_at *timestamps users id name *timestamps registrations id conference_id user_id *timestamps
  6. ΠϕϯτΤϯςΟςΟΛݟग़͢ͱͰ͖Δ͜ͱ UserMailer.registration_accepted(@user, @conference, at: Time.current).deliver_later # => #{@user.name}༷ɺ#{I18n.l(at)}ʹ#{@conference}΁ͷࢀՃΛड͚෇͚·ͨ͠ UserMailer.registration_accepted(@registration).deliver_later w

    SFHJTUSBUJPOΛݟग़͍ͯ͠ͳ͍৔߹ɺ!VTFSͱ!DPOGFSFODF΍ɺλΠϜελϯϓΛݸผʹ࣋ͪճΔඞཁ͕͋Δ w !VTFS͸΄Μͱʹ!DPOGFSFODFొ࿥͍ͯ͠Δ ࠶νΣοΫͨ͘͠ͳΒͳ͍  w λΠϜελϯϓ΄ΜͱʹDVSSFOUͰ͍͍ ϦτϥΠ͢Δͱ͖Ͳ͏͢Δ  w SFHJTUSBUJPO͕͋Ε͹ɺʮొ࿥ͨ͠ίτʯΛίʔυ্Ͱͦͷ··औΓճͤΔ w VTFSͱDPOGFSFODFΛ୧ΕΔɻ྆ऀΛ୧ΕΔ͜ͱ͸ɺ%#ͷࢀর੔߹ੑ੍໿Ͱ΋ࢧ͑ΒΕΔ w SFHJTUSBUJPOTDSFBUFE@BUΛొ࿥೔࣌ͱΈͳͤΔ υϝΠϯͰେࣄͳʮొ࿥ͨ͠ίτʯΛίʔυ্ʹදݱͰ͖Δ
  7. ଓΠϕϯτΤϯςΟςΟΛݟग़͢ͱͰ͖Δ͜ͱ w SFHJTUSBUJPOTʹΧϥϜΛ௥Ճͯ͠ɺ෇Ճ৘ใΛ΋ͨͤΒΕΔ w ొ࿥൪߸ͱ͔ɺొ࿥࣌ͷਃ͠ૹΓAOPUFAͱ͔ɺొ࿥छผ ݱ஍ࢀՃYPSΦϯϥΠϯࢀՃ ͱ͔ w ޙଓΠϕϯτͷ਌ϨίʔυʹͳΕΔ w

    ྫࢀՃඅ༻Λܾࡁͨ͠ίτQBZNFOUT ౰೔ʹࢀՃͨ͠ίτBUUFOEBODFTͳͲ w ACFMPOHT@UPSFHJTUSBUJPOAͳ"3ϞσϧͱͳΔ w ొ࿥ͨ͜͠ͱࣗମΛه࿥Ͱ͖Δ w ؂ࠪϩάʹ࢒ͨ͠Γɺίϯόʔδϣϯܦ࿏ͷϩάʹ࢒ͨ͠Γͱ͔
  8. ίτΛϦιʔεͱͯ͠ѻ͏ resources :conferences do resource :registration, only: [:new, :create] end

    resources :registrations w ͜ͷྫͰ͸ɺΧϯϑΝϨϯεʹࢀՃొ࿥Ͱ͖Δͷ͸ճ͚ͩొ࿥ܥͷ SFHJTUSBUJPO͸୯਺SFTPVSDF ొ࿥ͷ63-ΛΦγϟϨʹωετ͢ΔͷΛ 
 ΍ΊΔͱ΋ͬͱγϯϓϧʹͰ͖Δ
  9. ൺֱ༻3&45͡Όͳ͍৔߹ʹΑ͘ݟΔ΍ͭ resources :conferences do # POST /conferences/:conference_id/register # => conferences#register

    post :register end w A$POGFSFODFT$POUSPMMFSSFHJTUFSAΞΫγϣϯΛఆٛͯ͠͠·͏ w ਺͕૿͑ΔͱϧʔςΟϯά΋ෳࡶͳΔ͠ɺ$POGFSFODFT$POUSPMMFS΋ංେԽ͢Δ
  10. ΞϓϦέʔγϣϯঢ়ଶͷભҠ w ΞϓϦέʔγϣϯঢ়ଶͷભҠΛɺίτͷϦιʔεʹ·ͭΘΔϖʔδભҠͰ 
 දݱ͢Δ w ྫʮΧϯϑΝϨϯεৄࡉදࣔʯঢ়ଶͰ͸ɺొ࿥ϘλϯΛදࣔ͢Δɻ 
 ϘλϯΛԡ͢ͱʮొ࿥࣌৘ใͷೖྗ଴ͪʯঢ়ଶʹભҠ͢Δ w

    ͜ΕΛAB<ISFGDPOGFSFODFTLBJHJPOSBJMTSFHJTUSBUJPOOFX>AͳϦϯΫΛఏࣔ͢Δ͜ͱɺ 
 ͦΕ୧ͬͯ΋Β͏͜ͱͰදݱ͢Δ w ASFTPVDFTAએݴ͸͜ͷঢ়ଶભҠͷϧʔςΟϯά΋ఆٛͯ͘͠Ε͍ͯΔ
  11. ͞ΒʹʮίτʯΛϦιʔεͱͯ͠ΈΔ w ࢧ෷͍ͯ͠΄͍͠ࢧ෷͍ͱ͍͏ίτΛ࡞ͬͯཉ͍͠ w A(&5SFHJTUSBUJPOTSFHJTUSBUJPO@JEQBZNFOUOFXAͰࢧ෷͍Ҋ಺Λදࣔ͠ w ͔Βͷɺܾࡁ͍ͨ͡͸ಋઢ͸֎෦αʔϏε࿈ܞ͠ w ໭ͬͯ͘ΔA(&5SFHJTUSBUJPOTSFHJTUSBUJPO@JEQBZNFOUAͰࢧ෷͍׬ྃͷࢫΛදࣔ͢Δ w

    ༧ఆͷΩϟϯηϧ͸ɺA$BODFMMBUJPOAΛDSFBUF͢Δͱ΋ߟ͑ΒΕΔ͠ɺ A3FHJTUSBUJPOAΛEFTUSPZ͢Δͱ΋ߟ͑ΒΕΔ w ͜ͷ͋ͨΓ΋ΩϟϯηϧϙϦγʔʹΑͬͯߟ͑ΒΕΔ w ର৅αʔϏεʹͱͬͯԿ͕ద੾͔ɺߟ͑·͠ΐ͏ w ࢧ෷͍ͳ͠ͳΒ3FHJTUSBUJPOΛEFTUSPZɺࢧ෷͍ࡁΈͩͬͨΒฦۚϦΫΤετΛOFX͢Δɺͱ͔
  12. 3BJMTͷؾ࣋ͪʹͳͬͯߟ͑Δ w "3#BTFͷΦϒδΣΫτΛੜ੒͢Δͱ͖ͷΠϯλʔϑΣʔε͕͜Ε w ͷͪʹಉ༷ͷ*'Λ࡞ΔͨΊͷ"DUJWF.PEFM ҎԼ".P ΋ग़͍ͯΔ w ͞Βʹద੾ʹೖྗΛߜΔͨΊͷػߏͱͯ͠4USPOH1BSBNFUFST΋͋Δ w

    ͍ΖΜͳํ͕ࣜ͋Δ͏ͪɺNBTTBTTJHONFOUͱ૬ੑͷྑ͍΍͕ͭ࠾༻͞Εͨ ΤϯτϦϙΠϯτʹBUUSJCVUFTͷ)BTI ͷΑ͏ͳ΋ͷ Λ౉ͯ͠ 
 NBTTBTTJHONFOU͠ɺϑΝαʔυΛݺͿͷ͕جຊߏ଄
  13. ྫ͑͹ొ࿥࣌ʹऔΔ৘ใΛ૿΍͢ def create @registration = current_user.registrations.build( conference: Conference.find_by!(name: params[:conference_id]), **params.require(:r10n).permit(:note,

    :attend_type) ) @registration.save! end උߟ OPUF ͱࢀՃछผ BUUFOE@UZQF*/@1&340/c0/-*/& ͱΛ 
 ೖྗՄೳʹͯ͠ΈΔ w ༨ஊ"$1BSBNFUFSTUP@IBTIΛ Ͱ౉ͯ͠ύϥϝʔλΛ௥Ճ͢Δ΍ͭɺॻ͖ຯ͕ྑͯ͘޷͖Ͱ͢ SOʹSFHJTUSBUJPOͷུͰ͢
  14. ίϯτϩʔϥͰ΍ͬͯ΋͍͍͚Ͳʜ def create @registration = current_user.registrations.build( conference: Conference.find_by!(name: params[:conference_id]), **params.require(:r10n).permit(:note,

    :attend_type) ) @registration.save! UserMailer.registration_accepted(@registration).deliver_later OrganizerMailer.registration_accepted(@registration).deliver_later if @registration.attend_type.in_person? SeatAllocationJob.perform_later(@registration) … rescue ActiveRecord::RecordInvalid => ex ... end
  15. ".PΛ࢖ͬͯ*'ͷ͍ۙผϨΠϠΛಋೖ͢Δ w ίϯετϥΫλʹɺBUUSJCVUFTͷ)BTIΛ౉͢ w ͦͷΦϒδΣΫτͰ͸ೖྗηοτͷଥ౰ੑΛݕূ͢Δ w ೖྗ͕ଥ౰Ͱͳ͍৔߹ɺαʔϏεར༻ऀʹݟͤΒΕΔΤϥʔϝοηʔδΛੜ੒͢Δ w ଥ౰Ͱ͋Δ৔߹ɺ΍Γ͍ͨॲཧͷϑΝαʔυͱͳΔϝιουΛ࣮ߦ͢Δ w

    ͭ·ΓϑΥʔϜΦϒδΣΫτͱ͍͏͔αʔϏεΫϥεͱ͍͏͔ͷಋೖ w ϑΥʔϜͱݺশ͢Δ΄͏͕޷Έ w ͜ͷ૚΁ͷೖྗ͸ɺϢʔβʔೖྗͷܗɺ͢ͳΘͪϑΥʔϜͱҰக͓ͤͯ͘͞ͱָͩͱࢥ͏ͨΊ w ࣮༻্͸੒Ռ෺ͷू໿ϧʔτͱͳΔΦϒδΣΫτ΁ͷΞΫηα΋͋Δͱศར
  16. def create @form = RegistrationForm.new( user: current_user:, conference: Conference.find_by!(name: params[:conference_id])

    **params.require(:r10n).permit(:note, :attend_type) ) @form.call redirect_to form.registration rescue ... ".PΛ࢖ͬͯ*'ͷ͍ۙผϨΠϠΛಋೖ͢Δ ʮ3FHJTUSBUJPO'PSN͸ొ࿥ϑΥʔϜΛද͢ΦϒδΣΫτͰ͢ʯ
  17. class RegistrationForm < ApplicationForm attribute :user, :conference, :note, :attend_type validates

    :attend_type, inclusion: {in: ...} attr_reader :registration def call @registration = user.registration.create!(...) notify_registration! if @registration.attend_type.in_person? SeatAllocationJob.perform_later(@registration) ".PΛ࢖ͬͯ*'ͷ͍ۙผϨΠϠΛಋೖ͢Δ ".P.PEFMͱ͔".P"UUSJCVUFͱ͔Λ JODMVEFͨ͠ബ͍εʔύʔΫϥε
  18. ;ͭ͏ͷ30ͳͷͰࣗಈςετ΋ॻ͖΍͍͢ w "SSBOHFηοτΞοϓ w ίϯετϥΫλʹɺBUUSJCVUFTͷ)BTIΛ౉͢ w "DUॲཧ࣮ߦ w ϑΝαʔυΛݺͼग़ͯ͠ॲཧͷҰ࿈͕૸Δ w

    "TTFSU݁Ռݕূ w ࡞Γ͍ͨσʔλͷू໿ϧʔτʹΞΫηεͰ͖ΔͷͰɺ 
 ͔ͦ͜ΒҰ࿈ͷσʔλάϥϑ͕ҙਤ௨ΓͰ͖͍ͯΔ͔ΛݕূͰ͖Δ w όϦσʔγϣϯΤϥʔʹͳΔೖྗύλʔϯ΋௥Ճ͠΍͍͢ w ޙॲཧ͕࣮ߦ͞ΕΔ͔ͳͲ΋ςετͰ͖Δ
  19. ίτͷDSFBUFͱ%#ӬଓԽͱͷؒ w 3FHJTUSBUJPOT$POUSPMMFSDSFBUFΛड͚ΔΞΫγϣϯͱͯ͠ɺ 
 */4&35JOUPSFHJTUSBUJPOTҎ֎ͷ͜ͱ·Ͱ΍͍͍ͬͯͷ  w ͦͷαʔϏεͷ੹຿ͱͯ͠ʮࢀՃొ࿥͢Δ͜ͱʯ෇ਵ͢ΔॲཧͰ͋Ε͹΍͍͍ͬͯ w Ή͠Ζ΍Δ΂͖

    w 3FHJTUSBUJPOϦιʔεͷDSFBUF͸ɺʰαʔϏεར༻ऀͷߟ͑Δʮొ࿥͢Δ͜ͱʯʱΛද͍ͯ͠Δ w ҧ࿨ײ͕ग़͖ͯͨΒɺίʔυͷ༷ࢠΛΈͯநग़͍ͯ͘͠ w 3VCZͳͷͰ w ΠϯλʔϑΣʔε͕҆ఆ͓ͯ͠Γςετ΋ॆ࣮ͤ͞΍͍͢ͷͰɺϦϑΝΫλϦϯά͠΍͍͢͸ͣ