⑦日記の投稿機能を作成

はじめに

今までの「Ruby on Rails 〜 基礎 〜」までのカリキュラムでは、「ユーザ登録」「ログイン・ログアウト」などWebアプリケーションの基礎となる機能を実装してきました。

これ以降の章では、さらに機能を付け加え、ユーザ毎に画像付きの日記を保存できるアプリを作成していきます。

また今後は、ファイルの場所を画像で示したり、githubへのプッシュ、マージの説明などは省略します。

適宜、新たなブランチの作成、コミット、プッシュ、マージなどを行ってください。

途中で分からなくなった場合は、過去の章を復習しながら、学習を進めていきましょう。

この章でのゴール

・日記を新規投稿できる機能を実装

日記の投稿機能を作成

この章では、新規の日記を投稿できる機能を実装していきます。

完成イメージは下記です。

Postモデルの作成

今回は、新たに日記を保存するためのPostモデルを作成します。

まず、作業ディレクトリに移動します。

$ cd ~/hello_world

 

次に、rails gコマンドで、Postモデルを作成します。

Postモデルのカラムは、「user_id」「title」「description」「image」とします。

user_id:どのユーザの日記かを識別するid

title:日記のタイトル

description:日記の内容

image:アップロードした画像のパス(ファイル名)

 

$ rails g model post
/Users/alto/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/railties-5.2.3/lib/rails/app_loader.rb:53: warning: Insecure world writable dir /usr/local/bin in PATH, mode 040777
Running via Spring preloader in process 34462
      invoke  active_record
      create    db/migrate/20191007012713_create_posts.rb
      create    app/models/post.rb
      invoke    test_unit
      create      test/models/post_test.rb
      create      test/fixtures/posts.yml

 

./db/migrate/20191006182918_create_posts.rb(生成された年月日によってファイル名が異なります)を開き、以下の通り保存します。

Postモデルに対して、どのようなカラムを設定するかを定義します。

class CreatePosts < ActiveRecord::Migration[5.2]
  def change
    create_table :posts do |t|
      t.string :user_id
      t.string :title
      t.string :description
      t.string :image

      t.timestamps
    end
  end
end

 

保存したら、rails db:migrateでマイグレーションを行います。

$ rails db:migrate
== 20191007012713 CreatePosts: migrating ======================================
-- create_table(:posts)
   -> 0.0164s
== 20191007012713 CreatePosts: migrated (0.0164s) =============================

 

CarrierWaveの追加

今回、日記には画像を差し込むので、画像ファイルを扱う必要があります。

画像ファイルを扱うためには、「CarrierWave」というgemを使用します。

このgemを利用することで、簡単に画像を扱うことができます。

./Gemfileを開き、以下の通り保存します。

・
・
・

# 画像投稿用のGemを追加
gem "carrierwave"

・
・
・

 

そして、bundle installします。

$ bundle install
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
Using rake 12.3.3
Using concurrent-ruby 1.1.5
Using i18n 1.6.0
・
・
・
Using uglifier 4.1.20
Using web-console 3.7.0
Bundle complete! 24 Gemfile dependencies, 93 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

 

次に、画像をアップロードする機能を作成するために、以下のコードを実行します。

$ rails g uploader image
/Users/alto/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/railties-5.2.3/lib/rails/app_loader.rb:53: warning: Insecure world writable dir /usr/local/bin in PATH, mode 040777
Running via Spring preloader in process 34703
      create  app/uploaders/image_uploader.rb

 

次に、config/application.rbを開き、以下の通り保存します。

require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module HelloWorldApp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

    config.autoload_paths += Dir[Rails.root.join('app', 'uploaders')]

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
  end
end

 

これは、「どこにファイルをアップロードするか」を指定しています。

今回は、app/uploaders以下にファイルをアップロードします。

.gitignoreの追加

.gitignoreを開いて、以下を加えます。

.gitignoreに追加したファイルやディレクトリは、gitの管理から除外されます。

アップロードした画像がgitの管理下にあると、開発時に画像ファイルがアップロードされる度に、全ての画像が管理されるため、public/uploadsを指定して、git管理から除外しておきます。

・
・
・
.DS_Store
public/uploads

Postモデルのバリデーションを追加

app/models/post.rbを開き、Postモデルバリデーションを追加します。

class Post < ApplicationRecord
  validates :user_id, presence: true
  validates :title, presence: true
  validates :description, presence: true
  validates :image, presence: true

  belongs_to :user

  mount_uploader :image, ImageUploader
