Slide 1

Slide 1 text

ϚϧνςφϯτΞʔΩςΫνϟ ✖ &MJYJS1IPFOJY 4BB4ͷ࠷લઢ GVLVPLBFY Ώ͔͡Θ!ZVKJLBXB@QZ

Slide 2

Slide 2 text

w ໊લ w ઒্༞࢘ Ώ͔͡Θ w ॴଐ w ΧϥϏφςΫϊϩδʔ w ৬छ w όοΫΤϯυΤϯδχΞ w 5XJUUFS w !ZVKJLBXB@QZ w ීஈͷ͓࢓ࣄ w &MJYJS1IPFOJYΛ࢖ͬͨ8FC։ൃ w ޷͖ͳݴޠ w &MJYJS w 1ZUIPO w ࠷ۙͷ׆ಈ w 1Z$PO,ZVTZVͷϝϯόʔͱͯ͠׆ಈத ࣗݾ঺հ

Slide 3

Slide 3 text

໨࣍ w &MJYJSͱ1IPFOJYʹ͍ͭͯ w ࠷ۙͷฐࣾͷ&MJYJSࣄ৘ w ࠷ۙͷੈͷதͷ&MJYJSࣄ৘ w Ϛϧνςφϯτͱ͸ʁ w &MJYJS1IPFOJYͰϚϧνςφϯτΛ͢Δʹ͸ʁ w ։ൃ؀ڥʹ͍ͭͯ w ࣮૷ฤBQBSUNFOUFY w ·ͱΊ

Slide 4

Slide 4 text

w ؔ਺ܕݴޠ w &SMBOH7. #&". ্Ͱಈ͘ w όʔδϣϯ͸ w 8FCϑϨʔϜϫʔΫʢ3BJMT΍%KBOHPΈ͍ͨͳײ͡ʣ w 3BJMTͷTDB⒎PME͕Ͱ͖Δ &MJYJSͱ1IPFOJYʹ͍ͭͯ

Slide 5

Slide 5 text

࠷ۙͷฐࣾͷ&MJYJSࣄ৘ w ͜Ε·Ͱʢ݄͝Ζ·Ͱʣ w 1ZUIPOΛ࢖ͬͨγεςϜ։ൃ w ͜Ε͔Βʢ݄͔Βʣ w &MJYJS1IPFOJYΛ࢖ͬͨγεςϜ։ൃ w ؔ਺ܕݴޠͷอकੑɾฒྻॲཧͳͲͷߴ଎ੑʹັྗΛײ͡બఆɺγεςϜͷί Ξ෦෼͸&MJYJSΛ࢖͏ɻ͍͟ͱͳΕ͹&SMQPSUΛ࢖͍ɺ1ZUIPO౳ଞͷݴޠͱͷ ૊Έ߹Θͤ΋Մೳ w ࢀߟɿʮ&MJYJSʴ,FSBTʹखܰʹߴ଎ͳʮσʔλαΠΤϯεϓϥοτϑΥʔ Ϝʯʙ'MPXͰͷϚϧνίΞ׆༻ࣄྫʙʯIUUQTRJJUBDPNQJBDFSF JUFNTDBGCDFECD⒎

Slide 6

Slide 6 text

࠷ۙͷฐࣾͷ&MJYJSࣄ৘ w ͜Ε·Ͱ࢖ͬͯΈͯͷײ૝ w ϙδςΟϒ 㱼ʆ w 1IPFOJYͰ3BJMTฒΈͷര଎։ൃ͕Ͱ͖Δ w 5%%ʢςετۦಈ։ൃʣ͕͠΍͍͢ w ίʔυ͕ಡΈ΍͍͢ʢอक͠΍͍͢ʣ w ॲཧ଎౓͕଎͍ʢ1ZUIPOͩͱؾʹͳΔ͕࣌͋Δʣ w ڧྗͳύλʔϯϚονͰίʔυྔ͕গͳ͘ࡁΜͩ w ωΨςΟϒ ʀ㱼ʀ w ৭ʑͳαʔϏεͷެࣜͷϥΠϒϥϦ͸·ͩগͳ͍ w υΩϡϝϯτ΋গͳ͍ʢ೔ຊޠ͸ಛʹʣ ॻ͖΍͍͢ɾಡΈ΍͍͢ɾύΠϓॲཧָ͕͍͠

