20210801のvue.jsに関する記事は3件です。

[Rails+Vue.js]〜分前を実装してみた

はじめに Q&Aサイトを作成している中で、質問の投稿時刻をTwitterのような〜分前にしたいと考えました。 しかし、Railsから渡される値をそのまま使うと、 のようになってしまいます。 そこで今回は、Moment.jsを用いて相対時刻の表示をしたいと思います。 バージョン等 Rails 6.1.3 Vue.js 2.6.11 Moment.js 2.29.1 手順 まずは、moment.jsをインストールします npm install moment --save 次に〜分前表示をしたいコンポーネント内に以下の記述をします。 <script> import moment from "moment"; export default { filters: { moment: function(date) {                 moment.locale("ja"); return moment(date).fromNow(); }, }, </script> コードの解説をすると、 moment.locale("ja");で日本語表示にしています。 returnでmoment(date)の後に、希望のフォーマットになるようにメソッドを記述します。 ここに関しては、 https://blog.capilano-fw.com/?p=1033 が参考になりました。 あとは、Vueのフィルターを使用して、 {{ question.created_at | moment }} とすると、 〜分前のフォーマットで表示することができました! まとめ Railsから渡された値を、フロント側で処理をすることができました。 また、最近ではDay.jsがMoment.jsよりも処理が早いとも聞いたのでこれから導入する方は調べてみるのもいいかもしれません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

todoリスト (Vue.js) その3

はじめに 前回は、部分削除、一括削除、タスクがない場合のコメントの表示の実施を行いました。今回は、ローカルでのデータの保存、取得を行います。 作成 ストレージにデータの保存 js/main.js watch: { todos: { handler: function(){ localStorage.setItem("todos", JSON.stringify(this.todos)); }, deep: true } }, handlerってなに?ってところでつまずきました。handlerとdeepは入れ子になったデータ(オブジェクトのプロパティ)を監視する場合に必要になるそうです。今回はtodosの状態を監視するために必要になりました。.setItem()の構文はストレージにキーの追加・更新をします。今回の場合は、todosというキーに現在のtodosの状態を追加しています。 参考文献 ストレージデータの呼び出し js/main.js mounted: function() { this.todos = JSON.parse(localStorage.getItem("todos")) || []; } JSON.parse()で文字列をJSONとして解析、.getItemでキーに対する値を返します。結果ストレージに保存されている情報を呼び出します。 感想 ローカルにストレージを保存するというとこが初めてだったので、難しく感じました。今回は理解しきれていないところが多かったのでまた復習したいと思いました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails + Vue.jsで都道府県に応じた市区町村を表示するセレクトボックスを作成する

はじめに 表題のようなセレクトボックスを作成する機会があったため備忘録として記事を残しておきます。 完成品 本記事ではrails newから始め、以下のようなセレクトボックスを作成するところまで手順を書いていきます。 環境 Ruby 2.7.3 Rails 6.0.4 Vue 2.6.14 1. 都道府県, 市区町村モデル作成 以下のER図のような都道府県(Prefecture), 市区町村(City)モデルを作成していきます。 まずはrails newでRailsアプリケーションを新規作成します。 $ rails _6.0.4_ new example_app $ cd example_app $ rails db:create 都道府県(Prefecture)モデルを作成していきます。 $ rails g model Prefecture name:string Running via Spring preloader in process 71121 invoke active_record create db/migrate/20210731145941_create_prefectures.rb create app/models/prefecture.rb マイグレーションファイルを以下のように編集しましょう。 都道府県名は一意なのでunique制約を付けておきます。 db/migrate/20210731145941_create_prefectures.rb class CreatePrefectures < ActiveRecord::Migration[6.0] def change create_table :prefectures do |t| t.string :name, null: false t.timestamps end add_index :prefectures, :name, unique: true end end マイグレーションをDBに適応させます。 $ rails db:migrate == 20210731145941 CreatePrefectures: migrating ================================ -- create_table(:prefectures) -> 0.0010s -- add_index(:prefectures, :name, {:unique=>true}) -> 0.0004s == 20210731145941 CreatePrefectures: migrated (0.0016s) ======================= モデルファイルにnameカラムのバリデーションを追記します。 app/models/prefecture.rb class Prefecture < ApplicationRecord validates :name, presence: true, uniqueness: { case_sensitive: false } end 次に市区町村(City)モデルを作成します。 $ rails g model City name:string prefecture:references Running via Spring preloader in process 71410 invoke active_record create db/migrate/20210731150527_create_cities.rb create app/models/city.rb マイグレーションファイルを以下のように編集しましょう。 市区町村は名称の重複があるためユニーク制約は付けないようにします。 db/migrate/20210731150527_create_cities.rb class CreateCities < ActiveRecord::Migration[6.0] def change create_table :cities do |t| t.string :name, null: false t.references :prefecture, null: false, foreign_key: true t.timestamps end end end マイグレーションをDBに適応させます。 $ rails db:migrate == 20210731150527 CreateCities: migrating ===================================== -- create_table(:cities) -> 0.0017s == 20210731150527 CreateCities: migrated (0.0018s) ============================ モデルファイルにnameカラムのバリデーションを追記します。 app/models/city.rb class City < ApplicationRecord belongs_to :prefecture validates :name, presence: true end また都道府県(Prefecture)モデルに市区町村(City)とのアソシエーションを追記します。 app/models/prefecture.rb class Prefecture < ApplicationRecord has_many :cities validates :name, presence: true, uniqueness: { case_sensitive: false } end 2. 都道府県, 市区町村オブジェクトを作成する 総務省のサイトから都道府県, 市区町村のリストデータ(Excelファイル)をダウンロードしましょう。 ダウンロードしたらExcelやNumbersで開きCSVファイルとして書き出しを行います。 書き出したCSVファイルをRailsアプリケーションのlib/フォルダに入れましょう。 このCSVファイルをRubyで読み込み、都道府県のデータと市区町村のデータをうまく配列に変換していきます。 CSVファイルを開いてみると以下のようになっていると思います。 1列目に自治体コード, 2列目に都道府県名, 3列目に市区町村名...といったようになっています。 lib/自治体一覧表.csv 010006,北海道,,ホッカイドウ,,, 011002,北海道,札幌市,ホッカイドウ,サッポロシ,, 012025,北海道,函館市,ホッカイドウ,ハコダテシ,, 012033,北海道,小樽市,ホッカイドウ,オタルシ,, 012041,北海道,旭川市,ホッカイドウ,アサヒカワシ,, ... このデータを使い都道府県の配列を作っていきます。 require 'csv' # CSV読み込み file_path = 'lib/自治体一覧表.csv' # CSVを1行毎の配列へ変換 csv_data = CSV.read(file_path) # => [["010006", "北海道", nil, "ホッカイドウ", nil, nil, nil], ["011002", "北海道", "札幌市", ... csv_dataを以下のように処理すると2列目の都道府県名のみの配列になります。 # 2列目のみの配列へ変換 csv_data.map { |row| row[1] } # => ["北海道", "北海道", "北海道", "北海道", ... "沖縄県", "沖縄県", "沖縄県"] # uniqメソッドを使用することで重複を削除できます prefectures_list = csv_data.map { |row| row[1] }.uniq # => ["北海道", "青森県", "岩手県", ... "宮崎県", "鹿児島県", "沖縄県"] 次に市区町村の配列を作っていきます。 市区町村オブジェクトを作成する際、都道府県名も必要となってくるため以下のような配列を作ることを目標としていきます。 [["北海道", "札幌市"], ["北海道", "函館市"], ... ["沖縄県", "竹富町"], ["沖縄県", "与那国町"]] 都道府県の配列を作ったコードに習うと以下のようなコードになると思いますが元データの都合上nilの入ったデータが出来てしまいます。 # 2, 3列目のみの配列へ変換 csv_data.map { |row| row[1, 2] } # => [["北海道", nil], ["北海道", "札幌市"], ... ["沖縄県", "竹富町"], ["沖縄県", "与那国町"]] # 3列目がnilだった場合処理を飛ばす csv_data.map do |row| next if row[2] == nil row[1, 2] end # => [nil, ["北海道", "札幌市"], ... ["沖縄県", "竹富町"], ["沖縄県", "与那国町"]] # compactメソッドで配列内のnilを削除 cities_list = csv_data.map do |row| next if row[2] == nil row[1, 2] end.compact # => [["北海道", "札幌市"], ["北海道", "函館市"], ... ["沖縄県", "竹富町"], ["沖縄県", "与那国町"]] 長くなりましたが以上でCSVデータから都道府県, 市区町村の配列が作成出来ました。上記のコードを用いてPrefectureオブジェクト, Cityオブジェクトを作成するseeds.rbを書いていきましょう。以下のようになります。 db/seeds.rb require 'csv' # CSV読み込み file_path = 'lib/自治体一覧表.csv' csv_data = CSV.read(file_path) # 都道府県データ抽出 prefectures_list = csv_data.map { |row| row[1] }.uniq # 市区町村データ抽出 cities_list = csv_data.map do |row| next if row[2] == nil row[1, 2] end.compact # 都道府県データ作成 prefectures_list.each do |prefecture| Prefecture.create!(name: prefecture) end # 市区町村データ作成 cities_list.each do |prefecture, city| prefecture = Prefecture.find_by(name: prefecture) prefecture.cities.create(name: city) end さて、初期データを作成してみましょう! $ rails db:seed Railsコンソールでデータが作成出来ているか確認してみます。 $ rails c > Prefecture.count => 47 > City.count => 1747 > Prefecture.all.each { |pref| puts pref.name } 北海道 青森県 岩手県 ... 宮崎県 鹿児島県 沖縄県 > Prefecture.find_by(name: '東京都').cities.each { |city| puts city.name } 千代田区 中央区 港区 ... 八丈町 青ヶ島村 小笠原村 都道府県, 市区町村の数を確認しましたが合っています。 ※ 市町村の数は総務省によると1,724あるそうです。これに東京都の特別区23を足すことで上記の1,747になります。 関連付けもしっかり出来ています。 20行程度のコードで都道府県, 市区町村のデータをまとめられるRuby素敵です。 以上で必要なオブジェクトは揃いました。これから表題の内容に入っていきます。 3. Vueの導入 RailsアプリケーションにVue.jsを導入していきましょう。 本章ではVueコンポーネントをerbから読み込んでHello Worldを表示していきたいと思います。 ルートページ用の適当なコントローラを作っておきます。 $ rails g controller home index ルーティングを設定しておきます。 config/routes.rb Rails.application.routes.draw do root 'home#index' end 以下のコマンドを叩いてRailsアプリケーションにVue.jsを導入します。 app/javascriptディレクトリ下にVueコンポーネントとVueコンポーネントを読み込むjsファイルが作成されました。 $ rails webpacker:install:vue ... create app/javascript/packs/hello_vue.js create app/javascript/app.vue ... Webpacker now supports Vue.js ? 以降はbin/webpackを実行してファイルの変更がある度に自動でコンパイルしておくようにします。 $ bin/webpack-dev-server Home#indexビューに作成されたVueコンポーネントを読み込むためのコードを追記します。 app/views/home/index.html.erb <%= javascript_pack_tag 'hello_vue' %> それではrails sコマンドを実行しルートパスにアクセスしてみましょう。以下のように"Hello Vue!"という文字が表示されていればVue.jsが動作しています。 4. セレクトボックスに都道府県を表示する ビューに以下を追記してフォームを表示します。 app/views/home/index.html.erb <%= form_with id: 'example_form' do |f| %> <%= f.select :prefecture, [] %> <%= f.select :city, [] %> <%= f.submit '検索' %> <% end %> <%= javascript_pack_tag 'hello_vue' %> 今回はVueコンポーネントを使用せずにerb上のタグにVueを適応させていこうと思います。app/javascript/app.vueは削除しapp/javascript/packs/hello_vue.jsを以下のように編集します。 app/javascript/packs/hello_vue.js import Vue from 'vue/dist/vue.esm'; new Vue({ el: '#example_form', data: { message: 'Hello Vue' } }); 上記ではdataにmessageという変数を宣言しています。erb内でこの変数が読み込めるかテストしてみましょう。 app/views/home/index.html.erb <%= form_with id: 'example_form' do |f| %> <%= f.select :prefecture, [] %> <%= f.select :city, [] %> <%= f.submit '検索' %> {{message}} <% end %> <%= javascript_pack_tag 'hello_vue' %> 読み込めていますね!確認が出来たらmessage変数は削除しておいてください。 それではセレクトボックスに都道府県を表示していきましょう。 都道府県のデータはデータベース上に登録されているためRails上で読み込みVue側に渡す必要があります。 RailsからVueにデータを渡す方法はいくつかありますが今回はgonというgemを使用します。 Gemfileに以下を追記しbundle installして下さい。 gonについては以下の記事が参考になります。 gonを使ったRailsとJavascriptの連携について Gemfile gem 'gon' gonを使用するためにapplication.html.erbに以下を追記します。 app/views/layouts/application.html.erb ... <%= include_gon %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> ... Prefectureモデルの中でセレクトボックスで使用する情報はidとnameになります。(idは都道府県名を表示するだけなら必須ではありませんがセレクトボックスの使用用途を考えると後々必要になると思います) というわけでindexアクション内でidとnameの情報をJSONデータに変換しVue側に渡します。 app/controllers/home_controller.rb class HomeController < ApplicationController def index gon.prefectures = Prefecture.all.to_json only: %i[id name] end end Rails側でJSONに変換して格納した変数をJavaScript側でJSON.parseメソッドを用いてJSONからオブジェクトへ変換します。 app/javascript/packs/hello_vue.js import Vue from 'vue/dist/vue.esm'; new Vue({ el: '#example_form', data: { prefectures: JSON.parse(gon.prefectures) } }); 上記のイメージがわかない場合はブラウザの開発者ツールのコンソールでコードを打ってみるといいかもです。 以上でVue側に都道府県のデータを渡せました。 あとはerb側でVueのコードを記述するだけです。v-forを使用し配列prefecturesの繰り返し処理を行います。 app/views/home/index.html.erb <%= form_with id: 'example_form' do |f| %> <%= f.select :prefecture do %> <option v-for="prefecture in prefectures" :key="prefecture.name" :value="prefecture.id"> {{prefecture.name}} </option> <% end %> <%= f.select :city, [] %> <%= f.submit '検索' %> <% end %> <%= javascript_pack_tag 'hello_vue' %> 以上でセレクトボックスに都道府県を表示することが出来ました。 ↑ 省略してますが沖縄県までちゃんと表示されています! ちなみに5章の実装を行わないのであればこんな面倒なことをしなくても以下のコードで同様の実装が出来ます。 <%= f.select :pref, options_for_select(Prefecture.all.map{ |pref| [pref.name, pref.id] }) %> 5. セレクトボックスに都道府県に応じた市区町村を表示する さて、いよいよ本題の実装に入ります。 セレクトボックスで都道府県が選択されたらVueがAjax通信を行いRails側から市区町村データを受け取る機能を実装していきます。 まずRails側で市区町村データを返す機能を実装します。 $ rails g controller cities app/controllers/cities_controller.rb class CitiesController < ApplicationController def set_cities cities = Prefecture.find(params[:id]).cities render json: cities.all.to_json(only: %i[id name]) end end config/routes.rb Rails.application.routes.draw do root 'home#index' post 'set_cities', to: 'cities#set_cities' end これで/set_citiesに都道府県のidを渡せば対応した市区町村のJSONデータが帰ってくるようになりました。 Vue側の実装をしていきます。 まずセレクトボックスで選択された都道府県のidを取得していきたいと思います。 Vueに選択された都道府県のidを格納する変数selectedPrefを定義します。また、都道府県が選択された際実行するメソッドgetCities()も定義します。 app/javascript/packs/hello_vue.js import Vue from 'vue/dist/vue.esm'; new Vue({ el: '#example_form', data: { selectedPref: '', prefectures: JSON.parse(gon.prefectures) }, methods: { getCities: function(prefecture) { console.log(prefecture); // とりあえず取得したデータをコンソール上で表示 } } }); erbを編集しselectタグにv-modelと@changeを定義します。 セレクトボックスで選択された内容がv-modelに指定された変数に格納されるようになります。 また、セレクトボックスで選択された内容が変更された場合@changeで指定されたメソッドが実行されるようになります。 app/views/home/index.html.erb <%= form_with id: 'example_form' do |f| %> <%= f.select :prefecture, nil, {}, {'v-model': 'selectedPref', '@change': 'getCities(selectedPref)'} do %> <option v-for="prefecture in prefectures" :key="prefecture.name" :value="prefecture.id">{{prefecture.name}}</option> <% end %> <%= f.select :city, [] %> <%= f.submit '検索' %> <% end %> <%= javascript_pack_tag 'hello_vue' %> それではブラウザ上で動作確認してみましょう。セレクトボックスで適当な都道府県を選択すると開発者ツールのコンソール上に対応するidが表示されると思います。 getCities()メソッドに都道府県のidが渡されることが確認出来ました。 次にAjax通信の実装をしていきます。 VueでAjax通信をするにはaxiosというライブラリを読み込む必要があります。 またAjax通信する際にCSRFトークンを作成しておかないと422エラーを吐かれます。 詳しくはこちらの記事を参考にしてみてください。 app/javascript/packs/hello_vue.js import Vue from 'vue/dist/vue.esm'; import axios from 'axios'; // CSRFトークン作成 axios.defaults.headers.common = { 'X-Requested-With': 'XMLHttpRequest', 'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content') }; new Vue({ el: '#example_form', data: { selectedPref: '', cities: [], // 取得した市区町村データを格納する変数 prefectures: JSON.parse(gon.prefectures) }, methods: { getCities: function(prefecture) { // Ajax通信 axios // /set_citiesへPOSTリクエストを送信 .post('/set_cities', { id: prefecture }) // Rails側から帰ってきたデータをcitiesへ格納 .then((response) => { this.cities = response.data }) } } }); erbを編集して市区町村名を表示するよう実装します。 app/views/home/index.html.erb <%= form_with id: 'example_form' do |f| %> <%= f.select :prefecture, nil, {}, {'v-model': 'selectedPref', '@change': 'getCities(selectedPref)'} do %> <option v-for="prefecture in prefectures" :key="prefecture.name" :value="prefecture.id">{{prefecture.name}}</option> <% end %> <%= f.select :city do %> <option v-for="city in cities" :key="city.name" :value="city.id">{{city.name}}</option> <% end %> <%= f.submit '検索' %> <% end %> <%= javascript_pack_tag 'hello_vue' %> ブラウザ上で確認してみましょう。 無事、セレクトボックスに都道府県に応じた市区町村を表示できました! ですが1つだけ問題が発生しています。 北海道を選択した際コンソールを見るとエラーが発生しています。 北海道には「泊村」が2つあるためダブってるよとエラーが出ているっぽいです。 このエラーの対応は人によって異なると思いますが手っ取り早くオブジェクトの名称を「泊村(国後郡)」のように変更しちゃえばいいのかなと思います。 参考 https://www.soumu.go.jp/denshijiti/code.html https://www.soumu.go.jp/kouiki/kouiki.html https://qiita.com/s_nakamura/items/5d153f7d9db1b1190296 https://qiita.com/ngron/items/2faae8068baa093d6aba
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む