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

TechTrain RoRハンズオン

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for pokohide pokohide
April 05, 2019

TechTrain RoRハンズオン

Avatar for pokohide

pokohide

April 05, 2019
Tweet

More Decks by pokohide

Other Decks in Technology

Transcript

  1. Railsͷ։ൃ؀ڥΛߏங $ git clone https://github.com/pokohide/rails_app_for_tech_train.git $ cd rails_app_for_tech_train ## DockerͰRails؀ڥΛߏங

    $ docker-compose build ## σʔλϕʔε(PostgreSQL)Λ࡞੒ $ docker-compose run web rails db:create ## ্ཱͪ͛Δ $ docker-compose up ## GET http://localhost:3000/ ## Yay!! You’re on Rails!!
  2. ςʔϒϧઃܭ Questionςʔϒϧ DPOUFOU 4USJOH PSEFS@JOEFY *OUFHFS Choiceςʔϒϧ RVFTUJPO@JE *OUFHFS DPOUFOU

    4USJOH BUUS@ *OUFHFS BUUS@ *OUFHFS BUUS@ *OUFHFS BUUS@ *OUFHFS ※ ޙͰઆ໌͠·͕͢ɺ͜Ε͸ϕετϓϥΫςΟεͰ͸͋Γ·ͤΜ 1 N
  3. QuestionϞσϧΛ࡞੒ (1) ## QuestionςʔϒϧΛ࡞੒͢Δ
 $ docker-compose run web rails g

    model Question content:string order_index:integer ## => # create db/migrate/20190330094200_create_questions.rb # create app/models/question.rb
  4. QuestionϞσϧΛ࡞੒ (1.1) # db/migrate/20190330094200_create_questions.rb class CreateQuestions < ActiveRecord::Migration[5.2] def change

    create_table :questions do |t| t.string :content t.integer :order_index t.timestamps end end end
  5. QuestionϞσϧΛ࡞੒ (1.2) # db/migrate/20190330094200_create_questions.rb class CreateQuestions < ActiveRecord::Migration[5.2] def change

    create_table :questions do |t| t.string :content t.integer :order_index, null: false, default: 0 t.timestamps end end end # order_indexʹNOT NULL੍໿ͱॳظ஋0Ληοτ
  6. QuestionϞσϧΛ࡞੒ (2) ## DBʹϚΠάϨʔγϣϯ $ docker-compose run web rails db:migrate

    ## QuestionϞσϧʹίϯιʔϧ͔ΒΞΫηεՄೳʹ $ docker-compose run web rails console > Question => Question(id: integer, content: string, order_index: integer, created_at: datetime, updated_at: datetime)
  7. ChoiceϞσϧΛ࡞੒ (1) ## ChoiceςʔϒϧΛ࡞੒͢Δ $ docker-compose run web rails g

    model Choice question:references content:string attr_1:integer attr_2:integer attr_3:integer attr_4:integer ## => # create db/migrate/20190330095049_create_choices.rb # create app/models/choice.rb
  8. QuestionϞσϧΛ࡞੒ (1.1) # db/migrate/20190330094200_create_questions.rb class CreateChoices < ActiveRecord::Migration[5.2] def change

    create_table :choices do |t| t.references :question, foreign_key: true t.string :content t.integer :attr_1 t.integer :attr_2 t.integer :attr_3 t.integer :attr_4 t.timestamps end end end
  9. QuestionϞσϧΛ࡞੒ (1.2) # db/migrate/20190330094200_create_questions.rb class CreateChoices < ActiveRecord::Migration[5.2] def change

    create_table :choices do |t| t.references :question, foreign_key: true t.string :content t.integer :attr_1, null: false, default: 0 t.integer :attr_2, null: false, default: 0 t.integer :attr_3, null: false, default: 0 t.integer :attr_4, null: false, default: 0 t.timestamps end end end # order_indexʹNOT NULL੍໿ͱॳظ஋0Ληοτ
  10. ChoiceϞσϧΛ࡞੒ (2) ## DBʹϚΠάϨʔγϣϯ $ docker-compose run web rails db:migrate

    ## ChoiceϞσϧʹίϯιʔϧ͔ΒΞΫηεՄೳʹ $ docker-compose run web rails console > Choice => Choice(id: integer, question_id: integer, content: string, attr_1: integer, attr_2: integer, attr_3: integer, attr_4: integer, created_at: datetime, updated_at: datetime) ## ·ͩQuestionϞσϧ͔ΒChoiceϞσϧʹ͸ΞΫηεͰ͖ͳ͍ > Question.new.choices =>NoMethodError: undefined method `choices' for #<Question: 0x000055d3f5a4c8c8>
  11. Question - Choice ͷϦϨʔγϣϯఆٛ # app/models/question.rb class Question < ApplicationRecord

    has_many :choices end # app/models/choice.rb class Choice < ApplicationRecord belongs_to :question end
  12. ςʔϒϧઃܭ Questionςʔϒϧ DPOUFOU 4USJOH PSEFS@JOEFY *OUFHFS Choiceςʔϒϧ RVFTUJPO@JE *OUFHFS DPOUFOU

    4USJOH BUUS@ *OUFHFS BUUS@ *OUFHFS BUUS@ *OUFHFS BUUS@ *OUFHFS ※ ޙͰઆ໌͠·͕͢ɺ͜Ε͸ϕετϓϥΫςΟεͰ͸͋Γ·ͤΜ 1 N
  13. ॳظσʔλͷૠೖ ## db/fixtures/development/01_question.rb ## db/fixtures/development/02_choice.rb $ docker-compose run web rails

    db:seed_fu == Seed from /rails_app_for_tech_train/db/fixtures/development/01_question.rb - Question {:id=>1, :order_index=>1, :content=>"΋͋͠ͳ͕ͨεʔύʔώʔϩʔͷੈքʹ͍Δͱ ͨ͠৔߹ɺͲΜͳεΩϧ͕ཉ͍͠Ͱ͔͢ʁ"} - Question {:id=>2, :order_index=>2, :content=>”΋͋͠ͳ͕ͨεϚϗήʔϜͰετϨεൃࢄΛ͢ Δ৔߹ɺͲΜͳήʔϜΛબͼ·͔͢ʁ"} … == Seed from /rails_app_for_tech_train/db/fixtures/development/02_chocie.rb - Choice {:question_id=>1, :content=>"ࣗ༝ࣗࡏʹม਎Ͱ͖ΔεΩ ϧ", :attr_1=>1, :attr_2=>3, :attr_3=>5, :attr_4=>1} - Choice {:question_id=>1, :content=>"εϐʔυઓಆೳྗͱߴ͍ӡಈεΩϧ ", :attr_1=>4, :attr_2=>3, :attr_3=>0, :attr_4=>1} … ॳظσʔλ͸༻ҙͯ͋͠Γ·͢
  14. ೖΕͨσʔλΛ৮ͬͯ֬ೝʂ $ docker-compose run web rails console > Question.count =>

    5 > Question.first.content => “΋͋͠ͳ͕ͨεʔύʔώʔϩʔͷੈքʹ͍Δͱͨ͠৔߹ɺͲΜͳεΩϧ͕ཉ͍͠Ͱ͢ ͔ʁ” > Question.first.choices.pluck(:content) => ["ࣗ༝ࣗࡏʹม਎Ͱ͖ΔεΩϧ", "εϐʔυઓಆೳྗͱߴ͍ӡಈεΩϧ", "ے೑͕ൃ ୡͨ͠ݟࣄͳ೑ମͱɺఈ஌Εͳ͍ύϫʔ͕͋ΔεΩϧ", "͘͢͝ڧྗͳ೦ྗͱ৺ཧత߈ܸε Ωϧ"]
  15. ControllerΛ࡞੒ $ docker-compose run web rails g controller Questions index

    result create app/controllers/questions_controller.rb route get 'questions/index' get 'questions/result' create app/views/questions create app/views/questions/index.html.erb create app/views/questions/result.html.erb ࡞੒ͨ͠QuestionsController ͔Βఆٛͨ͠ϞσϧΛ৮Δ
  16. ϧʔςΟϯάΛఆٛ # config/routes.rb Rails.application.routes.draw do get 'questions/index' get 'questions/result' #

    For details on the DSL available within this file, see http:// guides.rubyonrails.org/routing.html end HTTPϦΫΤετͱControllerΛ݁Ϳ # config/routes.rb Rails.application.routes.draw do root to: 'questions#index' get :result, to: ‘questions#result’, as: :result end
  17. Controller͔Β࣭໰Λऔಘ # app/controllers/questions_controller.rb class QuestionsController < ApplicationController def index @questions

    = Question. all. order(:order_index) end def result end end ࣭໰(Question)Λશͯ(all)औಘͯ͠ɺ ॱ൪(order_index)Ͱฒͼସ͑Δ
  18. औಘ࣭ͨ͠໰ΛViewͰදࣔ͢Δ # app/views/question.html.erb <h1>Questions#index</h1> <p>Find me in app/views/questions/index.html.erb</p> <%- @questions.each

    do |question| %> <p><%= question.content %></p> <ul> <%- question.choices.each do |choice| %> <li><%= choice.content %></li> <%- end %> </ul> <%- end %>
  19. બΜͩબ୒ࢶΛαʔόʔʹૹΔ # app/views/question.html.erb <%= form_with url: result_path, local: true, method:

    :get do |f| %> <%- @questions.each do |question| %> <p><%= question.content %></p> <%- question.choices.each do |choice| %> <label> <%= f.radio_button "choices[#{question.id}]", choice.id %> <%= choice.content %> </label> <%- end %> <%- end %> <%= f.submit 'ճ౴' %> <% end %>
  20. બΜͩબ୒ࢶΛαʔόʔʹૹΔ ## αʔόʔͷϩά web_1 | Processing by QuestionsController#result as HTML

    web_1 | Parameters: {"utf8"=>"✓", "choices"=>{"1"=>"1", "2"=>"6", "3"=>"10", "4"=>"16", "5"=>"20"}, "commit"=>"ճ౴"} web_1 | Rendering questions/result.html.erb within layouts/ application web_1 | Rendered questions/result.html.erb within layouts/ application (0.6ms) web_1 | Completed 200 OK in 252ms (Views: 218.3ms | ActiveRecord: 0.0ms) ͪΌΜͱૹΒΕͯͦ͏ id=1ͷ࣭໰ͷબ୒ࢶ͸id=1 id=2ͷ࣭໰ͷબ୒ࢶ͸id=6 …
  21. બ୒ࢶ͔Β݁ՌΛܭࢉ ## αʔόʔͷϩά web_1 | Processing by QuestionsController#result as HTML

    web_1 | Parameters: {"utf8"=>"✓", "choices"=>{"1"=>"1", "2"=>"6", "3"=>"10", "4"=>"16", "5"=>"20"}, "commit"=>"ճ౴"} id=1, 6, 10, 16, 20ͷChoiceͷ attr_1, attr_2, attr_3, attr_4ͷ ͷ߹ܭ஋Λܭࢉ͢Δ Choiceςʔϒϧ RVFTUJPO@JE *OUFHFS DPOUFOU 4USJOH BUUS@ *OUFHFS BUUS@ *OUFHFS BUUS@ *OUFHFS BUUS@ *OUFHFS
  22. બ୒ࢶ͔Β݁ՌΛܭࢉ # app/controllers/questions_controller.rb class QuestionsController < ApplicationController … def result

    choice_ids = params[:choices].values choices = Choice.where(id: choice_ids) @attr_1 = choices.sum(:attr_1) @attr_2 = choices.sum(:attr_2) @attr_3 = choices.sum(:attr_3) @attr_4 = choices.sum(:attr_4) end end GETύϥϝʔλ͔ΒChoiceͷIDҰཡΛऔಘ DB͔Βબ୒ࢶҰཡΛऔಘɺଐੑ஋Λܭࢉ
  23. ݁ՌΛදࣔͯ͠ΈΔ # app/views/result.html.erb <h1>Questions#result</h1> <p>Find me in app/views/questions/result.html.erb</p> <p>ଐੑ1ɿ <%=

    @attr_1 %></p> <p>ଐੑ2ɿ <%= @attr_2 %></p> <p>ଐੑ3ɿ <%= @attr_3 %></p> <p>ଐੑ4ɿ <%= @attr_4 %></p>
  24. ࣭໰Λม͑ͯΈΔ # db/fixtures/development/01_question.rb ##### Q.1 ##### Question.seed(:id) do |q| q.id

    = 1 q.order_index = 1 q.content = '΋͋͠ͳ͕ͨεʔύʔώʔϩʔͷੈքʹ͍Δͱͨ͠৔߹ɺͲΜͳεΩϧ͕ཉ͍͠Ͱ͔͢ʁ' end ##### Q.2 ##### Question.seed(:id) do |q| q.id = 2 q.order_index = 2 q.content = '΋͋͠ͳ͕ͨεϚϗήʔϜͰετϨεൃࢄΛ͢Δ৔߹ɺͲΜͳήʔϜΛબͼ·͔͢ʁ' end … $ dokcer-compose run web rails db:seed_fu
  25. બ୒ࢶ΍ଐੑΛม͑ͯΈΔ # db/fixtures/development/02_choice.rb ##### Q.1 ͷબ୒ࢶ ##### Choice.seed(:question_id, :content) do

    |a| a.question_id = 1 a.content = 'ࣗ༝ࣗࡏʹม਎Ͱ͖ΔεΩϧ' a.attr_1, a.attr_2, a.attr_3, a.attr_4 = 1, 3, 5, 1 end Choice.seed(:question_id, :content) do |a| a.question_id = 1 a.content = 'εϐʔυઓಆೳྗͱߴ͍ӡಈεΩϧ' a.attr_1, a.attr_2, a.attr_3, a.attr_4 = 4, 3, 0, 1 end … ࠓճ͸͋͑ͯattr_1, …ͱந৅తͳΧϥϜΛ࢖༻ ͍ͯ͠ΔͷͰԿͱղऍͯ͠΋OK
  26. ݁ՌΛදࣔͯ͠ΈΔ # app/views/result.html.erb <h1>Questions#result</h1> <p>Find me in app/views/questions/result.html.erb</p> <p>ͣΔݡ͍ɿ <%=

    @attr_1 %></p> <p>಄೴໌᏷ɿ <%= @attr_2 %></p> <p>୯७ɿ <%= @attr_3 %></p> <p>ߦ͖౰ͨΓ͹ͬͨΓɿ <%= @attr_4 %></p>
  27. BulmaΛಋೖ https:/ /bulma.io/ # app/views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title>RailsAppForTechTrain</title>

    <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks- track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= stylesheet_link_tag 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/ css/bulma.min.css' %> </head> <body> <%= yield %> </body> </html>
  28. ࣭໰ϖʔδͷσβΠϯมߋ # app/views/questions/index.html.erb <section class="section"> <div class="container"> <%= form_with url:

    result_path, local: true, method: :get do |f| %> <%- @questions.each do |question| %> <h3 class="title is-3"><%= question.content %></h3> <%- question.choices.each do |choice| %> <label class="choice"> <%= f.radio_button "choices[#{question.id}]", choice.id %> <div class="notification"><%= choice.content %></div> </label> <%- end %> <%- end %> <%= f.submit 'ճ౴', class: "button is-primary" %> <% end %> </div> </section>
  29. ࣭໰ϖʔδͷσβΠϯมߋ # app/assets/stylesheets/questions.scss .choice { div { display: block; margin-bottom:

    1rem; } &:hover div { opacity: .8; cursor: pointer; } input[type="radio"] { display: none; &:checked + div { background-color: #00d1b2; color: #fff; } } }
  30. ݁ՌϖʔδͷσβΠϯมߋ # app/views/questions/result.html.erb <section class="section"> <div class="container"> <nav class="level"> <div

    class="level-item has-text-centered"> <div> <p class="heading">ͣΔݡ͍</p> <p class="title"><%= @attr_1 %> </div> </div> <div class="level-item has-text-centered"> <div> <p class="heading">಄೴໌᏷</p> <p class="title"><%= @attr_2 %> </div> </div> … </nav> </div> </section>
  31. ݁ՌʹԠͯ͡ग़͠෼͚ # app/controllers/questions_controller.rb class QuestionsController < ApplicationController … def result

    … if @attr_1 > 10 && @attr_4 < 10 @recommend = 'υϥΰϯΫΤετVIII ۭͱւͱେ஍ͱढΘΕ͠ඣ܅' elsif … @recommend = ‘τϧωίͷେ๯ݥ ෆࢥٞͷμϯδϣϯ' … @recommend = ‘υϥΫΤ2 Ϛϧλͷ;͗͠ͳ伴 ϧΧͷཱཱྀͪ’ end end end
  32. ݁ՌʹԠͯ͡ग़͠෼͚ # app/views/questions/result.html.erb <section class="section"> <div class=“container"> <nav class=“level”> …

    </nav> <article class="message is-primary"> <div class="message-body"> ͋ͳͨ͸ <span class="title is-4">ʮ<%= @recommend %>ʯ</span> ͕޷͖Ͱ͠ΐ͏ɻ </div> </article> </div> </section>
  33. ࠓճͷςʔϒϧઃܭ Questionςʔϒϧ DPOUFOU 4USJOH PSEFS@JOEFY *OUFHFS Choiceςʔϒϧ RVFTUJPO@JE *OUFHFS DPOUFOU

    4USJOH BUUS@ *OUFHFS BUUS@ *OUFHFS BUUS@ *OUFHFS BUUS@ *OUFHFS ※ ͜Ε͸ϕετϓϥΫςΟεͰ͸ͳ͍ 1 N
  34. ͨͱ͑͹… Questionςʔϒϧ DPOUFOU 5FYU PSEFS@JOEFY *OUFHFS JNBHF 4USJOH Choiceςʔϒϧ RVFTUJPO@JE

    *OUFHFS DPOUFOU 4USJOH JNBHF 4USJOH ChoiceͱAttributeΛଟରଟͷؔ܎ʹ͢Δͱεέʔϥϒϧ 1 N Attributeςʔϒϧ OBNF 4USJOH Choice-Attribute ςʔϒϧ RVFTUJPO@JE *OUFHFS BUUS@JE *OUFHFS QPJOU *OUFHFS 1 N 1 N N M