end

imageカラムに保存されるのは、

画像ファイルではなく、画像のパス(ファイル名)です。

Userモデルにアソシエーションを追加

app/models/user.rbを開き、以下のコードを追加します。

has_many :posts

 

これで、UserモデルPostモデルアソシエーションが追加されました。

アソシエーションとは、関連付けのことで、モデル同士のつながりのことです。

例えば、今回は、一人のユーザは、複数の日記を投稿できるので、「User対Post」「1対多」となります。

そのため、Userモデルにhas_manyPostモデルにbelongs_toを追加しています。

こちらの記事も参考になります。

日記の投稿画面を作成

まずは、rails gコマンドで、日記を扱うためのコントローラを作成します。

$ rails g controller posts
/Users/alto/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/railties-5.2.3/lib/rails/app_loader.rb:53: warning: Insecure world writable dir /usr/local/bin in PATH, mode 040777
Running via Spring preloader in process 34932
      create  app/controllers/posts_controller.rb
      invoke  erb
      create    app/views/posts
      invoke  test_unit
      create    test/controllers/posts_controller_test.rb
      invoke  helper
      create    app/helpers/posts_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/posts.coffee
      invoke    scss
      create      app/assets/stylesheets/posts.scss

 

次に、touchコマンドで、日記投稿ページのビューを作成します。

$ touch app/views/posts/new.html.erb

 

app/views/posts/new.html.erbを作成したら、以下の通りに保存します。

<div class="post-new-wrapper" >
  <div class="container">
    <div class="row">
      <div class="col-md-6 col-md-offset-3">
        <h1 class="text-center">新規投稿</h1>
        <%= form_for @post do |f| %>
          <div class="form-group">
            <%= f.label :トップ画像 %>
            <%= f.file_field :image%>
          </div>

          <div class="form-group">
            <%= f.label :タイトル %>
            <%= f.text_field :title, class: 'form-control' %>
            <%= f.label :内容 %>
            <%= f.text_area :description, class: 'form-control' %>
          </div>

          <%= f.submit '投稿', class: 'btn btn-black btn-block' %>

        <% end %>
      </div>
    </div>
  </div>
</div>

 

また、ヘッダーに日記の投稿画面へのリンクを追加します。

app/views/layouts/application.html.erbを開き、以下のように保存します。

<!DOCTYPE html>
<html>
  <head>
    <title>HelloWorldApp</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' %>
  </head>

  <body>
    <header class="navbar navbar-inverse">
      <div class="container">
        <%= link_to "サンプルアプリケーション(仮)", '/', id: "logo" %>
        <nav>
          <ul class="nav navbar-nav navbar-right">
            <% if current_user %>
              <li><%= link_to '新規投稿', new_post_path %></li>
              <li><%= link_to 'ログアウト', logout_path, method: :delete %></li>
            <% else %>
              <li><%= link_to 'ログイン', login_path %></li>
            <% end %>
          </ul>
        </nav>
      </div>
    </header>
    <% flash.each do |key, value| %>
      <div class="alert alert-<%= key %>" role="alert"><%= value %></div>
    <% end %>

    <%= yield %>
  </body>
</html>

 

次に、app/controllers/posts_controller.rbを開き、以下の通り保存します。

class PostsController < ApplicationController
  before_action :require_login

  def new
    @post = Post.new
  end

  def create
    @post = current_user.posts.new(post_params)

    if @post.save
      redirect_to '/', success: '投稿しました。'
    else
      flash.now[:danger] = "投稿に失敗しました"
      render :new
    end
  end

  private

  def post_params
    params.require(:post).permit(:image, :title, :description)
  end

  def require_login
    redirect_to '/' if current_user.blank?
  end

end

 

最後に、ルーティングの設定を行います。

routes.rbに以下のコードを追加してください。

resources :posts

 

ここまで完成したら、サーバを再起動します。

(サーバ再起動)

$ rails s
/Users/alto/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/railties-5.2.3/lib/rails/app_loader.rb:53: warning: Insecure world writable dir /usr/local/bin in PATH, mode 040777
=> Booting Puma
=> Rails 5.2.3 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.1 (ruby 2.5.0-p0), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop

 

作成したユーザでログインして、以下のように、新規投稿できていればOKです。

 

ここまで完成したら、githubへプッシュしておきましょう。

 

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA