【Rails】active_hashを使う!

フリマアプリを制作中で、active_hashを使用する機械があったので備忘録として残しておきます。これから実装する方の参考になれば幸いです。

active_hashとは?

わざわざテーブルを作成しなくても、読み込み専用情報をまとめたハッシュを扱うことができるものです。テーブルを持つほどでもない、静的なデータ(都道府県情報など不変なもの)を扱う時には便利です。 DBに変動が起きないデータをmodelに保存している場合、すぐ入れ替えることが可能でgemを導入して使用します。

導入

gemをbundleinstallします。

gem 'active_hash'
モデル(擬似モデル)を作成する

モデルを作成しますが、「rails g model~」を使用しないでモデルを手動で作成します。maigrationファイルでカラムの設定等をしない。ここが擬似モデルと言われる理由だと思います。今回はmodelに直接ファイルを作成する方法が紹介されている方法を使用します。
①appのmodelフォルダに移る
②modelフォルダ内に作成したい名前でモデルファイルを作成する
gyazo.com

モデル内の記述

①自分でモデルファイルを作成したので、当然中身は何もありません。「ActiveHash::Base」を継承して下記のようにクラスを設定します。

class Shipping < ActiveHash::Base

end

②モデル内に呼び出す静的データを記述します。
{カラム名: 値, カラム名:値}をハッシュ形式で作成しています。都道府県等どれだけ多い情報でも同様の記述で対応が可能です。

class Shipping < ActiveHash::Base
  self.data = [
    {id: 1, name: "1日〜2日で発送"},
    {id: 2, name: "2日〜3日で発送"},
    {id: 3, name: "4日〜7日で発送"},
  ]
end

③アソシエーションを組む
アソシエーションを組む時は通常とは少し違っているので注意が必要です。記述場所はそれぞれのmodelファイルで問題ありません。

1, has_manyの場合(今回はproducts.rbとアソシエーションを組んでいます)

include ActiveHash::Associations
has_many :products

2, belongs_toの場合

extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to_active_hash :shipping
viewファイルに記述する

viewファイルにcollection_selectを使って呼び出すようにします。書き方は下記の通りです。
1、「shipping_id」: form_withで送信先で登録されるレコードのカラム名を指します。
2、「shipping.all」: 擬似モデルの全ての情報を呼び出しています。
3、 {include_blank: "○○"} : セレクトボックスの中に文字列を表示させる事ができます
4、「:id, :name」 : 表示させるidとnameらしいですが、書き方として覚えてます。
5、「{class: '〇〇'}」 : クラスを設定する時は{}をつけるようにします。

= form.collection_select :shipping_id, Shipping.all, :id, :name, {include_blank: "選択してください"}, {class: '〇〇'}

gyazo.com

その他の設定

①active_hashはform_withと一緒に使っていると思うのでコントローラー上でストロングパラメーターの設定が必要です、カラム名は「shipping_id」とします。
gyazo.com

②form_withで送信された内容が保存されるテーブルにカラム名(shipping_id)を追加します。
擬似モデルで設定したid番号が入るようになります。
gyazo.com


これでactive_hashを使用して情報が送信されるようになりました!

参考サイト

github.com

pikawaka.com

【Rails × jQuery】モーダルウィンドウの実装の仕方について

レビュー(口コミ)機能を実装しましたが、見た目にださかったこともあり
簡易的なモーダル機能を使ってそれっぽくしてみました。参考になれば幸いです。

実装前

「よかった点」と「わるかった点」を書いて投稿し、内容は上にeachを回して一覧を表示するというような実装でした。Ajaxを使って非同期にしています。
gyazo.com

実装後

ボタンを押すとモーダルが立ち上がり、「よかった点」と「わるかった点」を書いて投稿が
できるというものです。Ajaxはすでに実装しているのでモーダルのコードを記述するだけで
結構簡単にできました
gyazo.com


Railsの投稿・削除機能とAjaxを使って非同期(投稿のみ)はできている前提で紹介していきます。

コントローラー

respnd_to doを使って非同期の処理をしています。

class ReviewsController < ApplicationController
  
  def create
    @review = Review.create(review_params)
    respond_to do |format|
      format.html { redirect_to "/matches/#{@review.job_id}.reviews" }
      format.json
    end
  end