Slide 7

Slide 7 text

࠷ۙͷੈͷதͷ&MJYJSࣄ৘

Slide 8

Slide 8 text

࠷ۙͷੈͷதͷ&MJYJSࣄ৘ w ($1ʢ(PPMHF$MPVE1MBUGPSNʣͰ&MJYJS͕࢖͑ΔΑ ͏ʹͳΓ·ͨ͠ʂԼهͷ63-Ͱ͸1IPFOJYΛ࢖͏·Ͱͷ νϡʔτϦΞϧ͕ܝࡌ͞Ε͍ͯ·͢ɻڵຯͷ͋Δํ͸ͥͻ ৮ͬͯݟ͍ͯͩ͘͞ɻ w νϡʔτϦΞϧɿIUUQTDMPVEHPPHMFDPNDPNNVOJUZ UVUPSJBMTFMJYJSQIPFOJYPOHPPHMFBQQFOHJOF

Slide 9

Slide 9 text

࠷ۙͷੈͷதͷ&MJYJSࣄ৘ w ༸ॻ͕࣍ʑͱൢച༧ఆ ൃച ൃച ˞࣌఺ͷ৘ใ ൃച &MJYJS'PSVNݟͯΔͱ҆͘ങ͑ΔՄೳੑ͋Γʂ
 IUUQTFMJYJSGPSVNDPNUGVODUJPOBMXFCEFWFMPQNFOUXJUI FMJYJSPUQBOEQIPFOJYQSBHQSPH

Slide 10

Slide 10 text

࠷ۙͷੈͷதͷ&MJYJSࣄ৘ w ༸ॻ͕࣍ʑͱൢച༧ఆ ൃച ˞࣌఺ͷ৘ใ ൃച ଓʑͱຊ͕ग़൛͞ΕɺੈքతϒʔϜ౸དྷʂʁ

Slide 11

Slide 11 text

Ϛϧνςφϯτͱ͸ʁ w Ϛϧνςφϯτͱ͸ʜ w ̍ͭͷγεςϜʹෳ਺ͷςφϯτΛಉډ͍ͤͯ͞Δํࣜ ͷ͜ͱ w اۀ΍νʔϜͰ࢖͏4BB4͕Πϝʔδ͠΍͍͢ͱ͜Ζ ʢ#BDLMPHɺ+*3"ɺ2JJUBνʔϜͳͲʣ w ϚϧνςφϯτԽʹ͸͍͔ͭ͘ͷ෼཭ͷछྨ͕͋Δ

Slide 12

Slide 12 text

Ϛϧνςφϯτͱ͸ w ᶃར༻ऀ͝ͱʹݸผΞϓϦͱݸผͷσʔλϕʔε "ࣾ #ࣾ $ࣾ "ࣾͷࣾһ #ࣾͷࣾһ $ࣾͷࣾһ ӡ༻ίετ͕ߴ͘εέʔϧ͠ʹ͍͘

Slide 13

Slide 13 text

Ϛϧνςφϯτͱ͸ "ࣾ #ࣾ $ࣾ w ᶄશར༻ऀ͕ಉҰΞϓϦͱݸผͷσʔλϕʔε "ࣾͷࣾһ #ࣾͷࣾһ $ࣾͷࣾһ ֤%#ͷ؅ཧ͸݈ࡏ͠ӡ༻ίετ͕ߴ͍

Slide 14

Slide 14 text

Ϛϧνςφϯτͱ͸ w ᶅશར༻ऀ͕ಉҰΞϓϦͱಉҰσʔλϕʔε %# ӡ༻ίετ΋௿͘εέʔϧ͠΍͍͢ ͜ͷΞʔΩςΫνϟ͕Ұ൪Ϛϧνςφϯγʔͱ͞Ε͍ͯΔ "ࣾͷࣾһ #ࣾͷࣾһ $ࣾͷࣾһ

Slide 15

Slide 15 text

Ϛϧνςφϯτͱ͸ w ϚϧνςφϯτԽʹඞཁͳཁૉ w ΞϓϦέʔγϣϯ͕ϚϧνςφϯγʔΛαϙʔτ͢Δ͜ͱ w ΞϓϦέʔγϣϯ͕͋Δఔ౓ͷࣗಈαΠϯΞοϓػೳΛඋ͍͑ͯΔ͜ͱ w ొ࿥՝ۚϝΧχζϜ͕༻ҙ͞Ε͍ͯΔ͜ͱ w ΞϓϦέʔγϣϯΛޮ཰తʹεέʔϦϯάͰ͖Δ͜ͱ w ΞϓϦέʔγϣϯͱςφϯτΛ؂ࢹɺߏ੒ɺ؅ཧ͢ΔͨΊͷػೳ͕༻ҙ͞Ε͍ͯΔ͜ͱ w ҰҙͷϢʔβʔ*%͓ΑͼೝূΛαϙʔτ͢ΔϝΧχζϜ͕༻ҙ͞Ε͍ͯΔ͜ͱ w ςφϯτ͝ͱͷΧελϚΠζΛ͋Δఔ౓Մೳʹ͢ΔͨΊͷϝΧχζϜ͕༻ҙ͞Ε͍ͯΔ ͜ͱ Ҿ༻ɿʮ8FCΞϓϦέʔγϣϯΛϚϧνςφϯτܕ4BB4ιϦϡʔγϣϯʹม׵͢Δʯ IUUQTXXXJCNDPNEFWFMPQFSXPSLTKQDMPVEMJCSBSZDMNVMUJUFOBOUTBBT ஫໨ &MJYJSͰ Ͳ͏΍Δʁ

Slide 16

Slide 16 text

&MJYJS1IPFOJYͰ Ϛϧνςφϯτʹ͢Δʹ͸ʁ w 044ͷϥΠϒϥϦ͕ଘࡏ͠·͢ w BQBSUNFOUFY EPXOMPBET w IUUQTIFYQNQBDLBHFTBQBSUNFOUFY w 5SJQMFY EPXOMPBET w IUUQTIFYQNQBDLBHFTUSJQMFY ˞࣌఺ͷσʔλ ஫໨ ࠓճ͸ ͜Ε࢖͏Αʂ 5SJQMFYͷ࢖͍ํ͸2JJUBʹॻ͖·ͨ͠ IUUQTRJJUBDPNZVKJLBXBJUFNTCCDFBFEDD

Slide 17

Slide 17 text

։ൃ؀ڥʹ͍ͭͯ w &MJYJS &SMBOH051 w 1IPFOJY w 1PTUHSF42-

Slide 18

Slide 18 text

࣮૷ฤ BQBSUNFOUFYͷ࣮૷ํ๏

Slide 19

Slide 19 text

࣮૷ฤBQBSUNFOUFY w 1IPFOJYͷϓϩδΣΫτΛ࡞੒ $ mix phx.new tenant_app ………লུ $ cd tenant_app/ $ mix ecto.create $ mix phx.server $ [info] Running TenantAppWeb.Endpoint with Cowboy using http://0.0.0.0:4000 IUUQʹΞΫηεͯ͠Έ·͠ΐ͏

Slide 20

Slide 20 text

࣮૷ฤBQBSUNFOUFY ͜ͷը໘͕දࣔ͞ΕΕ͹ͻͱ·ͣ0,

Slide 21

Slide 21 text

࣮૷ฤBQBSUNFOUFY w BQBSUNFOUFYΛNJYFYTʹ௥Ճ defp deps do [ {:phoenix, "~> 1.3.0"}, {:phoenix_pubsub, "~> 1.0"}, {:phoenix_ecto, "~> 3.2"}, {:postgrex, ">= 0.0.0"}, {:phoenix_html, "~> 2.10"}, {:phoenix_live_reload, "~> 1.0", only: :dev}, {:gettext, "~> 0.11"}, {:apartmentex, github: "Dania02525/apartmentex"}, {:cowboy, "~> 1.0"} ] end ࣌఺͸)FYʹ্͕͍ͬͯΔϓϩάϥϜʹ ෆ۩߹͕͋ΓHJUIVC͔ΒΠϯετʔϧ͢ΔΑ͏ʹมߋͨ͠

Slide 22

Slide 22 text

࣮૷ฤBQBSUNFOUFY w ϥΠϒϥϦΛΠϯετʔϧ $ mix deps.get && mix deps.compile

Slide 23

Slide 23 text

࣮૷ฤBQBSUNFOUFY w ςφϯτςʔϒϧͷ࡞੒ w αϒυϝΠϯଐੑΛ࣋ͨͤͨDPNQBOJFTςʔϒϧΛ࡞੒ʢί ϚϯυͰҰൃʣ $ mix phx.gen.context Accounts Company companies sub_domain:string ͜ͷίϚϯυ͸ςʔϒϧ࡞੒༻ͷϚΠάϨʔγϣϯϑΝΠϧ΍ .7$Ͱ͍͏.෦෼·ͰࣗಈͰ࡞੒ͯ͘͠Ε·͢ɻ

Slide 24

Slide 24 text

࣮૷ฤBQBSUNFOUFY w Ϣʔβ৘ใϓϩάϥϜͷ࡞੒ w ؆୯ͷͨΊϢʔβͷ໊લ͚ͩΛొ࿥͢ΔΞϓϦΛ࡞੒ $ mix phx.gen.html Accounts User users name:string ͜ͷίϚϯυ͸ςʔϒϧ࡞੒༻ͷϚΠάϨʔγϣϯϑΝΠϧ΍ .7$Ͱ͍͏.7$શͯࣗಈͰ࡞੒ͯ͘͠Ε·͢ɻ

Slide 25

Slide 25 text

࣮૷ฤBQBSUNFOUFY w ςφϯτΞϓϦ༻ʹςʔϒϧϚΠάϨʔγϣϯϑΥϧμΛ࡞੒ w BQBSUNFOUFY͕࢖͑ΔΑ͏ʹϑΥϧμͷ࡞੒͠ɺઌ΄Ͳ࡞ͬ ͨϢʔβ৘ใͷϚΠάϨʔγϣϯϑΝΠϧ͚ͩΛҠಈͤ͞·͢ɻ $ mkdir priv/repo/tenant_migrations $ mv priv/repo/migrations/20180213211936_create_users.exs priv/ repo/tenant_migrations

Slide 26

Slide 26 text

࣮૷ฤBQBSUNFOUFY w ϧʔςΟϯάΛ௥Ճ MJCUFOBOU@BQQ@XFCSPVUFSFY w Ϣʔβ৘ใͷϧʔςΟϯάΛઃఆ͠·͢ scope "/", TenantAppWeb do pipe_through :browser # Use the default browser stack get "/", PageController, :index resources "/users", UserController end

Slide 27

Slide 27 text

࣮૷ฤBQBSUNFOUFY w $PNQBOZϚΠάϨʔγϣϯϑΝΠϧʹVOJRVFJOEFYΛઃ ఆ defmodule TenantApp.Repo.Migrations.CreateCompanies do use Ecto.Migration def change do create table(:companies) do add :sub_domain, :string timestamps() end create unique_index(:companies, [:sub_domain]) end end

Slide 28

Slide 28 text

࣮૷ฤBQBSUNFOUFY w ϚΠάϨʔγϣϯΛ͠·͢ $ mix ecto.migrate [info] == Running TenantApp.Repo.Migrations.CreateCompanies.change/0 forward [info] create table companies [info] create index companies_sub_domain_index [info] == Migrated in 0.0s

Slide 29

Slide 29 text

࣮૷ฤBQBSUNFOUFY w %#ૢ࡞ͷؔ਺Λมߋ͠·͢ MJCUFOBOU@BQQBDDPVOUTBDDPPVOUTFY def create_company(attrs \\ %{}) do with changeset <- Company.changeset(%Company{}, attrs), {:ok, company} <- Repo.insert(changeset), do: Apartmentex.new_tenant(Repo, company.sub_domain) end def create_user(attrs \\ %{}, sub_domain) do with changeset <- User.changeset(%User{}, attrs), do: Apartmentex.insert(Repo, changeset, sub_domain) end def list_users(sub_domain) do Apartmentex.all(Repo, User, sub_domain) end ొ࿥ͱऔಘͷؔ਺ʹαϒυϝΠϯରԠΛ͢Δ

Slide 30

Slide 30 text

࣮૷ฤBQBSUNFOUFY w ςετσʔλͷ࡞੒ w ಈ࡞֬ೝͷͨΊʹखಈͰ࡞੒͠·͢ $ iex -S mix iex(1)> alias TenantApp.Accounts iex(2)> Accounts.create_company(%{sub_domain: "company-aaa"}) iex(3)> Accounts.create_company(%{sub_domain: "company-zzz"}) iex(4)> Accounts.create_user(%{name: "Yuji Kawakami"}, "company-aaa") iex(5)> Accounts.create_user(%{name: "Taro Tanaka"}, "company-zzz") iex(6)> Accounts.create_user(%{name: "Hanako Takahashi"}, "company-zzz")

Slide 31

Slide 31 text

࣮૷ฤBQBSUNFOUFY w 6TFSίϯτϩʔϥͷมߋ MJCUFOBOU@BQQ@XFCDPOUSPMMFSTVTFS@DPOUSPMMFSFY w Ϣʔβ৘ใͷίϯτϩʔϥΛมߋ͠·͢ def action(conn, _) do [sub_domain|_] = String.split(conn.host, ".") apply(__MODULE__, action_name(conn), [conn, conn.params, sub_domain]) end def index(conn, _params, sub_domain) do users = Accounts.list_users(sub_domain) render(conn, "index.html", users: users) end BDUJPOؔ਺ͰίϯτϩʔϥͰఆٛͨؔ͠਺ʹ TVC@EPNBJOΛҾ਺Ͱ౉͢Α͏ʹ͍ͯ͠Δ

Slide 32

Slide 32 text

࣮૷ฤBQBSUNFOUFY w ςετ༻ʹIPTUTʹυϝΠϯΛઃఆ͠ɺαʔόىಈ $ vim /etc/hosts 127.0.0.1 company-aaa.dev.local dev 127.0.0.1 company-zzz.dev.local dev $ mix phx.server Compiling 1 file (.ex) [info] Running TenantAppWeb.Endpoint with Cowboy using http:// 0.0.0.0:4000

Slide 33

Slide 33 text

࣮ફฤ%&.0

Slide 34

Slide 34 text

࣮ફฤ%&.0

Slide 35

Slide 35 text

࣮ફฤ%#ͷ༷ࢠ 1VCMJDʹͳ͍ͬͯΔςʔϒϧ͸DPNQBOJFTͷΈ

Slide 36

Slide 36 text

࣮ફฤ%#ͷ༷ࢠ 1PTUHSFTͷεΩʔϚػೳΛ্ख͘࢖͏͜ͱͰ αϒυϝΠϯ͝ͱʹσʔλΛ࣋ͯΔ࢓૊ΈΛ࣮ݱ͍ͯ͠Δ

Slide 37

Slide 37 text

·ͱΊ w &MJYJS1IPFOJYͰ΋؆୯ʹϚϧνςφϯτͳΞϓϦ͕࡞ ੒Ͱ͖Δʂ w ࠓճͷϚϧνςφϯτରԠ͸1PTUHSFTͰ͕ͨ͠ɺڵຯ͕ ͋Δਓ͸.Z42-Ͱ΋ࢼͯ͠Έ͍ͯͩ͘͞ɻ w ΋͏ҰͭͷϥΠϒϥϦʔ5SJQMFY΋ࢼͯ͠ɺ͍ͭͷ೔͔· ͨ࿩͕࣌͢དྷΕ͹͍͍ͳ͊ɾɾ

Slide 38

Slide 38 text

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