20210801のRubyに関する記事は9件です。

binding.pryを使えるようになりたい!

はじめに 本記事は、「binding.pry」を今後活用できるようにするため、 現時点で学習したことをアウトプットします。 インストール pry-railsというGemをインストールする必要があります。 Gemfileに以下のコードを記述します。 gem 'pry-rails' その後、ターミナルにてbundle installします。 「binding.pry」に限らず、Gemをインストールする際には、bundle installします。 エラーが発生した場合、原因がどのコードにあるのかを「binding.pry」を使って確認することができます。 コードで「binding.pry」という文字列をコード内に記述すると、 そこで、処理が止まります。 その後からの処理の結果を手動で確認することができます。 例文 class OrdersController < ApplicationController def index @order = Order.new end def create @order = Order.new(order_params) binding.pry if @order.valid? @order.save return redirect_to root_path else render 'index' end end private def order_params params.require(:order).permit(:price) end end 今回は、Ordersコントローラーのcreateアクションにエラーはないのかを確認するために、 9行目で、「binding.pry」を発動しています。 ここで「rails s」サーバーを起動させ、 指定した行為を実行すると、 ターミナル上で、 [1] pry(#<OrdersController>)> と表示されます。 その後からの処置がどうなるのかを試したい時に、 その後の処理を記述することで、結果を確認することができます。 10行目で、 if @order.valid? という記載があるので、 [1] pry(#<OrdersController>)> @order.valid? と記述します。 すると、 [1] pry(#<OrdersController>)> @order.valid? => false コード全体を記述していないため、わかりづらいですが、 結果は、「エラー」となりました。 *「valid?」は、エラーがある時は「false」、ない時は「true」となります。 コントローラーのcreateアクションでミスが発生しているということですね。 終わり 学習段階で、ここまでの理解です。 正直申し上げると、理解が浅く、使いこなせるレベルまで到達していないことが、 今回投稿してみてわかりました。 明日、メンターへさらに理解をするために、 質問し、理解を深めます。 さらに深く説明できるようになれば、また投稿したいと思います。 それでは、引き続きがんばりましょう!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MVCについて(仕事で実際に触れてみて)思ったこと

イントロダクション 4月より転職してエンジニアとして働いています。 業務ではRails、フロントはVue.jsを使用した開発に携わらせてもらっています。 タイトルの通り、MVCモデルについて実務を通して思ったことを書いていくのですが、せっかくなので、自分の知識の復習も兼ねてMVCモデルとはというところから話してみたいと思います。 MVCとは ググればめちゃくちゃ記事出てくるのと、本筋ではないのでさっくりと書かせていただきます。 M(モデル)・・・データを加工する場所 C(コントローラー)・・・データをモデルやビューに受け渡す場所 V(ビュー)・・・見た目を整える場所 それぞれ上記のように役割を明確にすることで、開発をしやすく、かつ保守なども行いやすいというメリットがあります。 実際、僕のような業務に入り始めて間もないものでも、このMVCモデルのおかげで開発に携われるようになっています。 レストランで例えると キッチン・・・モデル。データ(食材)を美味しい料理に加工する ウェイター・・・コントローラー。加工された料理をお客様のもとに運んだり、お客様から受け取った注文をキッチンに伝えたりする。 ビュー・・・料理そのもの。見た目整えればお客様の食欲そそる(UI向上)。 自分なりにMVCモデルについてなにかわかりやすい例えないかなと考えた結果、レストランめっちゃわかりやすいやん! って思ったけど、調べてみたら結構これも記事にされていた(本当に自分で考えましたよ!)。 MVCのメリットって? さっきも書きましたけど、M・V・Cそれぞれで明確に役割を持っているので、開発しやすい。 また、モデルだけ改善させたいのよね〜とかいうときに改善させやすい。 実務で扱っていてエラーが起きたとしても、どこでエラー起きているのか判断しやすいというのもメリットかと感じています。 MVCのデメリットって? 現状、Railsしか経験していないため、もしかしたらRailsに限ってしまうかも知れませんが、 モデルで行うべき処理をコントローラーで行えてしまうというのが今の所僕が感じる最大のデメリットかなと感じています。 本来、データの加工などはモデルで行うべきとされていますが、Railsのその自由度のおかげでコントローラーで書いても正常に動いてしまいます。 その瞬間はそれで良いのかも知れませんが、コントローラーをファットにしてしまうと、その後機能を追加しようとしたときにボディブローのように効い来ている場面を見かけます。 そして、いざどうしようもなくなったときにコントローラーをリファクタリングすることになり、結局モデルにビジネスロジックを移行するという作業が増えてしまう(もしくは複雑になりすぎて手が出せないということになりかねない)。 まとめ 一言でまとめると「取り返しがつかないことになるかも知れないので、コードを書くときはMVCの役割に沿った場所で書くべき」なのだと実務を通して感じております。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

開発環境の構築を自動化するシェルスクリプト[Xcode, Homebrew, Ruby, MySQL]

この記事の目的 今週の初めに以下の手順通り、Homebrewのインストールから、Rubyのセットアップまで、開発環境の構築を行いました。 そして今週の終わりに、この手順を自動化するシェルスクリプトを作成しました。初めて作成して、自動化の有益性を実感したのでここに記します。 App/construct_dev.sh 以下がシェルするクリプトです。 #!/bin/bash # 環境変数 RUBY_VERSION=2.7.1 MYSQL_VERSION=5.7 RAILS_VERSION=6.0.3 DATABASE_HOST=127.0.0.1 LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" # 必要なパッケージのインストール sudo curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | bash git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask fetch --unshallow brew update brew install ruby rbenv ruby-build mysql@$MYSQL_VERSION shared-mime-info gnu-sed # プロジェクト配下に移動 cd ~/App # Rubyのセットアップ rbenv install -s $RUBY_VERSION rbenv local $RUBY_VERSION rbenv rehash # rubyとmysqlそれぞれにパスを通す echo 'eval "$(rbenv init -)"' >> ~/.zshrc echo 'export PATH="/usr/local/opt/mysql@'$MYSQL_VERSION'/bin:$PATH"' >> ~/.zshrc source ~/.zshrc # 環境変数の設定 cp .env.example .env gsed -i 's/DATABASE_HOST="0.0.0.0"/DATABASE_HOST="'$DATABASE_HOST'"/' .env # 外部ライブラリのバージョン管理 bundle config --local build.mysql2 --with-ldflags=$LDFLAGS # ローカルのRailsをセットアップ gem install rails -v $RAILS_VERSION # DBの起動 brew services start mysql@$MYSQL_VERSION # Railsアプリケーションのセットアップ bundle install rails db:create rails db:migrate rails db:seed スクリプトの説明 ここではスクリプトの実行条件と実行手順などを説明します。 スクリプトの実行条件 ローカルでgit cloneができる状態であること clone先にこのスクリプトファイルが存在すること リモートリポジトリに環境変数を管理する.env.exampleファイルが存在すること スクリプトの実行手順 ① プロジェクトのクローン $ git clone git@github.com:user_name/repogitory_name.git ~/App ② スクリプトの実行 この時、XcodeとHomebrewそれぞれのインストールのために、パスワードの入力が2回求められます。 $ bash ~/App/construct_dev.sh ③ Railsアプリの起動 $ rails s ④ ローカルホストにアクセス スクリプトのこだわりポイント 環境構築の手順を極限まで省略していること git clone以外の作業をほぼ自動化していること(素晴らしい!w バージョン管理を環境変数を用いて管理していること これはまさにスクリプトで環境構築をする利点で、開発環境をコードで管理できるようになります Mac環境に合わせて、ファイル内の文字の置換にgsedを用いていること gsed -i 's/DATABASE_HOST="0.0.0.0"/DATABASE_HOST="'$DATABASE_HOST'"/' .env 参考記事 gsedコマンドについて mysql2がbundle installできないエラーについて この記事は以上です!シェルスクリプトは初めて記述しましたが、とても便利で個人的に他にも作成してみたいと思いました!最後までお読み頂きありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

挿入順を覚えている連想配列

これは何? Ruby の Hash には shift があることの紹介。 と思って調べたら、 Python3 の dict にも順序があるのがあったので、それも紹介。 Ruby の Hash Ruby の Hash は挿入順を覚えている。 挿入順を利用して古いものから順に取り出せる。 以下のような感じ。 ruby h={foo:111,bar:22,hoge:3} h[:bar]=44 h[:baz]=55 s="" while ! h.empty? do s += h.shift.inspect end p s #=> "[:foo, 111][:bar, 44][:hoge, 3][:baz, 55]" 先頭の値を見る first と、先頭の値を撤去する shift はあるけど、末尾を扱う last と pop は無い。 ruby {a:1}.first #=> [:a, 1] {a:1}.last #=> NoMethodError: undefined method `last' {a:1}.shift #=> [:a, 1] {a:1}.pop #=> NoMethodError: undefined method `pop' 値の追加がないのはわかるけど、末尾の値が扱えないのは不思議。 あと、Hash の first は引数ありなし両方あるけど、shift は引数なし。 ruby {a:1,b:2}.first(2) #=> => [[:a, 1], [:b, 2]] {a:1,b:2}.shift(2) #=> ArgumentError: wrong number of arguments (given 1, expected 0) [1,2].shift(2) #=> [1, 2] これも対応してくれればいいのにと思う。 Hash 内には挿入順が記憶されているのに、 == での比較では挿入順が度外視されるので ruby x={a:1,b:2} y={b:2,a:1} p(x==y) #=> true p([x.first, y.first]) #=> [[:a, 1], [:b, 2]] このように、等値であるオブジェクトに同じメソッドを送っても違う結果になったりする。 歴史的経緯からまあそうするしかないかとも思うけどわかりにくいよね。 Hash が挿入順を覚えていて、古い順から取り出せるので、ある種の探索アルゴリズムで役に立つ。 見つかったものを Hash に挿入しつつ、先頭から取り出して消費するという流れとか。 Python3 の dict この記事を書くにあたって調べて初めて知ったんだけど、Python3 の dict にも挿入順が入っている。 Python3 d = { "foo":111, "bar":22, "hoge":3 } d["bar"] = 44 d["baz"] = 55 s="" while d: s += repr(d.popitem()) print(s) #=> ('baz', 55)('hoge', 3)('bar', 44)('foo', 111) この popitem() は、 3.7 で「LIFO 順序が保証されるようになりました。」 とのこと。そりゃ知らなかったわけだ。 collections.OrderedDict の popItem には引数があって、末尾から取るか先頭から取るかを選べるんだけど、普通の dict の popItem には引数がない。必ず末尾から。なぜなのか。しかも ruby と逆。 辞書に入っている先頭要素は Python3 d = { "foo":111, "bar":22, "hoge":3 } iter(d.items()).__next__() #=> ('foo', 111) と、items() と iter() を使えば撤去せずに取得できるけど、もっと簡単な方法がありそうな気がする。 一方、popitem() で容易に 撤去+取得 できる末尾の要素だが、これを撤去せずに取得する方法は Python3 d = { "foo":111, "bar":22, "hoge":3 } iter(reversed(d.items())).__next__() #=> ('hoge', 3) と、むしろ面倒になる。これももっと簡単な方法がありそうな気がする。 まとめ ruby Python3 先頭を撤去せずに取得 h.first iter(d.items()).__next__() 先頭を撤去して取得 h.shift 表外下記 末尾を撤去せずに取得 不可能だと思う iter(reversed(d.items())).__next__() 末尾を撤去して取得 不可能だと思う d.popitem() Python3 の「先頭を撤去して取得」は、 firstkey = iter(d).__next__() で、先頭のキーを取得 firstval = d[firstkey] で、先頭の値を取得 del[firstkey] で、先頭の要素を撤去 という三手で実施可能。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails] VSCodeを入れたらやること

はじめに ほとんどの方が開発するために用いるエディタとしてVSCodeを使っていることでしょう。 Railsで開発していく上で私が初めてVSCodeを導入したときに、最低限入れておくべきと思った、拡張機能や、設定を忘れないうちに記事に残しておきたいと思います。 もしおすすめ拡張機能があれば教えていただけると幸いです。 よろしくお願いします。  ##VSCodeの日本語化 我々が親しんでいる日本語で表示させたい人はまずはこれをするべきですね。 英語の方が使いやすいって人や、ストイックな人はする必要はないです。 拡張機能の検索に「Japanese Language Pack for Visual Studio Code」と打ち込むと出てきます。 検索予測で出てくるので全部打ち込む必要はありません。 インストールした後、再起動しないと反映されなかったりするので気を付けましょう。 HTML/CSS自動補完機能 続いてHTMLとCSSの自動補完をしてくれる拡張機能を入れます。 拡張機能の検索フォームで「HTML Snippets」で検索してインストールします。 Rubyの構文チェック Rubyの構文チェックをしてくれます。Rubyを使って開発をするのであれば必須でしょう。 拡張機能の検索フォームで「Ruby」と検索すると出てきます。 全角スペースのチェック機能 全角スペースにより、動作しない場合、それを見つけるのは苦労します。 全角スペースになっているところを検出してくれる拡張機能です。 拡張機能の検索フォームで、「zenkaku」と入力すれば出てきます。 zenkakuを利用するにはまだ設定が必要です。 インストールが完了した後「command + shift + p」の三つのキーを同時に入力し、コマンドパレットという設定ファイルの検索画面を開きます。 そこに「> Enable zenkaku」と入力して選択します。 「command + Q」の二つのキーを同時に入力してVSCodeを終了させます。 続いて常にzenkakuをONにしておくための設定もしておきます。 finderでホームディレクトリを開く command + shift + .で隠しディレクトリを表示する  > .vscode > extensions > mosapride.zenkaku-0.0.3 > と移動する extension.jsを2本指タップしてメニューを表示する 「このアプリケーションを開く」から「テキストエディット」を選択する 5行目の「var enabled = false;」を「var enabled = true;」に変更してcommand + Sで保存する これで完了です。 コードのスペルチェック コードのスペル間違いを指摘してくれる拡張機能を追加します。 拡張機能の検索フォームで「Code Spell Checker」と入力してインストールします。 オートセーブ設定 最後に拡張機能ではなくVSCode自体の設定をいじります。 「command + , 」で設定画面を開けます。 一番上のAuto Saveというところのプルダウンから「onFocusChange」を選択します。 最後に あくまでこれは私が最初に行った設定です。他にも便利機能や必須の拡張機能や設定があれば教えて欲しいです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

新規登録画面実装② devise 新規登録の項目追加 別モデルから取得

やりたいこと devise導入済みです。 ①の記事では、userモデルのカラムを deviseの新規登録画面に表示、登録できるようにしましたが、 今回は別モデルであるDepartment(部署)を登録したいです! 3時間程戦いました・・・。 departmentとuserの関係は、1:Nにしてます。 (userは1つの部署に所属。部署は複数のuserを持つ) modelファイルにアソシエーション ここら辺はなんてこと無く出来ました。 models/user.rb belongs_to:department models/department.rb has_many:users, dependent: :destroy マイグレーションファイル class CreateDepartments < ActiveRecord::Migration[5.2] def change create_table :departments do |t| t.string :name,null: false   #表示名 t.string :correct_name #正式名称 t.timestamps end end end 部署名は、会社によっては長くなりがちで、、あまり長いと厄介なので、 表示名と正式名称でカラムを分けました。 class DeviseCreateUsers < ActiveRecord::Migration[5.2] 省略 t.integer :department_id,null:false 省略 department_idは外部キーです。 部署idを登録させる  Applicationコントローラー class ApplicationController < ActionController::Base # ユーザー認証などが行われる前に、configure~が実行される before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters # デフォルトにないname/join_year/部署を追加しているので、それらを許可するよう記載している devise_parameter_sanitizer.permit(:sign_up, keys: [:name,:join_year,:department_id]) end end ちゃんとdepartment_idを受け取って保存するように指示します。 新規登録画面に入力フォームを追加 <div class="form-group"> <%= f.label:"所属先" %><br /> <%= f.collection_select(:department_id, @departments, :id, :name, class: "form-control") %> </div> これで、完成!!!!だと思ってました...。 しかしこれだと@departmentsを渡せてないので、 undefined methodmap' for nil:NilClassというエラーが出てきます。 どこに@departmentsの値を定義すれば・・・・? @departmentsの値を定義する controllers/users/registrations_controller.rbに書きます! あることに気づかず、rails g devise:controllers usersをやってしまいました。 (無ければ、rails g devise:controllers usersで、コントローラー作れます) class Users::RegistrationsController < Devise::RegistrationsController # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] def new @user = User.new @departments = Department.all end 省略 ルーティングを直す 上記のコントローラーを通過してビューを表示してほしいので、ルーティングを直します。 routes.rb Rails.application.routes.draw do devise_for :users, controllers: { registrations: 'users/registrations' } # devise_for :users  ←元々はコレだった マイページでの部署の表示 users/show/html.erb 省略 <div style="text-align:center;"><%=link_to departments_path do %><%= user.department.name %><% end %></div> <div style="text-align:center;"><%= user.name %></div> 省略 完成! 無事に部署の登録、マイページでの表示に成功しました!! 参考にさせていただいた記事 ありがとうございます!この記事のおかげでなんとか実装できました!
  • このエントリーをはてなブックマークに追加
  • 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で続きを読む

BEM記法とは?Bootstrapとの併用は難しい・・・[初心者]

初めに ポートフォリオ制作でBEM記法を取り入れていきたいと思いましたが... Bootstrapを導入しているため、出来そうにないということに気づきました。 (BEM記法に触れていないレベルで、Bootstrapとの併用は高度すぎるように感じました) 色々調べて自分なりに理解したことをまとめていきます。 BEM記法って何? CSSの命名規則。BEM記法にのっとり、記述すればココはあそこの記述ね!というのが自分以外の人が見ても、わかりやすい。 ただし、コードが長くなりがち。 B:Block (ブロック)でっかい括り E:Element(エレメント) でっかい括りの中の要素 M:Modifier(モディファイアー・修飾語という意味) 上記2つの変化球 とのこと。 この順番でクラス名を決めていくらしい。(block_element--modifireのように) 実際にどう記述するのか <button type="button" class="form__btn">送信</button> <button type="button" class="form__btn form__btn--disabled">送信</button> <nav class="nav"> <ul class="nav__list"> <li class="nav__item"><a href="">menu</a></li> </ul> </nav> ここで気付く... Bootstrapでは、"btn btn-primary"や、"nav navbar"とか書いて、ボタンやら、ナビゲーションバーを表示していました。もしここにBEM記法のクラス名を導入したら... かなり長くゴチャゴチャになってしまうのでは....????? BEM記法とBootstrapは併用できるのか? 相性が悪いというのはやはりあるらしい。 考えたこと Bootstrap使うところは、Bootstrapの命名規則に従って、Bootstap使わないところはBEM記法で書くのはどうだろうか?? 一つの Web システム内に2つの命名規則が混在してしまうことになる...ややこしい・・・ こうすれば綺麗に併用できるらしい 正直、今のレベルで...ポートフォリオ制作期限もある中で...自身のポートフォリオでBEM記法とBootstapをうまく併用するのは無理だと感じました。 BEM記法について 参考にした記事 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】ストロングパラメーターってなに???

対象者 ストロングパラメーターに関して知りたい方 ストロングパラメーターの入力方法を知りたい方 目的 ストロングパラメーターのメソッド1つ1つの意味を考えながら使うこと 実際の手順と実例 1.ストロングパラメーターって?? 結論から言うと、ストロングパラメーターとは、データ送信時に不正なリクエストによって予期しない値に変更されてしまう脆弱性(マスアサインメント脆弱性)を防ぐ仕組みです。 私個人的に不正アクセスを防ぐ仕組みくらいに考えています。 2.書き方 1.基本構文 private def user_params params.require(:キー(モデル名)).permit(:カラム名1,:カラム名2,・・・).marge(カラム名: 入力データ) end 以下は例になります user_controller.rb def edit @user = User.find(params[:id]) end def update @user = User.find(params[:id]) if @user.update(user_params) redirect_to user_path(@user), notice: "You have updated user successfully." else render "edit" end end private def user_params params.require(:user).permit(:name, :introduction, :profile_image) end 2.private privateは一種の境界線のようなもので、 「ここから下はControllerの中でしか呼び出せません」という意味を持ちます。 3.requireメソッド 引数にしたいキーを指定する場所 例では,(:user)に当たります。 キーの値に対するデータを抽出したい場合上記例のように書きます。 4.permitメソッド 許可された値のみを取得することができます。 permitに記載のないカラムは、保存や更新が実行されません。 5.ストロングパラメーターの呼び出し user_controller.rb def update @user = User.find(params[:id]) if @user.update(user_params) redirect_to user_path(@user), notice: "You have updated user successfully." else render "edit" end end 上記例のUpdateアクション抜粋です。 if文の(user_params)の部分でストロングパラメーターを呼び出しています。この他にもcreate,new等でこのように記述する場合が多いです。 参照 Rails4 | 新規・変更機能 | マスアサインメント機能と脆弱性とStrong Parameters 投稿者コメント 先日ストロングパラメーターに記載がないことが理由で作業が前に進まなかったので、このように記事にして改めて認識をまとめてみることにしました。 構文こぴぺして使っていただけると嬉しいです。 My Profile プログラミング学習歴3ヶ月目のアカウントです! プログラミングスクールで学んだ内容や自分が躓いた箇所等のアウトプットの為に発信しています。 また、プログラミング初学者の方にわかりやすく、簡潔にまとめて情報共有できればと考えています。 もし、投稿した記事の中に誤り等ございましたら、コメント欄でご教授いただけると幸いです。 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む