end

ビューファイル(実装前)

.Review-wrapper__form
  =form_with model: [match, review], id: "new-comment", local: true do |form|
    .Review-box
      .Review-box__good
        【よかった点】
        = form.text_area :good, maxlength: 250, class: 'Review-box__text', placeholder: 'ここに文章を入力してください'
      .Review-box__bad
        【わるかった点】
        = form.text_area :bad, maxlength: 250, class: 'Review-box__text', placeholder: 'ここに文章を入力してください'
    .Review-button
      = form.submit '投稿する', class: 'Review-button__submit'

ビューファイル(実装後)

最下部にテンプしている記事を参考に次のようにコードを記入しています。モーダルのテンプレートの中にform_withを入れるだけで簡単にできます。
記事だとbootstrapも導入していますが、私の場合自分でcsswo書いていたので今回は
bootstrapの記述は省いて記載しました。

参考にした記事のコード
gyazo.com

%button{"data-target" => "#post", "data-toggle" => "modal", :type => "button"} つぶやきを投稿する   
#post.modal.fade{"aria-hidden" => "true", :role => "dialog", :tabindex => "-1"}
  .modal-dialog{:role => "document"}
    .modal-content
-#↓ここに任意のform_withを記入する
      =form_with model: [match, review], id: "new-comment", local: true do |form|
        .Review-wrapper__form
          .Review-post
            .Review-box
              .Review-box__good
                【よかった点】
              = form.text_area :good, maxlength: 250, class: 'Review-box__text', placeholder: 'ここに文章を入力してください'
              .Review-box__bad
                【わるかった点】
              = form.text_area :bad, maxlength: 250, class: 'Review-box__text', placeholder: 'ここに文章を入力してください'
        .Review-button
          = form.submit '投稿する', class: 'Review-button__submit'
-#↓閉じるボタンは記事からそのままコピーする
          %button{"data-dismiss" => "modal", :type => "button", class: 'Review-button__close'} 閉じる


これでモーダルができました!
bootstrapを使用すればもっとよかったとは思いますのでこれから勉強していきます。


参考記事
www.techry.net

【Rails】 ページネーションの実装 (ページングしても内容が重複して表示されてうまくページングができない場合の解決法)

railsでページネーションを実装しています。
他の記事でも紹介されていたのを参考に、自分でも実装をしてみましたが、実装したページングのページをめくっても同じ画面が表示されてしまいました。
簡単ですが、そんな時の解決法を紹介します。ページネーションの実装の方法は他に記事が多くありますので最下部に参考がありますのでそちらをご参照ください。

1 kaminariジェムのインストール

gem 'kaminari'

2 bundle installを入力してインストールします。

% bundle install

3 view画面に「= paginate matches」を記入します。
(今回はhamlで記入、部分テンプレートを使用しているので@matchesではなくmatchで使用しています。)

.Under-wrapper
    .Bar-left
      .Bar-left__upper
        .Bar-left__upper--title
          応募可能な全てのお仕事を公開しています
        .Bar-left__upper--text
          = paginate pages           ←ここを追加します

3-1該当するコントローラーにコードを追加します。←ここがポイントでした
記事を参考に私が書いたコードです。@pagesの部分がページングで必要なコードです。

class MatchesController < ApplicationController
  
  def index
    @matches = Job.all.order("created_at DESC") 
    @pages = Job.all.page(params[:page])
  end

確かにこれでも下記のように表示はされますが,いざページをめくってみても表示される項目は一緒(重複)の状態でした.....

gyazo.com


3-2私の場合すでに@matchesでJobの一覧を表示していましたが、インスタンス変数をもう一つ作成(@pages)して値を呼ぼうとしていました。これが間違いで@matchesで作成したものに「.page(params[:page])」を追加すれば無事にページングもしてくれるようになりました。

class MatchesController < ApplicationController
  
  def index
    @matches = Job.all.order("created_at DESC").page(params[:page]).per(3)
  end

ローカル変数も「pages」から「matches」に変更します。

.Under-wrapper
    .Bar-left
      .Bar-left__upper
        .Bar-left__upper--title
          応募可能な全てのお仕事を公開しています
        .Bar-left__upper--text
          = paginate matches           ←ここを追加します

