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が保存されていれば実装完了です。