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

レールの伸ばし方

 レールの伸ばし方

Rails Developers Meetup 2017での発表内容です。

大きいRailsアプリケーションの可読性を保つためのコツについてまとめました。

Shinichi Maeshima

December 09, 2017
Tweet

More Decks by Shinichi Maeshima

Other Decks in Technology

Transcript

  1. Ϩʔϧͷ৳͹͠ํ
    !XJMMOFU

    View full-size slide

  2. 3BJMT%FWFMPQFST
    .FFUVQ

    View full-size slide

  3. $MFBO5FTU$PEF

    View full-size slide

  4. IUUQTXJMMOFUHJUCPPLTJPSTQFDTUZMFHVJEF

    View full-size slide

  5. ӳޠ൛΋͋Γ·͢
    5IBOLT!HB[BZBT

    View full-size slide

  6. Shinichi Maeshima
    !
    "
    #
    @netwillnet
    @willnet
    http://blog.willnet.in
    Rails Consultant

    View full-size slide

  7. 8FBSFOPUIJSJOH

    View full-size slide

  8. ͔͜͜Βຊ୊

    View full-size slide

  9. 8PSLJOHXJUI3BJMT
    XIJMFGFFMJOHTUSFTT

    View full-size slide

  10. Ͳ͏ͨ͠ΒͭΒ͘ͳ͍͔

    View full-size slide

  11. ద੾ͳந৅Խ

    View full-size slide

  12. ద੾ͳந৅Խ
    Կͯ͠Δͷ͔ͻͱ໨Ͱ
    ෼͔ΔΑ͏ʹ͢Δ

    View full-size slide

  13. ద੾ͳந৅Խͷྫ CFGPSF

    class Registration
    def save
    ApplicationRecord.transaction do
    case @auth_hash[:provider]
    when 'twitter' then register_by_twitter!
    when 'facebook' then register_by_facebook!
    when 'github' then register_by_github!
    end
    Friendship.create!(user: invitation.sender, friend: user)
    Friendship.create!(user: user, friend: invitation.sender)
    invitation.joined_at = Time.zone.now
    invitation.receiver = user
    invitation.save!
    end
    true
    rescue ActiveRecord::RecordInvalid
    false
    end

    View full-size slide

  14. ద੾ͳந৅Խͷྫ BGUFS

    class Registration
    def save
    ApplicationRecord.transaction do
    register!
    make_friends!
    finish_invite!
    end
    true
    rescue ActiveRecord::RecordInvalid
    false
    end

    View full-size slide

  15. ద੾ͳந৅Խ

    View full-size slide

  16. ద੾Ͱͳ͍ந৅Խͷྫ
    class IssuesController < ApplicationController
    before_filter :find_issue, :only => [:show, :edit, :update]
    before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
    before_filter :find_project, :only => [:new, :create, :update_form]
    before_filter :authorize, :except => [:index]
    before_filter :find_optional_project, :only => [:index]
    before_filter :check_for_default_issue_status, :only => [:new, :create]
    before_filter :build_new_issue_from_params, :only => [:new, :create, :update_form]

    View full-size slide

  17. 3BJMTͷ.7$ʹ͓͚Δ՝୊
    w.7$ɺਖ਼͔ͭ͑ͯ͘͠·͔͢ʁ
    w.7$͚ͩͰ͸ϨΠϠ଍Γͳ͍ͷͰ͸ʁ

    View full-size slide

  18. $POUSPMMFSΛਖ਼͘͠࢖͏

    View full-size slide

  19. ѱ͍ྫ 'BU$POUSPMMFS

    IUUQTHJUIVCDPNTIBLBDPEFGBUDPEFSFGBDUPSJOHUFDIOJRVFT
    def create
    @micropost = Micropost.new(micropost_params.merge(user: current_user))
    if current_user.minor? && (profane_words_used = profane_words_in(@micropost.content))
    current_user.increment(:profanity_count, profane_words_used.size)
    current_user.save(validate: false)
    send_parent_notifcation_of_profanity(profane_words_used)
    flash.now[:error] = <<-MSG.html_safe
    Profanity: '#{profane_words_used.join(", ")}' not allowed! You've tried to use
    profanity #{view_context.pluralize(current_user.profanity_count, "time")}!
    Your parents have been notified!
    MSG
    render 'static_pages/home'
    else
    if @micropost.save
    flash[:success] = "Micropost created!"
    redirect_to root_url
    else
    render 'static_pages/home'
    end
    end
    end
    end

    View full-size slide

  20. 'BU$POUSPMMFS㲈ద੾ͳ
    ந৅Խ͕Ͱ͖͍ͯͳ͍

    View full-size slide

  21. मਖ਼ޙ
    def create
    @micropost = Micropost.new(micropost_params.merge(user: current_user))
    if @micropost.save_with_profanity_callbacks
    flash[:success] = "Micropost created!"
    redirect_to root_url
    else
    adjust_micropost_profanity_message
    render 'static_pages/home'
    end
    end

    View full-size slide

  22. $POUSPMMFSͷ੹຿
    w ϞσϧͷϝιουΛݺͿ
    w Πϯελϯεม਺΁ͷ୅ೖ
    w Ϗϡʔͷબ୒ ΋͘͠͸ϦμΠϨΫτઌͷબ୒

    View full-size slide

  23. ϩδοΫͷ͢΂ͯΛ
    Ϟσϧʹ೚ͤΔؾ࣋ͪͰ

    View full-size slide

  24. class UsersController < ApplicationController
    def create
    @user = User.new(user_params)
    if @user.save
    UserMailer.thanks(@user).deliver_later
    redirect_to @user, notice: '登録完了しました'
    else
    render :new
    end
    end
    ͜ͷ͘Β͍͸ڐ༰

    View full-size slide

  25. ͺͬͱݟͯ෼͔ΔൣғͳΒ
    ίϯτϩʔϥʹॻ͍ͯ΋େৎ෉

    View full-size slide

  26. .PEFMΛਖ਼͘͠࢖͏

    View full-size slide

  27. ࠶ܝ
    ϩδοΫͷ͢΂ͯΛ
    Ϟσϧʹ೚ͤΔؾ࣋ͪͰ

    View full-size slide

  28. ϩδοΫͷ͢΂ͯΛ
    Ϟσϧʹ೚ͤΔ
    'BU.PEFM

    View full-size slide

  29. 'BU.PEFMͷԿ͕ྑ͘ͳ͍ͷ
    w େ఍ͷ৔߹ɺϞσϧಉ͕࢜ີ݁߹ʹͳ͍ͬͯΔ
    w ີ݁߹͸मਖ਼͕࿈࠯͠΍͍͢
    w "ΫϥεͷϝιουΛमਖ਼ͨ͠Β#Ϋϥεͷमਖ਼͕ඞཁ
    ʹͳͬͯɺͦΕΛमਖ਼ͨ͠Β$Ϋϥεͷमਖ਼͕ʜ
    w ˠόάͷݪҼʹͳΓ΍͍͢

    View full-size slide

  30. 'BU.PEFMͷྫ
    class User < ApplicationRecord
    has_many :posts
    has_many :friendships
    has_many :friends, through: :friendships
    def create_post_with_notifications!(body)
    transaction do
    posts.create!(body: body)
    friends.each do |friend|
    friend.notifications.create!("#{name}さんが投稿しました")
    end
    end
    end
    # 大量の似たようなメソッド
    end

    View full-size slide

  31. 1030ʹ੾Γग़͢
    class PostWithNotifications
    def self.create!(creator:, body:)
    new(creator: creator, body: body).create!
    end
    def initialize(creator:, body:)
    @creator = creator
    @body = body
    end
    def create!
    ActiveRecord::Base.transaction do
    create_post!
    create_notifications!
    end
    end

    private
    attr_reader :creator, :body
    def create_post!
    creator.posts.create!(body: body)
    end
    def create_notifications!
    creator.friends.each { |friend|
    create_notification!(friend)
    }
    end
    def create_notification!(friend)
    friend.notifications.create!(
    “#{creator.name}さんが投稿しました"
    )
    end
    end

    View full-size slide

  32. IUUQUFDINFEQFFSDPKQFOUSZ

    View full-size slide

  33. 7JFXΛਖ਼͘͠࢖͏

    View full-size slide

  34. 7JFXʹ
    େ͖͍՝୊͸ͳ͍ ͸ͣ

    View full-size slide

  35. ͜͜·Ͱͷ·ͱΊ
    w ϩδοΫΛϞσϧʹدͤΔ
    w 1030 "DUJWF3FDPSEҎ֎ͷϞσϧ
    Λ׆༻͢Δ

    View full-size slide

  36. ͜Ε͚ͩͰ΋ฏۉҎ্
    ͷՄಡੑ ౰ࣾൺ

    View full-size slide

  37. ͔࣍͠͠ͷΑ͏ͳέʔεͰ
    ·ͩࠔΔ
    w େྔͷCFGPSF@pMUFS
    w WBMJEBUJPO΍DBMMCBDLͷ৔߹෼͚
    w ͻͱͭͷΞΫγϣϯͰͨ͘͞Μ΍Δ͜ͱ͕͋Δ

    View full-size slide

  38. େྔͷCFGPSF@pMUFS
    class IssuesController < ApplicationController
    before_filter :find_issue, :only => [:show, :edit, :update]
    before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
    before_filter :find_project, :only => [:new, :create, :update_form]
    before_filter :authorize, :except => [:index]
    before_filter :find_optional_project, :only => [:index]
    before_filter :check_for_default_issue_status, :only => [:new, :create]
    before_filter :build_new_issue_from_params, :only => [:new, :create, :update_form]

    View full-size slide

  39. CFGPSF@pMUFS͕ଟ͍ͱ
    Կ͕໰୊͔
    w ࣗ෼͕ؾʹ͍ͯ͠ΔίϯςΩετ ΞΫγϣϯ
    Ͱͳ
    ʹ͕࣮ߦ͞Ε͍ͯΔͷ͔͕Θ͔ΓͮΒ͍
    w ࠷ऴతʹͲΜͳΠϯελϯεม਺͕ઃఆ͞Ε͍ͯΔ
    ͷ͔Θ͔ΓͮΒ͍

    View full-size slide

  40. આ໌༻ͷ΋ͬͱ؆୯ͳྫ
    class PostsController < ApplicationController
    before_filter :set_posts, only: :index
    before_filter :set_post, only: :show
    before_filter :set_recommendations
    def index
    end
    def show
    end
    private
    def set_posts
    @posts = post.page(params[:page).per(10)
    end
    def set_post
    @post = post.find(params[:id])
    end
    def set_recommendations
    @recommendation_categories = Category.recommendations
    @recommendations = @recommendation_categories.posts
    end
    end

    View full-size slide

  41. CFGPSF@pMUFSBDUJPO
    class PostsController < ApplicationController
    def index
    set_recommendations
    set_posts
    end
    def show
    set_recommendations
    set_post
    end
    private
    def set_posts
    @posts = post.page(params[:page).per(10)
    end
    def set_post
    @post = post.find(params[:id])
    end
    def set_recommendations
    @recommendation_categories = Category.recommendations
    @recommendations = Recommendations.new(@recommendation_categories)
    end
    end

    View full-size slide

  42. w ࣗ෼͕ؾʹ͍ͯ͠ΔίϯςΩετ ΞΫγϣϯ
    Ͱͳʹ͕࣮ߦ
    ͞Ε͍ͯΔͷ͔͕Θ͔ΓͮΒ͍ˠ


    w ࠷ऴతʹͲΜͳΠϯελϯεม਺͕ઃఆ͞Ε͍ͯΔͷ͔Θ
    ͔ΓͮΒ͍ˠ

    View full-size slide

  43. ΫΤϦϝιουԽ
    class PostsController < ApplicationController
    def index
    @recommendation_categories = fetch_recommendation_categories
    @recommendations = fetch_recommendations(@recommendation_categories)
    @posts = fetch_posts
    end
    def show
    @recommendation_categories = fetch_recommendation_categories
    @recommendations = fetch_recommendations(@recommendation_categories)
    @post = fetch_post
    end
    private
    def fetch_posts
    post.page(params[:page).per(10)
    end
    def fetch_post
    post.find(params[:id])
    end
    def fetch_recommendation_categories
    Category.recommendations
    end
    def fetch_recommendations(categories)
    Recommenadtions.new(categories)
    end
    end

    View full-size slide

  44. w ࣗ෼͕ؾʹ͍ͯ͠ΔίϯςΩετ ΞΫγϣϯ
    Ͱͳʹ͕࣮ߦ
    ͞Ε͍ͯΔͷ͔͕Θ͔ΓͮΒ͍ˠ

    w ࠷ऴతʹͲΜͳΠϯελϯεม਺͕ઃఆ͞Ε͍ͯΔͷ͔Θ
    ͔ΓͮΒ͍ˠ

    View full-size slide

  45. Ұݟ໰୊ͳͦ͞͏ʹ
    ݟ͑Δ

    View full-size slide

  46. Πϯελϯεม਺͕ଟ͍ͱʜ
    class PostsController < ApplicationController
    def index
    @recommendation_categories = fetch_recommendation_categories
    @recommendations = fetch_recommendations(@recommendation_categories)
    @posts = fetch_posts
    @ad = fetch_ad
    @widget = fetch_widget
    @sidebar = fetch_sidebar
    @title = fetch_title
    @cart = current_cart
    @search = build_search_form
    end
    def show
    # indexと同じようにたくさんのインスタンス変数への代入がある
    end
    private
    # たくさんのプライベートメソッド
    end

    View full-size slide

  47. Πϯελϯεม਺͕ଟ͍ͱʜ
    w ϓϥΠϕʔτϝιου͕ଟ͘ͳΓݟ௨͕͠ѱ͘ͳΔ
    w ˢΛϞσϧ΁Ҡ͢ͱଟগ؇࿨͞ΕΔ

    View full-size slide

  48. Ϗϡʔʹ౉͢ΦϒδΣΫτ͕
    ଟ͍ͱݟͮΒ͍

    View full-size slide

  49. ղܾࡦ
    ʮϏϡʔʹ౉͢ม਺Λந৅Խʯ

    View full-size slide

  50. 7JFX.PEFM 7JFX0CKFDU

    class PostsController < ApplicationController
    def index
    @view_model = PostIndexViewModel.new
    end
    end
    class PostIndexViewModel
    def posts
    @posts ||= Post.page(params[:page).per(10)
    end
    def recommendation_categories
    @recommendation_categories ||= Category.recommendations
    end
    def recommendations
    @recommendations ||= recommendation_categories.posts
    end
    end

    View full-size slide

  51. 7BMJEBUJPO DBMMCBDL
    ͷ
    ৔߹෼͚
    class Post < ApplicationRecord
    validates :body, presence: true, length: { maximum: 1000 }
    validates :published_at, presence: true
    validate :publish_at_should_after_current, unless: :by_admin
    attr_reader :by_admin
    def update_by_admin(attrs)
    @by_admin = true
    update(attrs)
    end
    def publish_at_should_after_current
    return unless publish_at
    return if publish_at > Time.zone.now
    errors.add(:publish_at, 'は現在時刻より後にしてください')
    end
    end

    View full-size slide

  52. ద੾ͳந৅Խ
    Կͯ͠Δͷ͔ͻͱ໨Ͱ
    ෼͔ΔΑ͏ʹ͢Δ

    View full-size slide

  53. Կͯ͠Δͷ͔ͻͱ໨Ͱ
    ෼͔ΔΑ͏ʹ͢Δ
    ৔߹෼͚

    View full-size slide

  54. ղܾࡦ
    ϑΥʔϜ͝ͱʹΫϥεΛ࡞Δ

    View full-size slide

  55. 'PS̼0CKFDU
    class PostForm
    include ActiveModel::Model
    attr_accessor :post, :body, :publish_at
    validates :body, presence: true, length: { maximum: 1000 }
    validates :publish_at, presence: true
    validate :publish_at_should_after_current
    def save
    post.attributes = { body: body, publish_at: publish_at }
    post.save if valid?
    end
    private
    def publish_at_should_after_current
    return unless publish_at
    return if publish_at > Time.zone.now
    errors.add(:publish_at, 'は現在時刻より後にしてください')
    end
    end

    View full-size slide

  56. 'PS̼0CKFDU
    class AdminPostForm
    include ActiveModel::Model
    attr_accessor :post, :body, :publish_at
    validates :body, presence: true, length: { maximum: 1000 }
    validates :publish_at, presence: true
    def save
    post.attributes = { body: body, publish_at: publish_at }
    post.save if valid?
    end
    end

    View full-size slide

  57. IUUQUFDINFEQFFSDPKQFOUSZ

    View full-size slide

  58. ͻͱͭͷΞΫγϣϯͰ
    ͨ͘͞Μ΍Δ͜ͱ͕͋Δ
    class PostsController < ApplicationController
    def create
    Hoge.prepare_create1 # なんらかの前処理1
    @post = current_user.post.build(post_params)
    Hoge.prepare_create2 # なんらかの前処理2
    unless @post.save
    Fuga.prepare_new # new を表示するためのいろいろな前処理
    render :new and return
    end
    Foo.after # なんらかの後処理
    Bar.after # なんらかの後処理2
    end
    end

    View full-size slide

  59. ϩδοΫΛϞσϧʹ
    Ҡͯ͠΋TMJNʹͳΓ͖Εͳ͍
    έʔε

    View full-size slide

  60. ղܾࡦ
    ϞσϧͷϩδοΫΛݺͿՕॴΛ
    ந৅Խ͢Δ

    View full-size slide

  61. 4FSWJDF0CKFDU

    View full-size slide

  62. ஫ҙਓʹΑ͍ͬͯΖ͍Ζͳ
    4FSWJDF͕͋Δ
    w 1P&""ʮ4FSWJDF-BZFSʯ
    w %%%ʮ4FSWJDFʯ
    w ͦΕΒΛ౿·͑ͨ3BJMTͷʮ4FSWJDF0CKFDUʯ
    w ͜Ε΋ෳ਺छྨ͕͋Δ

    View full-size slide

  63. 3BJMTͷ4FSWJDF0CKFDUʹ΋
    ਓʹΑ༷ͬͯʑͳ࣮૷͕͋Δ
    w ͖ͬ͞ͷ1030ͷྫΛ4FSWJDF0CKFDUͱݺΜͰ͍Δ
    w ίϯτϩʔϥͷϩδοΫͷҰ෦ΛNPEVMFͷΫϥεϝιου
    ʹҠͯͦ͠ΕΛ4FSWJDFͱݺΜͰ͍Δ
    w ͦͷΞΫγϣϯͰ࣮ߦ͢Δ͜ͱΛ·ΔͬͱผΫϥεʹஔ͖
    ׵͑Δ

    View full-size slide

  64. ͜ͷൃදͰͷ4FSWJDF0CKFDU
    w ΞΫγϣϯͷࡉʑͨ͠෦෼Λ·Δͬͱ୲͏ΦϒδΣΫτ
    w SFOEFS SFEJSFDU@UPͳͲ͸ίϯτϩʔϥ͕΍Δ
    w υϝΠϯϩδοΫ͸Ϟσϧ͕΍Δ

    View full-size slide

  65. 4FSWJDF0CKFDU
    class CreatePostService
    attr_reader :result
    def self.call(user:, params:)
    new(user: user, params: params).call
    end
    def initialize(user:, params:)
    @user = user
    @params = params
    @result = true
    end
    def call
    before_callback
    unless post.save
    fail!
    prepare_new
    return
    end
    after_callback
    self
    end
    def post
    @post ||= user.post.build(params)
    end
    private
    attr_reader :user, :paramas
    def before_callback
    Hoge.prepare_create1
    Hoge.prepare_create2
    end
    def after_callback
    Foo.after
    Bar.after
    end
    def prepare_new
    Fuga.prepare_new
    end
    def fail!
    @result = false
    end
    def post_params
    params.require(:post).permit(:body)
    end
    end

    View full-size slide

  66. 4FSWJDF0CKFDU
    class PostsController < ApplicationController
    def create
    service = CreatePostService.call(user: current_user, params: params)
    unless service.result
    @post = service.post
    render :new and return
    end
    redirect_to posts_path, notify: '作成されました'
    end
    end

    View full-size slide

  67. ͜Ε͚ͩ͋Ε͹͋Δఔ౓େ͖͍
    3BJMTΞϓϦέʔγϣϯͰ΋ઓ͑Δ
    w7JFX.PEFM
    w'PSN0CKFDU
    w4FSWJDF0CKFDU

    View full-size slide

  68. ͔͠͠Ͳ͏΍ͬͯݱ৔
    ʹಋೖ͢Δʁ

    View full-size slide

  69. νʔϜ։ൃʹ͸۩ମతͳྫ΍
    Θ͔Γ΍͍͢υΩϡϝϯτ͕
    ෆՄܽ

    View full-size slide

  70. ౷Ұͨ͠ॻ͖ํʹ
    ༠ಋͰ͖Δπʔϧ͕༗Δͱྑ
    ͍ͷͰ͸

    View full-size slide

  71. IUUQTHJUIVCDPNXJMMOFUZVCB

    View full-size slide

  72. :VCBϙΤϜ
    w 7JFX.PEFM 'PSN0CKFDU 4FSWJDF0CKFDUͷ࡞੒ิॿ༻HFN
    w ن໿ʹΑΓ࡞ΓํͰ໎Θͳ͍Α͏ʹ
    w 1030ͩͱຖճ΍Βͳ͖Ό͍͚ͳ͍໘౗ͳهड़͸؆୯ʹ͔͚ΔΑ͏ʹ
    w ඞཁͳͱ͜Ζ͚ͩಋೖͰ͖ΔΑ͏ʹ
    w ಋೖ͠΍ࣺͯ͘͢΍͍͢࡞Γʹ
    w ബ͘࡞Δ
    w 3BJMTΤϯδχΞ͕ҧ࿨ײͳ͘࢖͑ΔΠϯλϑΣʔε

    View full-size slide

  73. ஫ҙ
    w WFSͰ͢
    w ී௨ʹ࢖͑Δ͸ͣͰ͕͢ɺ͜Ε͔Β࢓༷͕มΘΔՄೳੑ͕
    ͋Γ·͢
    w ಛʹ:VCB'PSN

    View full-size slide

  74. 1030Ͱ7JFX.PEFM
    class PostViewModel
    attr_reader :post
    def initialize(post:, author:, other: nil)
    @post = post
    @author = author
    @other = other
    end
    def title
    post.title
    end
    def body
    post.body
    end
    private
    attr_reader :author, :other
    end

    View full-size slide

  75. ຖճಉ͡Α͏ͳॲཧΛ
    ॻ͔ͳ͚Ε͹ͳΒͳ͍
    class PostViewModel
    attr_reader :post
    def initialize(post:, author:, other: nil)
    @post = post
    @author = author
    @other = other
    end
    def title
    post.title
    end
    def body
    post.body
    end
    private
    attr_reader :author, :other
    end

    View full-size slide

  76. :VCB7JFX.PEFM
    class PostViewModel < Yuba::ViewModel
    property :post
    property :author, public: true
    property :other, optional: true
    def title
    post.title
    end
    def body
    post.body
    end
    end

    View full-size slide

  77. !WJFX@NPEFM໰୊
    class PostsController < ApplicationController
    def show
    @view_model = PostViewModel.new(post: post, author: author)
    end
    end
    <%= @view_model.post.title %>
    <%= @view_model.author.name %>

    View full-size slide

  78. ඞͣ!WJFX@NPEFMΛ
    ܦ༝͠ͳ͚Ε͹ͳΒͳ͍
    class PostsController < ApplicationController
    def show
    @view_model = PostViewModel.new(post: post, author: author)
    end
    end
    <%= @view_model.post.title %>
    <%= @view_model.author.name %>

    View full-size slide

  79. 7JFX.PEFMΛల։ͯ͠
    Πϯελϯεม਺ʹׂ౰
    class PostsController < ApplicationController
    def show
    view_model = PostViewModel.new(post: post, author: author)
    render view_model: view_model
    end
    end
    <%= @post.title %>
    <%= @author.name %>

    View full-size slide

  80. :VCB4FSWJDF
    class PostController < ApplicationController
    def new
    @post = CreatePostService.call(user: current_user).post
    end
    def create
    service = CreatePostService.call(user: current_user, params: params)
    if service.success?
    redirect_to root_path
    else
    @post = service.post
    render :new
    end
    end
    end

    View full-size slide

  81. :VCB4FSWJDF
    class CreatePostService < Yuba::Service
    property :user, public: true
    property :params, optional: true
    def call
    if post.save
    notify_to_admin
    else
    fail!
    end
    end
    def post
    user.posts.build(post_params)
    end
    private
    def notify_to_admin
    AdminMailer.notify_create_post(post).deliver_later
    end
    def post_params
    params.require(:post).permit(:title, :body)
    end
    end

    View full-size slide

  82. :VCB4FSWJDFͷಛ௃
    w 7JFX.PEFMͱಉ͡࢓༷ͷQSPQFSUZ
    w ࣮ߦ͸DBMM
    w DBMMͷҾ਺ΛQSPQFSUZʹׂΓ౰ͯͯDBMMΛݺͼग़͢
    w TVDDFTT Ͱ੒ޭ൑ఆ

    View full-size slide

  83. :VCB'PSN
    w ݱঢ়
    SFGPSNSBJMTͷϥούʔ
    w IUUQTHJUIVCDPNUSBJMCMB[FSSFGPSNSBJMT
    w ࣗલͷίʔυʹॻ͖׵͑தͳͷͰ͠͹Β͓͘଴ͪԼ͍͞ʜ

    View full-size slide

  84. ࢼͯ͠Έ͍ͯͩ͘͞

    View full-size slide

  85. ·ͱΊ
    w .7$ͷਖ਼͍͠࢖͍ํʹ͍ͭͯ
    w 'BU$POUSPMMFS 'BU.PEFMͷղܾํ๏
    w 3BJMT͕ఏڙ͍ͯ͠Δ.7$͚ͩͰ͸ରԠ͖͠Εͳ͍໰୊ͷղܾํ๏
    w 7JFX.PEFM
    w 'PSN0CKFDU
    w 4FSWJDF0CKFDU
    w ˢΛແཧͳ͘ಋೖ͢ΔͨΊͷϥΠϒϥϦ:VCBͷ঺հ

    View full-size slide

  86. )BQQZ3BJMT$PEJOH

    View full-size slide