これで解決しました!
.per()などの説明は下記の参考記事等をご覧ください。
ページングのデザインの変更方法も記事をご覧ください。

参考記事
公式:
github.com

わかりやすいページネーションの実装の仕方
qiita.com

設定変更のあれこれ
nekorails.hatenablog.com

間違いに気付いた記事
stackoverflow.com

アプリを作成後、rails sを押した時にこんなエラーがでてしまったので
備忘録として残しておきます。

エラー内容は下記の通り。

ActiveRecord::PendingMigrationError (

Migrations are pending. To resolve this issue, run:

        rails db:migrate RAILS_ENV=development
):

指定された、コマンドを打っても解決しない、、、、、、どうするべきか?
まずDBのステータスをみます。(rails db:migrate:status)

chat-space % rails db:migrate:status

database: chat_space_development

 Status   Migration ID    Migration Name
--------------------------------------------------
  down    20200726062225  Devise create users
  down    20200728052202  Create groups
  down    20200728053005  Create group users
  down    20200731034659  Create messages
   up     20200822044159  ********** NO FILE **********
   up     20200825150117  ********** NO FILE **********
   up     20200825150130  ********** NO FILE **********
   up     20200826133011  ********** NO FILE **********

なんじゃこれ?となってしまいましたが、
ここで「rails db:reset」コマンドを入力します。
このコマンドを押すと、DBの中のデータが全て消えてしまうので注意が必要。

hat-space % rails db:migrate:status

database: chat_space_development

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20200726062225  Devise create users
   up     20200728052202  Create groups
   up     20200728053005  Create group users
   up     20200731034659  Create messages

結果としてdownの状態になっていたものがUpに変更になりました。
これでrails sを押してサーバーを立ち上げることができました!

rails db:migrate実行時にreferencesを使った外部キー制約ができない時の対処法について

個人アプリを制作している時にmySQLでテーブルを作成しようとすると
rails で外部キー制約をかける時にエラーが発生したので、その対処法についてご紹介します。

外部キーの設定をしようとした時に、referencesを使用してrails db:migrateをかけたところエラーが発生しました。1対多と多対多のリレーションでも同じようなエラーが発生します。

class CreatePrJobs < ActiveRecord::Migration[6.0]
  def change
    create_table :pr_jobs do |t|
      t.references :pr, foreign_key: true
      t.references :job, foreign_key: true

      t.timestamps
    end
  end
end

エラー内容

== 20200905041353 CreatePrJobs: migrating =====================================
-- create_table(:pr_jobs)
rails aborted!
StandardError: An error has occurred, all later migrations canceled:

Column `pr_id` on table `pr_jobs` does not match column `id` on `prs`, which has type `bigint(20)`. To resolve this issue, change the type of the `pr_id` column on `pr_jobs` to be :bigint. (For example `t.bigint :pr_id`).
Original message: Mysql2::Error: Cannot add foreign key constraint
/Users/shunjiro/rails-self-project/Dispatch-site/db/migrate/20200905041353_create_pr_jobs.rb:3:in `change'
/Users/shunjiro/rails-self-project/Dispatch-site/bin/rails:9:in `<top (required)>'
/Users/shunjiro/rails-self-project/Dispatch-site/bin/spring:15:in `<top (required)>'
bin/rails:3:in `load'
bin/rails:3:in `<main>'

色々と調べると下記が原因とわかりました。

原因

  • デフォルトのidカラムはinteger型で作成されるが、rails5.1以降からはbignit型で作成される
  • referencesをつかった書き方だと型が合致せず、エラーとなるので揃えてやる必要がある。

対処方法

  1. referencesをつかう時にidキーをinteger型に変更する
  2. referencesを使わない外部キー設定にする (参考記事をご参考ください)

2番目の方法を試すとがなぜかダメでした、仕方なく1番目のreferencesを使わない書き方で
rails db:migrateを実行したところ解決しました!

class CreatePrJobs < ActiveRecord::Migration[6.0]
  def change
    create_table :pr_jobs do |t|
      t.integer :pr_id, foreign_key: true
      t.integer :job_id, foreign_key: true

      t.timestamps
    end
  end
end

今までreferencesで設定できていましたが突然できなくなってしまったので、
勝手にバージョンを上げてしまったことが原因だと思います。

参考記事:
qiita.com

github.com