エンジニア転職日記

エンジニア転職に向けての日記です

How to ActiveHash

概要

今回は、カテゴリー選択や都道府県選択などのセレクトボックスに用いる、ActiveHashを解説します。

ActiveHashとは

ActiveHashとは、都道府県やカテゴリーなど、基本的に変更されないデータをモデルに記述し、あたかもデータベースに保存されているかのように取り扱うことができるgemです。これらのデータはユーザーや管理者が編集して値を増やすということを後から行わないので、データベースに保存する必要がありません。ActiveHashを用いると、データベースに保存していないのにもかかわらず、ActiveRecordのメソッドを用いることができるようになります。

使い方

事前準備

まずは、アプリケーションの雛形を作成します。

% cd
% cd projects
% rails _6.0.0_ new active_hash_app -d mysql
% cd active_hash_app
% rails db:create

 

Gemfileを編集します。

gem 'active_hash'

bundle installを実行して、事前準備は完了です。

 

モデル作成

Articleモデルを作成します。

% rails g model article

 

Genreモデルを作成します。

% rails g model genre --skip-migration

--skip-migrationをオプションにつけることでマイグレーションファイルの作成をスキップし、テーブルの作成を阻止しています。

 

Genreモデルを記述していきます。

# app/models/genre.rb
class
Genre < ActiveHash::Base
self.data = [ { id: 1, name: '--' }, { id: 2, name: '経済' }, { id: 3, name: '政治' }, { id: 4, name: '地域' }, { id: 5, name: '国際' }, { id: 6, name: 'IT' }, { id: 7, name: 'エンタメ' }, { id: 8, name: 'スポーツ' }, { id: 9, name: 'グルメ' }, { id: 10, name: 'その他' } ] end

ActiveHash::Baseを継承することで、ActiveHashを使えるようになります。Active::Baseでは、ActiveRecordと同様のメソッドが使用できます。

 

Articleモデルのマイグレーションファイルを編集します。

class CreateArticles < ActiveRecord::Migration[6.0]
 def change
   create_table :articles do |t|
     t.string     :title        , null: false
     t.text       :text         , null: false
     t.integer    :genre_id     , null: false
     t.timestamps
   end
 end
end

t.integer :genre_id とすることによって、articleテーブルにジャンルのIDを保存できるようにしています。記述できたら、rails db:migrateを実行します。

 

Articleモデルを編集します。

class Article < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :genre

  #空の投稿を保存できないようにする
  validates :title, :text, :genre, presence: true

  #ジャンルの選択が「--」の時は保存できないようにする
  validates :genre_id, numericality: { other_than: 1 } 
end

belongs_to_active_hashメソッドが、アソシエーションの役割を果たしています。

なお、Genreモデルにはアソシエーションの記述は必要ありません。

 

記事一覧表示機能の実装

ルーティングを設定します。

Rails.application.routes.draw do
  root to: 'articles#index'
  resources :articles
end

 

コントローラーを作成します。

% rails g controller articles index new

 

記事一覧がビューに表示されるよう編集します。

class ArticlesController < ApplicationController
  def index
    @articles = Article.order("created_at DESC")
  end

  def new
  end
end

 

index.html.erbを編集します。

<h1>記事一覧</h1>
<%= link_to "投稿する", new_article_path, class:"post" %>

<% @articles.each do |article| %>
  <div class="article">
    <div class="article-genre">
      <%= article.genre.name %>
    </div>
    <div class="article-title">
      <%= article.title %>
    </div>
    <div class="article-text">
      <%= article.text %>
    </div>
  </div>
<% end %>

CSSを記述します。

h1{
  text-align: center;
}

.post{
  display: block;
  width: 150px;
  padding: 10px;
  border: 1px solid white;
  background-color: orange;
  color: white;
  text-decoration: none;
  text-align: center;
  margin: 0 auto;
  margin-bottom: 20px;
}

.article{
  height:200px;
  background-color:lightgray;
  display: flex;
  align-items: center;
  flex-direction: column;
  border: 1px solid #fff;
  padding: 20px;
}

.article-genre{
  font-size: 16px;
  border: 1px solid;
  padding: 5px;
  background-color: lightblue;
}

.article-title{
  font-size: 20px;
  font-weight: bold;
}

 

投稿機能の実装

コントローラーを編集します。

class ArticlesController < ApplicationController

  def index
    @articles = Article.order("created_at DESC")
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)
    if @article.save
      redirect_to root_path
    else
      render :new
    end
  end

  private

  def article_params
    params.require(:article).permit(:title,:text,:genre_id)
  end

end

 

new.html.erbを編集します。

<%= form_with model: @article, url:articles_path, local: true do |f| %>
  <div class="article-box">
    記事を投稿する
    <%= f.text_field :title, class:"title", placeholder:"タイトル" %>
    <%= f.text_area :text, class:"text", placeholder:"テキスト" %>
    <%= f.collection_select(:genre_id, Genre.all, :id, :name, {}, {class:"genre-select"}) %>
    <%= f.submit "投稿する" ,class:"btn" %>
  </div>
<% end %>

f.collection_selectメソッドを使用することで、データをプルダウン形式で表示することができます。

 

CSSを記述します。

.article-box {
  height:800px;
  background-color: lightgray;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.title {
  height: 30px;
  width: 300px;
  margin: 20px;
}

.text {
  height: 100px;
  width: 300px;
  resize:none;
  margin-bottom: 20px;
}

.genre-select{
  height: 30px;
  width: 250px;
}

.btn {
  width: 200px;
  margin-top: 20px;
  padding: 15px;
  border: 1px solid white;
  background-color: orange;
  color: white;
}

 

ブラウザで確認してみて、ジャンルがプルダウン形式で表示され、ArticlesテーブルにIDが保存されていれば実装完了です。