- 投稿日:2020-04-30T23:43:55+09:00
【�database.yml】DBをDockerとrails server両方で使えるように�設定
Dokerで開発時に、
docker-compose runやdocker-compose runよりも早いrails serverで一時的に動作確認をしたい場合があるかと思う。
そういった場合にも、以下のconfig/database.yml内の記述だけで対応することができる。検証環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.3 BuildVersion: 19D76$ ruby -v ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin19]$ rails -v Rails 5.2.4.2database.ymlについて
まず、database.ymlとは
config/database.yml(例)default: &default adapter: mysql2 encoding: utf8 collation: utf8_general_ci pool: 5 host: <%= ENV['MYSQL_HOST'] || 'localhost' %> username: <%= ENV['MYSQL_USERNAME'] || 'root' %> password: <%= ENV['MYSQL_PASSWORD'] || '' %> socket: /tmp/mysql.sock主な内容
adapter: 使用するデータベースの種類(postgresql, mysql2等)
encoding: 文字コード
collation: MySQLの文字列と照合順序(ソート順)、”文字コード言語名比較法”で構成される
pool: 確保する接続プールの数
host: データベースが動作しているホスト名またはIPアドレス
username,password: データベースに接続するユーザー名・パスワード
socket: DB通信の接続口
比較演算子: ||
orと同じ働きをする。
Ruby 2.7.0 リファレンスマニュアル 演算子式文法:
式 `||' 式
式 or 式
左辺を評価し、結果が真であった場合にはその値を返します。左辺の評価結果が偽であった場合には右辺を評価しその評価結果を返します。config/database.ymlのhost,username,passwordの部分をこれで書くことで、
ENV['MYSQL_HOST']等の環境変数がない場合に、localhost等を返してくれる。終わりに。
最後まで読んで頂きありがとうございます
転職の為、未経験の状態からRailsを学習しております。正しい知識を着実に身に着け、実力のあるエンジニアになりたいと考えています。継続して投稿していく中で、その為のインプットも必然的に増え、成長に繋がるかと考えています。
今現在、初心者だからといって言い訳はできないですが、投稿の内容に間違っているところや、付け加えるべきところが多々あるかと思いますので、ご指摘頂けると幸いです。この記事を読んで下さりありがとうございました。参考にさせて頂いた記事
- 投稿日:2020-04-30T22:29:15+09:00
テストをまともにやってこなかったから、rspec-railsを使ってモデルの単体テストを初めてまともにやってみた話。
超簡単なモデルの単体テストをやってみる。
前回せっかくミニアプリまで作ったので、今までまともにやってこなかったモデルの単体テストもやってしまおう!
と、今回は、超簡単な単体テストを実施しました。
テスト環境の準備が色々あったので備忘録として記載します。動作環境
ruby 2.5.1
rails 5.2.4.2下準備
modelとかmigration等、ここまでの環境は前回記事の下準備をご覧ください。
テスト環境の準備
gemをインストール
.Gemfile(以下を追記) gem 'rspec-rails' gem 'factory_bot_rails'terminal.$ bundle installrespecをインストール
terminal.$ rails g rspec:install.rspecへの追記
.rspec(以下を追記) --format documentationこれ、なんの意味があるのかと思ったら、書かないとターミナルにテスト結果がdocument形式で表示されません。
spec/rails_helper.rbへの追記
spec/rails_helper.rbRSpec.configure do |config| (以下を追記) config.include FactoryBot::Syntax::Methods #Factory_botのメソッドを使用するため endrspecファイルを作成する
terminal.$ bin/rails g rspec:model item単体テスト実装
それでは単体テストのコードを書いていきます。
とりあえずテスト用インスタンスをつくってみた。
まずは半端な知識でテスト用のインスタンスを作ります。
spec/factoreis/item.rbFactoryBot.define do factory :item do #name に "test" とだけ入れます。 name {"test"} end endとりあえずテストコードも書いてみた。
次に半端な知識でテストコードも書いていきます。
spec/models/item_spec.rbrequire 'rails_helper' RSpec.describe Item, type: :model do describe '#create' do let(:item) {build(:item)} context 'can save' do it "is valid with a name" do expect(item).to be_valid #name に "test" が入っていれば成功する(はず) end end context 'can not save' do it "is valid without a name" do item.name = "" #name が 空の場合 expect(item).to be_invalid #失敗する(はず) end end end endテストコード走らせてみた。
インスタンスも作った。テストコードも書いた。
次にやることと言ったら、もう決まってる。
いざ。terminal.$ bundle exec rspec spec/models/item_spec.rbterminal.Item #create can save is valid with a title can not save is valid without a title (FAILED - 1) Failures: 1) Item#create can not save is valid without a title Failure/Error: expect(item).to be_invalid expected `#<Item id: nil, title: "", created_at: nil, updated_at: nil>.invalid?` to return true, got false # ./spec/models/item_spec.rb:14:in `block (4 levels) in <top (required)>' Finished in 0.34277 seconds (files took 5.22 seconds to load) 2 examples, 1 failure Failed examples: rspec ./spec/models/item_spec.rb:12 # Item#create can not save is valid without a titleあれ? エラー?
あ、validation書いてないですねこれ。validationを追加してみた。
null: falseだけ追加します。app/models/item.rbclass Item < ApplicationRecord (中略) validates :name,presence: true #null: false end結果
terminal.$ bundle exec rspec spec/models/item_spec.rbterminal.Item #create can save is valid with a title can not save is valid without a title Finished in 0.33208 seconds (files took 6.29 seconds to load) 2 examples, 0 failures上手(?)にできました!
教訓
validationを忘れない!
今回は以上です。
参考にさせていただいた記事
- 投稿日:2020-04-30T20:03:37+09:00
超基礎 Rails DBの作成
データベースを作成
$ rails db:create以下のような表示がされれば成功
Created database 'ファイル名_development' Created database 'ファイル名_test'モデルの作成
$ rails g model モデル名マイグレーションファイルが生成されるので必要な型、カラムや制約を追加
マイグレーションファイルの実行
$ rails db:migrateマイグレーションファイルの状況を確認
$ rails db:migrate:status修正する際にはマイグレーションファイルを差し戻す
$ rails db:rollbackマイグレーションファイルに追記
$ rails g migration Addカラム名To 追加先テーブル名 追加するカラム名:型 # マイグレーションファイルの実行 $ rails db:migrate
- 投稿日:2020-04-30T20:03:35+09:00
[Rails]カラムのreference型について
reference型とは
外部キーになるカラムを生成する時にこの型にすることが多い。
使い方
20××××××××××××.rbclass CreateUsers < ActiveRecord::Migration[5.0] def change create_table :users do |t| t.string :name t.references :category, foreign_key: true end end endこの場合category_idカラムが生成されます。
reference型は、外部キー制約をつけるときに「foreign_key: true」を使うことで制約が適用される。
※ちなみに、インデックスを自動で張ってくれるため自分で設定する必要はありません。
- 投稿日:2020-04-30T18:52:22+09:00
Railsのform_withを使った時にページが更新されない時
form_withとは
Railsアプリケーションでformを作成する時にform_for/form_tagを使っていました。
任意のmodelに紐づくフォームを作成したい場合にはform_forを使い、modelに紐づかない場合にはform_withを使います。
form_forを使えばPOSTの送信先urlなどを全て自動で行いますが、form_forの場合は全て明示します。
HTMLタグのヘルパーのようなイメージで使います。
【Rails】form_for/form_tagの違い・使い分けをまとめた
しかし、
Rails5.1以降は2つのメソッドを統合したform_withが登場し、form_withの利用が推奨されています。form_withでページが更新されない
form_withを使ってユーザのログインフォームを作っていました。
form_withには
UserModelを紐づけており、バリデーションやログイン認証の結果にエラーがあれば、viewに反映せるようにしていました。views/users/_form.html.erb<%= form_with model: @user, url: user_path do |f| %> <%= render 'shared/error_messages', object: f.object %> <%= f.label :name %> <%= f.text_field :user_name, class: "form-control" %> <%= f.label :email %> <%= f.email_field :email, class: "form-control" %> <%= f.label :password %> <%= f.password_field :password, class: "form-control" %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation, class: "form-control" %> <%= f.submit yield(:btn_text), class: "btn btn-primary" %> <% end %>ところが、エラーは発生しているのにviewには反映されない問題に衝突しました。
これは、
form_withでのパラメータの送信はajaxで行われているためです。HTMLのフォームとしてPOSTしたい場合は
local: trueオプションを付け加えます。views/users/_form.html.erb<%= form_with model: @user, url: user_path, local: true do |f| %> : <% end %>これでバリデーションなどのエラー結果を表示するviewを表示できます。
都度フォームにオプションをつけるのが面倒な場合は、
config/initializeディレクトリに適当なファイルを作成し以下のコードを追記します。config/initialize/some_file.rbRails.application.configure do config.action_view.form_with_generates_remote_forms = false end
- 投稿日:2020-04-30T18:50:59+09:00
【Rails】住所を入力すると自動的に地図表示される方法(Google Maps API)
はじめに
ポートフォリオ制作で、Google Map APIを用いて住所フォームを送信した際に住所名と地図を自動的に地図表示される設定を行ったので、アウトプットも兼ねて手順を紹介していきます。
手順
1.Google MapのAPI Keyを取得
2.住所(address)、緯度(latitude)、経度(longitude)カラムを追加する
3.住所を登録するフォームを作成する
4.gem geocoderを追加する
5.viewにGoogle Mapを表示させる記述を追加する
6.詳しい住所を表示させる
7.GitHubにPushされないように設定する
8.APIキーの書き換え
(その他)AWSでデプロイしている場合1.Google MapのAPI Keyを取得
APIの取得はこちらの記事がわかりやすいので参考にしてみてください。
https://qiita.com/tiara/items/4a1c98418917a0e74cbb
2.住所、緯度、経度カラムを追加する
住所(address)、緯度(latitude)、経度(longitude)カラムを追加しましょう。
class ChangeDatatypeLanguageOfLabs < ActiveRecord::Migration[5.2] def change change_column :labs, :address, :string change_column :labs, :latitude, :float change_column :labs, :longitude, :float end endlabsはモデル名なので人によって変わります。
latitudeとlongitudeは
float型にします。floate型については下記の記事を参考にしてみてください。
https://wa3.i-3-i.info/word14968.htmlカラムを追加したら
$ rails:db:migrateしましょう。3.住所を登録するフォームを作成する
<%= form_for(@lab) do |f| %> ・・・ <%= f.label :住所 %> <%= f.text_area :address, autofocus: true %> ・・・ <%= f.submit '投稿' %> <% end %>これで住所を登録するフォームが投稿できます。
4.gem geocoderを追加する
地図表示する際に、Google Mapでは緯度・経度から位置を取得します。
なので、緯度・経度の登録を行う為に今回は
gem geocoderを導入します。
geocoderによって住所の情報を元に緯度、経度を割り出してくれます。Gemfile.gem 'geocoder'記述後、ターミナル上で
$ bundle installを実行します。lab.rbgeocoded_by :address(←住所のカラム名) after_validation :geocode, if: :address_changed?これで、モデル登録時と住所(address)変更時にgeocoderが動いて緯度・経度のデータが登録・更新されます
5.viewにGoogle Mapを表示させる記述を追加する
labs/show.html.rb・・・ <p>住所</p> <p><%= @lab.address %></p>(住所名表示) <div id="map"></div>(地図を表示) ・・・ <style>(地図の大きさ指定) #map{ height: 150px; width:270px; } </style> <script type="text/javascript"> function initMap() { var test ={lat: <%= @lab.latitude %>, lng: <%= @lab.longitude %>}; var map = new google.maps.Map(document.getElementById('map'), { zoom: 15, center: test }); var transitLayer = new google.maps.TransitLayer(); transitLayer.setMap(map); var contentString = '住所:<%= @lab.address %>'; var infowindow = new google.maps.InfoWindow({ content: contentString }); var marker = new google.maps.Marker({ position:test, map: map, title: contentString }); marker.addListener('click', function() { infowindow.open(map, marker); }); } </script> <script async defer src="https://maps.googleapis.com/maps/api/js?v=3.exp&key=取得したAPIキー&callback=initMap"> </script>これで登録した住所を元に地図表示ができるようになりました。
しかし、この状態では住所名によって地図が表示されない場合があります。それはデフォルトのgeocoderのままでは詳しい住所の経度、緯度を持ってくることができないからです。
なので、詳しい住所でも表示されるように設定していきます。
6.詳しい住所を表示させる
ターミナル上で
$ bin/rails g geocoder:configコマンドを入力。
そうすると、config/initializers/geocoder.rbファイルが作成されます。作成されたファイルを開き、中身を変更させましょう。
geocoder.rbGeocoder.configure( # Geocoding options # timeout: 3, # geocoding service timeout (secs) lookup: :google, # name of geocoding service (symbol) # ip_lookup: :ipinfo_io, # name of IP address geocoding service (symbol) # language: :en, # ISO-639 language code use_https: true, # use HTTPS for lookup requests? (if supported) # http_proxy: nil, # HTTP proxy server (user:pass@host:port) # https_proxy: nil, # HTTPS proxy server (user:pass@host:port) api_key: ENV['GOOGLE_MAP_API_KEY'], # API key for geocoding service # cache: nil, # cache object (must respond to #[], #[]=, and #del) # cache_prefix: 'geocoder:', # prefix (string) to use for all cache keys # Exceptions that should not be rescued by default # (if you want to implement custom error handling); # supports SocketError and Timeout::Error # always_raise: [], # Calculation options # units: :mi, # :km for kilometers or :mi for miles # distances: :linear # :spherical or :linear )これで、Google mapのAPIを使って緯度、経度を検索できるようになりました。
7.GitHubにPushされないように設定する
この状態でPushしてしまうと取得したAPIキーもGitHub上に上がってしまいます。
なので、Pushしても表示されないように設定しましょう。gemの
dotev-railsを用いて設定していきます。Gemfile.gem 'dotenv-rails'ターミナル上で
$ bundle installを実行します。app等と同じステージに.envファイルを作成しましょう。
.envファイルにAPIキーを記述する。env.GOOGLE_MAP_API_KEY=取得したAPIキー
.envファイルの下にある
.gitignoreファイルの最後の行に.envと記述しましょう。
(ちなみにignoreとは無視するという意味です。)gitignore.・・・ ・・・ /.envこれでPushしても.envファイルは無視されます。
8.APIキーの書き換え
今までAPIキーを直接書き込んでいた全てのファイルでAPIキーの記述を.envファイル内で定義したGOOGLE_MAP_API_KEYに書き換えます。
labs/show.html.rb<script async defer src="https://maps.googleapis.com/maps/api/js?v=3.exp&key=<%= ENV['GOOGLE_MAP_API_KEY'] %>&callback=initMap"> </script>geocoder.rbapi_key: ENV['GOOGLE_MAP_API_KEY'],これでGitHub上にAPIキーが上がることなく地図が表示されるようになります。
(その他)AWSでデプロイしている場合
AWSでデプロイしている場合、本番環境に反映させる為には
EC2にログイン後、Git pullをして変更内容を取り込みます。その後、
$ sudo vi .envコマンドで.envファイルを開き、GOOGLE_MAP_API_KEY=取得したAPIキーを記述するとデプロイ先でも反映されるようになります。
- 投稿日:2020-04-30T18:50:59+09:00
【Rails】住所を入力すると自動で地図表示される方法(Google Maps API)
はじめに
ポートフォリオ制作で、Google Maps APIを用いて住所フォームを送信した際に住所名と地図を自動で地図表示される設定を行ったので、アウトプットも兼ねて手順を紹介していきます。
手順
1.Google MapのAPI Keyを取得
2.住所(address)、緯度(latitude)、経度(longitude)カラムを追加する
3.住所を登録するフォームを作成する
4.gem geocoderを追加する
5.viewにGoogle Mapを表示させる記述を追加する
6.詳しい住所を表示させる
7.GitHubにPushされないように設定する
8.APIキーの書き換え
(その他)AWSでデプロイしている場合1.Google MapのAPI Keyを取得
APIの取得はこちらの記事がわかりやすいので参考にしてみてください。
https://qiita.com/tiara/items/4a1c98418917a0e74cbb
2.住所、緯度、経度カラムを追加する
住所(address)、緯度(latitude)、経度(longitude)カラムを追加しましょう。
class ChangeDatatypeLanguageOfLabs < ActiveRecord::Migration[5.2] def change change_column :labs, :address, :string change_column :labs, :latitude, :float change_column :labs, :longitude, :float end endlabsはモデル名なので人によって変わります。
latitudeとlongitudeは
float型にします。float型については下記の記事を参考にしてみてください。
https://wa3.i-3-i.info/word14968.htmlカラムを追加したら
$ rails:db:migrateを実行します。3.住所を登録するフォームを作成する
<%= form_for(@lab) do |f| %> ・・・ <%= f.label :住所 %> <%= f.text_area :address, autofocus: true %> ・・・ <%= f.submit '投稿' %> <% end %>これで住所を登録するフォームが投稿できます。
4.gem geocoderを追加する
地図表示する際に、Google Mapでは緯度・経度から位置を取得します。
なので、緯度・経度の登録を行う為に今回は
gem geocoderを導入します。
geocoderによって住所の情報を元に緯度、経度を割り出してくれます。Gemfile.gem 'geocoder'記述後、ターミナル上で
$ bundle installを実行します。lab.rbgeocoded_by :address(←住所のカラム名) after_validation :geocode, if: :address_changed?これで、モデル登録時と住所(address)変更時にgeocoderが動いて緯度・経度のデータが登録・更新されます
5.viewにGoogle Mapを表示させる記述を追加する
labs/show.html.rb・・・ <p>住所</p> <p><%= @lab.address %></p>(住所名表示) <div id="map"></div>(地図を表示) ・・・ <style>(地図の大きさ指定) #map{ height: 150px; width:270px; } </style> <script type="text/javascript"> function initMap() { var test ={lat: <%= @lab.latitude %>, lng: <%= @lab.longitude %>}; var map = new google.maps.Map(document.getElementById('map'), { zoom: 15, center: test }); var transitLayer = new google.maps.TransitLayer(); transitLayer.setMap(map); var contentString = '住所:<%= @lab.address %>'; var infowindow = new google.maps.InfoWindow({ content: contentString }); var marker = new google.maps.Marker({ position:test, map: map, title: contentString }); marker.addListener('click', function() { infowindow.open(map, marker); }); } </script> <script async defer src="https://maps.googleapis.com/maps/api/js?v=3.exp&key=取得したAPIキー&callback=initMap"> </script>これで登録した住所を元に地図表示ができるようになりました。
しかし、この状態では住所名によって地図が表示されない場合があります。それはデフォルトのgeocoderのままでは詳しい住所の経度、緯度を持ってくることができないからです。
なので、詳しい住所でも表示されるように設定していきます。
6.詳しい住所を表示させる
ターミナル上で
$ bin/rails g geocoder:configコマンドを入力。
そうすると、config/initializers/geocoder.rbファイルが作成されます。作成されたファイルを開き、中身を変更させましょう。
geocoder.rbGeocoder.configure( # Geocoding options # timeout: 3, # geocoding service timeout (secs) lookup: :google, # name of geocoding service (symbol) # ip_lookup: :ipinfo_io, # name of IP address geocoding service (symbol) # language: :en, # ISO-639 language code use_https: true, # use HTTPS for lookup requests? (if supported) # http_proxy: nil, # HTTP proxy server (user:pass@host:port) # https_proxy: nil, # HTTPS proxy server (user:pass@host:port) api_key: ENV['GOOGLE_MAP_API_KEY'], # API key for geocoding service # cache: nil, # cache object (must respond to #[], #[]=, and #del) # cache_prefix: 'geocoder:', # prefix (string) to use for all cache keys # Exceptions that should not be rescued by default # (if you want to implement custom error handling); # supports SocketError and Timeout::Error # always_raise: [], # Calculation options # units: :mi, # :km for kilometers or :mi for miles # distances: :linear # :spherical or :linear )これで、Google mapのAPIを使って緯度、経度を検索できるようになりました。
7.GitHubにPushされないように設定する
この状態でPushしてしまうと取得したAPIキーもGitHub上に上がってしまいます。
なので、Pushしても表示されないように設定しましょう。gemの
dotev-railsを用いて設定していきます。Gemfile.gem 'dotenv-rails'ターミナル上で
$ bundle installを実行します。app等と同じステージに.envファイルを作成しましょう。
.envファイルにAPIキーを記述する。env.GOOGLE_MAP_API_KEY=取得したAPIキー
.envファイルの下にある
.gitignoreファイルの最後の行に.envと記述しましょう。
(ちなみにignoreとは無視するという意味です。)gitignore.・・・ ・・・ /.envこれでPushしても.envファイルは無視されます。
8.APIキーの書き換え
今までAPIキーを直接書き込んでいた全てのファイルでAPIキーの記述を.envファイル内で定義したGOOGLE_MAP_API_KEYに書き換えます。
labs/show.html.rb<script async defer src="https://maps.googleapis.com/maps/api/js?v=3.exp&key=<%= ENV['GOOGLE_MAP_API_KEY'] %>&callback=initMap"> </script>geocoder.rbapi_key: ENV['GOOGLE_MAP_API_KEY'],これでGitHub上にAPIキーが上がることなく地図が表示されるようになります。
(その他)AWSでデプロイしている場合
AWSでデプロイしている場合、本番環境に反映させる為には
EC2にログイン後、Git pullをして変更内容を取り込みます。その後、
$ sudo vi .envコマンドで.envファイルを開き、GOOGLE_MAP_API_KEY=取得したAPIキーを記述するとデプロイ先でも反映されるようになります。
- 投稿日:2020-04-30T18:19:21+09:00
seeds.rbの使い方
seeds.rbとは
初期データを生成してくれるファイルのこと。
このファイルにデータを生成するコードを書いておくだけで、アプリにデータを備えさせることができます。
簡単にテストデータを作ったりできます。使い方
1.自分が用意したいデータをファイル内でcreateする。
db/seed.rb#通常の場合 User.create(name: "tanaka") User.create(name: "sato") #配列の場合 users = User.create([{name: "tanaka"}, {name: "sato"}]) #大量のテストデータの場合 100.times do |n| User.create(title: "test{n}人目", content:"test!#{n}回目") end2.seedファイルを実行する
$ rails db:seedおまけ
実際に存在しそうなデータを生成してくるgem(Faker)があるので一応載せておきます。
1.Gemfileに以下を追記
gem 'faker'こちらも忘れず実行してください。
$ bundle install2.seeds.rbを以下のように記述する。
db/seed.rb100.times do |n| name = Faker::Name.name email = Faker::Internet.email content = "test" User.create( name: name, email: email, content: content ) end3.seedファイルを実行する。
$ rails db:seed※Fakerの使い方一覧は以下の表参照。
種類 役割 Faker::Name.name 名前 Faker::Internet.email メールアドレス Faker::Address.city 都市の名前 Faker::Food.ingredient 食べ物の名前 参考
- 投稿日:2020-04-30T18:18:53+09:00
商品情報と別のテーブルに保存している画像を一緒に表示させるためには
現在プログランミングスクールでチーム開発にてフリマアプリを作成中です。
やりたいこと
- トップページの商品一覧でitemテーブルのアソシエーション先であるimageテーブルから複数ある画像の一つだけを表示させたい。
- 表示させたいのは出品中の商品のみ。
解決までの思考
とりあえず一覧表示するため商品全部の情報を持ってきてみる
items_controller.rbdef index @items = Item.all endでもこれだと画像がない
items_controller.rbdef index @items = Item.includes([:images]).order(created_at: :desc) endモデルにアソシエーションがあれば.includesで取得可能!
item.rbclass Item < ApplicationRecord belongs_to :brand belongs_to :category has_many :images念のためアソシエーション確認
これで商品情報と画像を持ってこれた。でもそも欲しい情報は出品中の商品のみなので、このままだと販売済みなどの必要ない商品まであるよね?
じゃあモデルで定義しちゃおう!
item.rbclass Item < ApplicationRecord belongs_to :brand belongs_to :category has_many :images enum status: { sell: 0, buy: 1 , trading:2} scope :on_sell, -> { where(status: 0) } endまずenumで出品中、購入済み、取引中を定義しておく。
これによってstatusカラムに数字で保存されている。さらにscopeメソッドを使ってメソッドを定義する。
where句を使ってstatusが0(出品中)のレコードだけをon_sellに代入できた。
(コントローラーにも記述できるがこの方が可読性がいいのでモデル推奨)items_controller.rbdef index @items = Item.on_sell.includes([:images]).order(created_at: :desc) endあとはコントローラーに記述してあげれば
出品中の商品とそれに紐づいた画像を持ってこれた。ついでに.orderで最新順に表示できるようソートしておく。あとはビューに表示させるだけ!
.top-main__product__list__box - @items.each do |item| = link_to item_path(id: item.id) ,class:"top-main__product__list__box__item" do - item.images.first(1).each do |image| = image_tag image.url,class:"top-main__product__list__box__item__img" .top-main__product__list__box__item__body %h3.top-main__product__list__box__item__body__name = item.name .top-main__product__list__box__item__body__details %ul %li = item.price = "円" %p (税込)itemをeachで順番に表示させたはいいもののそのままだと紐づいた画像を全て表示してしまう。
- item.images.first(1).each do |image|eachは回数を指定できる、、、
じゃあ一回だけ回せば一枚だけ表示できるやん!とひらめき実装完了
(ただこの方法はあまり美しくない気が、、、)今回学べたこと
- 関連するテーブルからの取得方法
- アソシエーションの必要性
- スコープを使ってモデルに定義しコントローラーに記述することで可読性アップ
初めはどこに何を定義し、どう記述するのか見当もつきませんでしたが必要なポイントを箇条書きにすることで少しずつ近づけました。
ビューの画像表示の方法はもう少しいい表示方法がありそう?なので今後の課題として!
- 投稿日:2020-04-30T18:03:06+09:00
railsアプリで別のウィンドウでログアウトした時エラーにならないかRSpecのsystem specでテスト
railsでログイン機能を作った際、ログアウトしてる状態で別タブでログアウトした時にエラーにならないかsystem specでテスト
session_spec.rblet(:user) { FactoryBot.build(:user) } # 省略 it "別タブでログアウトをクリックした時、エラーにならない" do user.save test_log_in # 新しいタブを開く within_window open_new_window do test_log_in click_link "ログアウト" end # タブを最初のものに戻す switch_to_window windows[0] click_link "ログアウト" expect(current_path).to eq root_path endlogin_support.rb# spec/support/login_support.rb def test_log_in visit login_path fill_in "User_id", with: user.acount_id fill_in "Password", with: user.password click_button "Login" end
- 投稿日:2020-04-30T17:39:48+09:00
rails routesで覚えのないroutingが出力される。
問題のルーティング
こんなの設定してない、、、
$ rails routesrails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create rails_conductor_inbound_emails GET /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#index POST /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#create new_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/new(.:format) rails/conductor/action_mailbox/inbound_emails#new edit_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id/edit(.:format) rails/conductor/action_mailbox/inbound_emails#edit rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#show PATCH /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update PUT /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update DELETE /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#destroy rails_conductor_inbound_email_reroute POST /rails/conductor/action_mailbox/:inbound_email_id/reroute(.:format) rails/conductor/action_mailbox/reroutes#create rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create解決方法
$ rails new プロジェクトの名前 --skip-active-storage --skip-action-mailer --skip-action-mailboxrails newでプロジェクトを立ち上げる際にオプションを付け加える事で解決。
既にrails newした後はapplication.rbファイルにコードを記述する事で表示されなくなりました。Application.rb class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 6.0 # CODE YOU SHOULD ADD vvvvvv # ここから initializer(:remove_action_mailbox_and_activestorage_routes, after: :add_routing_paths) { |app| app.routes_reloader.paths.delete_if {|path| path =~ /activestorage/} app.routes_reloader.paths.delete_if {|path| path =~ /actionmailbox/ } } ←# ここまで追加 # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. end end
- 投稿日:2020-04-30T17:26:32+09:00
Rubyとは
Ruby
特徴
・記述量が少ない
・JavaやPHPといった他の言語同様、オブジェクト指向プログラミング言語である。
・スクリプト言語であるため、コンパイルする必要がない
・日本で生まれたプログラミング言語である。記述量が少ない
他の言語であれば6行〜10行必要な場合でも、Rubyは1行で済む場合がある。
記述量が少ないということは作業の短縮になり、開発者にとって非常に助かると言う利点がある。オブジェクト指向とは
プログラムの動作を属性値とメソッドを持ったパーツの組み合わせで実現すると言う考え方である。
スクリプト言語とは
プログラミング言語のうち、プログラムの記述や実行を比較的簡易に行うことができる言語の総称。インタプリンタ型(ソースコードを即座に実行開始できる)型のため、コンパイラ(一括してから実行する方式)に比べ、開発や修正をテンポよく進めることができる。
デメリットして
処理速度が他の言語に比べて遅いため、大規模アプリや処理速度が重要なサービスには向いていない。
- 投稿日:2020-04-30T17:11:11+09:00
Rails 初めてのAPIモード
概要
こんにちは。
今回は始めてRailsでAPIを作成してみたのでその備忘録を残したいと思います。以下を使いました。
ツール
- Postman(レスポンスを確認するためのツール)
gem
- active_model_serializers
今回はUserを管理できるAPIを作ります。
事前にこちらの記事を読んで作成しております。
https://qiita.com/Kaki_Shoichi/items/d4adcf0298ed0b4614a2
https://qiita.com/c5meru/items/1c921676de8a5a038f70
https://qiita.com/yyh-gl/items/30bd91c2b33fdfbe49b5仕様
jobテーブルとuserテーブルは1対多の関係にある。
jobとuserを登録できる。
- userはjob_idを外部キーに持つ
- job_nameとusernameというリクエストを送る
- すでにjob_nameが存在しているときはそのIDを外部キーに、job_nameがない場合は新しくjobを作成しそのidを外部キーとする。
user一覧を取得できる。
- リクエストにvalueを含めない場合は全てのuserを表示させる。
- リクエストにjob_nameを指定した場合は該当するuserのみを表示させる。
以上の仕様で作成したいと思います。
それでは早速始めていきます。
導入
まずはapiモードでRailsを作成してください。
$ rails new testapi --api以下のgemをインストールします。
gem 'active_model_serializers'テーブル作成
以下のようにテーブルとカラムを作成します。
db/schema.rbcreate_table "jobs", force: :cascade do |t| t.string "name", null: false t.index ["name"], name: "index_jobs_on_name", unique: true end create_table "users", force: :cascade do |t| t.text "username", null: false t.integer "job_id", null: false t.index ["job_id"], name: "index_users_on_job_id" endモデル
モデルのバリデーションは次のようにしました。
job.rbclass Job < ApplicationRecord has_many :users, dependent: :destroy validates :name, uniqueness: true, presence: true enduser.rbclass User < ApplicationRecord belongs_to :job validates :username, presence: true validates :job_id, presence: true endルーティング
api作成時はバージョン管理しやすい設計が推奨されているようです。
また今回はusers_contorollerのみを使用して機能実装を行います。config/routes.rbRails.application.routes.draw do namespace 'api' do namespace 'v1' do resources :users, only: [:create, :index] end end endコントローラ
users_controllerはこのように作成致しました。
users_controllermodule Api module V1 class UsersController < ApplicationController before_action :set_job def create @job = Job.create(name: user_params[:job_name]) if @job.blank? user = User.new(username: user_params[:username], job_id: @job.id) if user.save render status: :created, json: { status: 201 } else render status: :unprocessable_entity, json: { status: 422 } end end def index if user_params[:job_name].nil? users = User.all render json: users elsif @job.nil? render status: :not_found, json: { status: 404 } else users = @job.users render json: users end end private def user_params params.permit(:username, :job_name) end def set_job @job = Job.find_by(name: user_params[:job_name]) end end end endレスポンスを整形
次にjsonで返すレスポンスを整形します。
導入でインストールしたactive_model_serializersを使用します。※ 色々調べたのですが、現在は fast_json_apiというgemの方が推奨されているようです。使い方はほとんど変わらないようですが、レスポンスがシンプルだったので今回はamsを使用しました。
こちらの記事を参考にさせて頂きました。
https://qiita.com/m_nakamura145/items/75fd7c0934daf9bcc21d使い方は以下の通りです。
まずはコマンドで必要なファイルを作成します。$ rails generate serializer Userapp/serializers/model_serializer.rbファイルが作成されます。
作成されたファイルを以下のように記述します。serializers/user_serializer.rbclass UserSerializer < ActiveModel::Serializer attributes :id, :job, :username belongs_to :job def job object.job.name end endこれでjsonレスポンスに独自のパラメータを追加して返すことができます。
リクエスト
ではPostmanを使用してリクエストし、レスポンスをみてみます。
Postmanまずはルーティングを確認します。
$ rake routes api_v1_ideas GET /api/v1/users(.:format) api/v1/users#index POST /api/v1/users(.:format) api/v1/users#createそれではPostmanで上記URLにリクエストを送ってみます。(rails s してください。)
画像左上をpostに変更してください。すると以下のようなレスポンスが得られました。
{ "status": 201 }これでレコードを登録することができました。
次は作成したレコードを取得してみます。
画像左上をgetに変更してください。[ { "id": 1, "job": "testjob1", "username": "testuser" } ]先ほど登録したレスポンスを得られました。
ここでkey,valueを設定しない場合は登録している全てのレコードを取得することができます。
以上です。
APIの記事がそもそも少なかった事と、1対多関係にあるテーブルに独自のパラメータをリクエストする方法がなかなか見つからなかったのでかなり時間がかかりました。
お付き合い頂きありがとうございました。
- 投稿日:2020-04-30T16:30:27+09:00
【Rails】Kaminariで同一ページにもっと見るを複数実装する
通常の場合
home_controller.rbdef index @cats = Cat.page(params[:page]).per(1) endapp/views/home/index.html.erb<%= paginate @cats %>複数の場合
home_controller.rbdef index @cats = Cat.page(params[:cats_page]).per(1) @dogs = Dog.page(params[:dogs_page]).per(1) endapp/views/home/index.html.erb<%= paginate @cats, param_name: 'cats_page' %> <%= paginate @dogs, param_name: 'dogs_page' %>ajaxを利用したもっと見るの場合
home_controller.rbdef index @cats = Cat.page(params[:page]).per(1) @dogs = Dog.page(params[:page]).per(1) return unless request.xhr? case params[:type] when 'dog', 'cat' render "#{params[:type]}" end endapp/views/home/index.html.erb<%= link_to_next_page @cats, 'もっと見る', remote: true, params: { type: :cat }, id: 'more-cat' %> <%= link_to_next_page @dogs, 'もっと見る', remote: true, params: { type: :dog }, id: 'more-dog' %>app/views/home/cat.js.erb$('.cat-wrap').append('<%= escape_javascript(render 'cat', object: @cats) %>'); $('#more-cat').replaceWith('<%= escape_javascript(link_to_next_page(@cats, 'もっと見る', params: { type: :cat }, remote: true, id: 'more-cat')) %>');app/views/home/dog.js.erb$('.dog-wrap').append('<%= escape_javascript(render 'dog', object: @dogs) %>'); $('#more-dog').replaceWith('<%= escape_javascript(link_to_next_page(@dogs, 'もっと見る', params: { type: :dog }, remote: true, id: 'more-dog')) %>');参考
https://qiita.com/Coolucky/items/bde74b020b8d37ccf426
https://www.rubydoc.info/github/amatsuda/kaminari/Kaminari/ActionViewExtension
- 投稿日:2020-04-30T15:34:43+09:00
Address already in use - bind(2) for "0.0.0.0" port 3000 (Errno::EADDRINUSE) が出たとき
- 投稿日:2020-04-30T14:44:15+09:00
[Rails]FullCalenderで投稿一覧も表示させつつ、マイページでは自分の投稿だけに絞ってカレンダーを表示する
目的
FullCalenderを使って、Twitter+マイページでは自分の投稿をカレンダーで見る
ということを実装する前提
フルカレンダーを実装し、カレンダーが表示できている
下記のサイトを参考に作りました。
https://qiita.com/sasasoni/items/fb0bc1644ece888ae1d4
https://qiita.com/imp555sti/items/ee9809768f6dc9439ab5やること
FullCalenderをまずは準備しておきます。
そして自分が一番詰まったのは、indexではフォローしている人全員を表示する。
しかし自分のマイページのカレンダーでは、自分の投稿のみに限定する。
ということです。どうやらFullCalenderの使い方としてindexアクションで定めた@eventsをカレンダーで表示するようなので
indexでは投稿一覧を@eventsではなく、別の名前を与えて。
ユーザーの投稿一覧を@eventsとしてあげます。index.html.erbdef index @all_events = Event.all.includes(:user) @user = User.find(current_user.id) #フォローしているユーザーを取得 @follow_users = @user.followings.map { |f| f[:id] } @follow_users << current_user.id #フォローユーザーの投稿のみ表示 @events_onlyfollow = @all_events.where(user_id: @follow_users).order("created_at DESC") # 自分の投稿のみ @events = Event.where(user_id: current_user.id) endまだまだ理解が浅くちゃんとできている訳ではないと思いますが。。。
とりあえずカレンダーが自分の投稿だけで絞れたのでひとまずOK
- 投稿日:2020-04-30T14:15:22+09:00
Rails テストについて 2
はじめに
テストに拒否反応があるので、まずは整理したいと思います。
少しづつ記事を書いていきます。
前回記事 → Rails テストについて 1もうすでにご存知の方、省略の仕方等ご存知でしたら、ご助言願います。
必要なGemのインストール!
Gemfileに追記 gem 'rspec-rails'その後、bundle installです。
web_console(gemfile内)の記述!
- web_console というgemはtest環境で動かすと不具合が起きる可能性があるようです。
- ということで、development環境でのみ動くようにしてください。
- group :development do ~ endの記述が無ければ下記のように作成!
- 既にある場合、その記述の間にweb_consoleを移動!
Gemfile group :development do gem 'web-console' endその後、bundle installです。
RSpecの設定
- RSpec用設定ファイルの作成
ターミナル %rails g rspec:install↓
こんな感じで4つ作成されます!
ターミナル %rails g rspec:install Running via Spring preloader in process 3820 create .rspec ① create spec ② create spec/spec_helper.rb ③ create spec/rails_helper.rb ④ファイル説明
rails_helper.rb
- RailsにおいてRSpecを利用する際に、共通の設定を書いておくファイル
- 各テスト用ファイルでこちらのファイルを読み込むことで、共通の設定や、メソッドを適用できる。
spec_helper.rb
- rails_helper.rbと同じくRSpec用の共通の設定を書いておくファイル
- しかし、こちらはRSpecをRails無しで利用する際に利用する。
.rspecファイルに追記
表示の出力を綺麗にしてくれる一文です!
その分、出力数が多いです。.rspecファイル内に追記 --format documentation正常にRSpecが起動するか確認
ターミナル % bundle exec rspecNo examples found. Finished in 0.00077 seconds (files took 0.30404 seconds to load) 0 examples, 0 failuresと出力されれば、おkです!
テスト編、続きます・・・(さて準備が完了っすよ・・・)
さいごに
日々勉強中ですので、随時更新します。
皆様の復習にご活用頂けますと幸いです。
- 投稿日:2020-04-30T13:48:10+09:00
Unicorn の自動起動と etc/init.dの使い方
railsをawsに置く作業をしていた時にUnicornの自動起動も試しておきたいと思いやったこと、学習したことを書きます。
Unicornの自動起動をする際に、etc/init.dにスクリプトを置くとのことで置いてみた。
これって、プログラミング言語で言うと何に当たるんだろう??と気になりつつも進めます。まず、etc/init.d/にUnicornのfileを作成します。
作成した後には、chkconfig コマンドで自動起動をさせなきゃならない。そもそも、initはlinuxが起動した時に呼ばれ実行する。その際、run levelが0~6まであり、2~5あたりのrun levelをchkconfig コマンドで変更する。ex)chkconfig on unicorn
変更すると、etc/rc0~6.dのfileにrun levelに応じたfileのシンボリックリンクが作成され、
実際に起動、読み込みするのは、etc/rc0.dだが、参照先としてetc/init.d/unicornが参照される。そして、linixを起動すれば、etc/rcが動きunicornの中身も一緒に読み込まれて起動すると言う仕組みらしい。
以下は、etc/rc3.dをlsで見た際、S85unicornと言うfileができていることが確認できるかと。(シンボリックリンク付き)[ec2-user@ip-00000 rc3.d]$ ls -la 合計 0 drwxr-xr-x 2 root root 63 4月 26 14:47 . lrwxrwxrwx 1 root root 20 4月 7 01:51 K50netconsole -> ../init.d/netconsole lrwxrwxrwx 1 root root 17 4月 7 01:51 S10network -> ../init.d/network lrwxrwxrwx 1 root root 17 4月 26 14:47 S85unicorn -> ../init.d/unicornUnicornの一部
start() { if [ -e $PID ]; then //もしPIDがあれば echo "$NAME already started+${PID}" exit 1 fi echo "start $NAME"//もしPIDがなければ su - ${USER} -c "cd ${ROOT_DIR} && ${CMD}" }これは、調べるとすんなり出てくる。
#!/bin/sh #chkconfig:0000 00 00 #description:unicorn shell USER="ec2-user" NAME="Unicorn" ENV=production ROOT_DIR="/var/www/application" PID="${ROOT_DIR}/tmp/pids/unicorn.pid" CONF="${ROOT_DIR}/config/unicorn.rb" OPTIONS="" CMD="RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D" start() { if [ -e $PID ]; then echo "$NAME already started+${PID}" exit 1 fi echo "start $NAME" su - ${USER} -c "cd ${ROOT_DIR} && ${CMD}" } stop() { if [ ! -e $PID ]; then echo "$NAME not started" exit 1 fi echo "stop $NAME" rm ${PID} kill -QUIT `cat ${PID}` } force_stop() { if [ ! -e $PID ]; then echo "$NAME not started" exit 1 fi echo "stop ${NAME}" echo ${PID} kill -INT `cat ${PID}` } reload() { if [ ! -e $PID ]; then echo "$NAME not started" start exit 0 fi echo "reload $NAME" ##kill -HUP `cat ${PID}` su - $USER -c "cd ${ROOT_DIR} && bundle exec unicorn_rails:reload" ## su $USER -lc "cd ${RAILS_ROOT}&& bundle exec rake unicorn_rails:reload" } restart() { force_stop sleep 5 start } case "$1" in start) start ;; stop) ;; force-stop) force_stop ;; reload) reload ;; restart) restart ;; *) echo "Syntax Error: release [start|stop|force-stop|reload|restart]" ;; esac自動起動の際につまづいたことは、etc/environmentに環境変数入れていて手動では動いていたけども、
自動起動する際には動かなかったこと。
それは、rails自体の環境変数がないためでcredentials.ymlなどに環境変数をきちんと設定してあげるといいと思います。
自分は、これで三日潰しました。また、init自体はroot 権限で動かすみたいなので注意が必要かもしれません。
- 投稿日:2020-04-30T13:17:11+09:00
【Rails】form_forの基本の基
フォーム作成のメソッド
form_tag:(旧)モデルに関連しないフォームの作成に使うform_for:(旧)モデルに基づくフォームの作成に使うform_with:(新)モデルに関わらず、フォームの作成に使う。※ Rails5.1以前では、データ登録や更新ではform_for、検索ではform_tagで実装する、というような使い分けを行う。
※ 但し、form_tag、form_forは Rails5.1以降は、非推奨。今後はform_withを使ってね!という事。form_tag
指定するのは、URL(パス)とHTTPメソッド(put、post、patch)の2つ。
httpのデフォルトはgetになっている。基本の構造<%= form_tag(URL, HTTPメソッド) do %> : <% end %>例<%= form_tag('/items', method: :post, class:"class_name", id:"id_name") do %> <% end %> <%= form_tag(items_path, method: :post) do %> <% end %> <!-- コントローラーとアクションで指定する場合 --> <%= form_tag({:controller => 'items', :action => 'create'}, {:method => :post}) do %> <% end %> <!-- シンボル型 --> <%= form_tag({controller: :items, action: :create}, {method: :post}) do %> <% end %> <!-- 画像などのファイル登録の場合 --> <%= form_tag('/items', method: :post, multipart: true) do %> <% end %> <!-- Ajax通信の場合 --> <%= form_tag('/items', method: :post, remote: true) do %> <% end %>フォームヘルパー<%= label_tag :表示したい文字 %> <!-- ラベル表示 --> <%= text_field_tag :name %> <!-- 1行テキスト params[:name]に値が入る --> <%= text_area_tag :content %> <!-- 複数行テキスト params[:content]に値が入る --> <%= submit_tag "送信" %> <!-- 送信ボタン -->form_for
既に保存されている場合は、updateアクション、未保存の時は、createアクションを、自動的に選んでくれる。特別なパスやアクションを呼び出したい時は、url、methodを指定する。
form_forにclassやid名をつけたい時はhtmlオプションを使用する。基本の構造<%= form_for モデル名 do |f| %> : <% end %> <%= form_for モデル名, url: 自分で定義したパス, method: HTTPメソッド, html: {class:'class_name', id:'id_name'} do |f| %> : <% end %>例<% form_for @items do |f| %> <% end %> <% form_for([:name, @items]) do |f| %> <% end %>フォームヘルパー<!-- ラベル --> <%= f.label :name %> <!-- 一行のテキスト入力 --> <%= f.text_field オブジェクト名, プロパティ名 [, オプション] %> <%= f.text_field :name, class: "class_name", maxlength: 40 %> <%= f.text_field :name, id: :text_name %> <!-- 複数行のテキスト入力 --> <%= f.text_area オブジェクト名, プロパティ名 [, オプション] %> <%= f.text_area :content, class: "class_name", size: "100x50" %> <!-- サイズ指定はcols×rows --> <!-- メールアドレス入力 --> <%= f.email_field オブジェクト名, プロパティ名 [, オプション] %> <!-- 数字入力 --> <%= f.number_field オブジェクト名, プロパティ名 [, オプション] %> <%= f.number_field :item_id, min: 1, max: 150 %> <!-- パスワード入力 --> <%= f.password_field オブジェクト名, プロパティ名 [, オプション] %> <!--日時の入力 --> <%= f.datetime_field オブジェクト名, プロパティ名 [, オプション] %> <!-- selectボックス(DBからデータ生成しない:select / する場合:collection_select) --> <%= f.select オブジェクト名, プロパティ名, タグの情報 [, オプション] %> <%= f.select :category, Category.all, include_blank: true %> <%= f.collection_select :category, Category.all, :id, :name, include_blank: true %> <!--日付選択selectボックス フォーマットは年月日。例)日が不要であれば{:discard_day => true}) --> <%= f.date_select :date, {:discard_day => true}, {start_year: 1950, end_year: 2050}, default: {year: 1950, month: 1} %> <!-- ファイル添付 --> <%= f.file_field オブジェクト名, プロパティ名 [, オプション] %> <!-- チェックボックス(DBからデータ生成しない:check_box / する場合:collection_check_boxes) --> <%= f.check_box オブジェクト名, プロパティ名 [, オプション, checked_value = "1", unchecked_value = "0"] %> <%= f.collection_check_boxes(:name, :ids, Item.all, :id, :name) do |b| %> <%= b.label {b.check_box + b.text} %> <% end %> <!-- ラジオボタン --> <%= f.radio_button "カラム名", "保存したい内容" %> <%= f.collection_radio_buttons(:items, :ids, Item.all, :id, :name) do |b| %> <%= b.label {b.radio_button + b.text} %> <% end %> <!-- 非表示:入力しない情報をパラメーターに送る時に使用 --> <%= f.hidden_field :カラム名, value: "値" %> <%= f.hidden_field :user_id, value:current_user.id %> <%= f.hidden_field 'モデル名[user_ids][]', value: current_user.id) %> <!--送信ボタン --> <%= f.submit "送信ボタン" %>form_with
モデルへの送信は、form_for と同様に、URL、スコープが自動推測される。Rails 5.2以降では、id属性も自動付与される。
フォーマットがAjax送信なので、HTML送信には、local: trueをつける必要がある。
フォームヘルパーはform_forと同じ書き方。基本の構造<!-- DBに保存しない時 --> <%= form_with url: パス do |f| %> : <% end %> <!-- DBに保存する時 --> <%= form_with model: モデルのインスタンス do |f| %> : <% end %>例<% form_with model: @item, local: true, class: "class_name", id: "id_name" do |f| %> <% end > <%= form_with @item, url: {controller: 'items', action: 'index'} do |f| %> <% end %>
- 投稿日:2020-04-30T13:13:06+09:00
【Rails】gemのアンインストール・バージョン変更
Gemのアンインストール方法
バージョンを指定することも可。
$ bundle exec gem uninstall gem名 -v 'バージョン名'Gemfile.lockを確認すると、消えているハズ。
後は、Gemfileから直接削除すればok。Gemのバージョン変更
バージョンダウンの場合
アンインストール後に、バージョンを指定してインストールする。
バージョンアップの場合
※ gem名を指定しなければ、Gemfileに記載の全てに対して、最新バージョンにアップデートされる。
$ gem update gem名インストール済みのGemの確認
$ gem listインストール済みのGemのバージョン確認
$ gem名 -v
- 投稿日:2020-04-30T12:50:35+09:00
erbファイルをまとめてhamlに変換する方法
Hamlとは
Hamlとは、HTMLよりも簡単に書くためのビューテンプレートエンジンです。
Hamlを使用することで、「綺麗に」、「読みやすく」、「生産的に」ビューを作成することができます。Hamlへの変換
1.Gemの導入
Gemfileの一番下に'haml-rails'を書く
Gemfilegem 'haml-rails'ターミナルでbundle installする。
terminalbundle install2.一括変換
ターミナルで以下のコマンドを入力し、実行
terminalrails haml:erb2hamlコマンドを実行すると途中で
terminalWould you like to delete the original .erb files? (This is not recommended unless you are under version control.) (y/n)と聞かれる。
オリジナルのerbファイルを削除するか聞かれているので、特に不要なら
'y'と入力し、実行無事にerbファイルがhamlファイルに変換される!!
補足
「=>」(ハッシュロケット)で変換されたものは「:」(シンボル型)に修正すること
参考
- 投稿日:2020-04-30T12:01:08+09:00
Rails + jQueryでAjaxの動作テストをしてみる
はじめに
Rails + jQueryでAjaxの動作テストをしてみました。
フォームのテキスト項目に入力したユーザー名をキーに、usersテーブルを検索して、検索結果をフォームに表示する動作を、Ajaxで実現してみました。
尚、当記事は、こちらのサイトを参考にさせて頂いております。参考URL
https://qiita.com/yuki-n/items/fdc5f7d5ac2f128221d1環境
- Vagrant + Ubuntu 16.04.5 LTS
- Rails 5.2.4.2
- jQuery
やった事
scaffoldで雛形を作成します。
jQueryが動くように動作環境を整備します(手順は省略)。$rails new scaffold_sample $cd scaffold_sample $rails g scaffold user name:string age:integer $rails db:migrateindexビューにテキスト項目と、検索結果を表示する項目を作成します。
index.html.erb<input type=form id="form" placeholder="ユーザー名を入力" style="width: 250px;"/> <p id="result1"></p>coffeeスクリプトは利用しないで、jQueryを利用するため、javascrpts/user.coffeeの拡張子を、jsに変更します。そして、ビューのイベントに対応する処理と、イベントが駆動された時にAjax通信を行う設定を記述します。
javascrpts/user.js$(document).on('turbolinks:load', function(){ // blurは、テキスト項目からロストフォーカスした時に発生するイベント $(document).on('blur', '#form', function(e){ e.preventDefault(); //テキストで入力した値を変数にセット var input = $.trim($(this).val()); //ajax通信の設定 $.ajax({ url: '/users/search', //searchメソッドへ遷移 type: 'GET', //メソッドを指定 data: ('keyword=' + input), //テキスト項目に入力した値を変数にセット processData: false, //おまじない contentType: false, //おまじない dataType: 'json' //データ形式を指定 }) .done(function(data){ }) }); });userコントローラの中に、searchメソッドを作成するので、searchメソッドへのルートを設定します。
routes.rbresources :users do collection do get 'search' end endusersコントローラの中に、searchメソッドを作成します。Viewのテキスト項目に入力した値が、jsファイルの中で、keyword変数にセットされて、コントローラに渡されてきます。コントローラの中では、keyword変数をキーに、Userテーブルを検索して、検索結果を、@user変数にセットしています。そして、json形式でrenderします。render先は、searchというビューあるのではなく、ajaxを利用する場合、遷移元(indexビュー)に遷移される事になります。
users_controller.rbdef search @user = User.find_by(name: params[:keyword]) render json: @user endjsファイルに、ajax通信が成功した後の処理(.doneの中身)を記述します。
javascrpts/user.js$(document).on('turbolinks:load', function(){ // blurは、テキスト項目からロストフォーカスした時に発生するイベント $(document).on('blur', '#form', function(e){ e.preventDefault(); //テキストで入力した値を変数にセット var input = $.trim($(this).val()); //ajax通信の設定 $.ajax({ url: '/users/search', //searchメソッドへ遷移 type: 'GET', //メソッドを指定 data: ('keyword=' + input), //テキスト項目に入力した値を変数にセット processData: false, //おまじない contentType: false, //おまじない dataType: 'json' //データ形式を指定 }) //ajax通信が成功したらdoneに入る (dataには@usersが入る) .done(function(data){ // data変数の中身を、viewの#result1に表示する $(data).each(function(i, user){ $('#result1').text(user.id + " " + user.name) }); }) }); });動作確認
rails sで、http://192.168.33.10:3000/users にアクセスします。
適当にデータを新規更新します。
- 投稿日:2020-04-30T11:18:14+09:00
resource resourcesって何が違うの??
Railsルーターの目的
そもそもルーティングは何をしてるんや。という話。
Railsのルーターは受け取ったURLを認識し、適切なコントローラ内アクションやRackアプリケーションに割り当てます。ルーターは、ビューでこれらのパスやURLを直接ハードコードすることを避けるためにパスやURLを生成することもできます。つまり受け取ったURLを捌いて指示を出す、司令塔ですよってこと。
resources と resource の違い
①URLにidを必要とするかしないのか
②resourceの場合単数なので、一覧みたいな概念はなく、indexが作られないresources 複数
リソースをいくつも定義しなければならない場合は、以下のように簡単にわかりやすくできる。get,new,create,edit,update,destroy,showがresourcesでまとめられる!(only、exceptで限定することも可能)
resources :photos, :books, :videos上の記法は以下と完全に同一です。
resources :photos resources :books resources :videosポイントとしては、リソース名がbooks、photosのような複数形になっていることにも注意
リソースが複数なのでidを持たないと識別できないresource 単数
ユーザーがページを表示する際にidを一切参照しないリソースが使われることがあります。たとえば、/profileでは常に「現在ログインしているユーザー自身」のプロファイルを表示し、他のユーザーidを参照する必要がないとします。このような場合には、単数形リソース (singular resource) を使ってshowアクションに (/profile/:idではなく) /profileを割り当てることができます。
get 'profile', to: 'users#show'結局どういうこと?
①URLにidを必要とするかしないのか
下記のようにresourcesが複数だとidが必要
resourceが単数だとidは要らない。/mobile/posts/:id(.:format) ←postは何個も存在するためidが必要 /mobile/profile/edit(.:format) ←profileは一つしか存在しないため、idがいらない②resourceの場合単数なので、一覧みたいな概念はなく、indexが作られない
routes.ebresource :users生成されるルーティング
new_users GET /users/new(.:format) users#new edit_users GET /users/edit(.:format) users#edit users GET /users(.:format) users#show PATCH /users(.:format) users#update PUT /users(.:format) users#update DELETE /users(.:format) users#destroy POST /users(.:format) users#create参考文献
https://railsguides.jp/routing.html#%E5%8D%98%E6%95%B0%E5%BD%A2%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9
- 投稿日:2020-04-30T10:33:24+09:00
[devise]値を配列の形で保存する
背景
deviseを使っている上で、配列の形でデータを送りたいと考えたが、なかなかやり方が見つからず苦労してやっと実装出来たので、備忘録や他の人の役に立てればと思い書きました。
実装方法
deviseのデフォルトで設定されたカラム以外を保存する際に以下のコードを書いてあげるが、
配列を渡す時は「:category_ids => []」のように空の配列を一緒に付けてあげればうまく保存されます。application_controller.rb#中略 protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :self_introduction, :sex, :img_name, :category_ids => []]) devise_parameter_sanitizer.permit(:account_update, keys: [:name, :self_introduction, :sex, :img_name, :category_ids => []]) end #中略すごく時間がかかりましたが以外と簡単だったことに驚きました。。
deviseはやはり便利な分難しいですね
- 投稿日:2020-04-30T07:44:13+09:00
Heroku Postgres じぶんまとめ
プランアップする
1.まずは追加
新しいDatabaseをリソースから追加する。追加するときに、採用したいプランを選ぶ。
HEROKU_POSTGRESQL_CYAN のように追加される。PINKとか色の名前が割り当てられている模様。2.copy
Database を追加した後、追加された HEROKU_POSTGRESQL_CYAN へコピーする。
heroku pg:copy DATABASE_URL HEROKU_POSTGRESQL_CYAN --app myapp3. DATABASE 削除
古い方を削除。DATABASEがない状態になる。
フロントとめておくためにはメンテナンスモードにする。4. attachment
同じ app に attach すると、DATABASEに割り当てられる。
その後、CYAN を削除する。cf.
アップグレードの手順の中に、 copy の説明がある。
Upgrading the Version of a Heroku Postgres Database
https://devcenter.heroku.com/articles/upgrading-heroku-postgres-databasesCLIから指定するのはこちらに。
Sharing Heroku Postgres between applications
https://devcenter.heroku.com/articles/heroku-postgresql#sharing-heroku-postgres-between-applications
- 投稿日:2020-04-30T03:30:33+09:00
DB設計でのデータ型の決定方法
そもそもなぜデータ型を指定しないといけないの?
データ型を指定するという事は変数がどのくらいのメモリ領域を必要とするかをDBに教えてあげる行為です。
仮にデータ型を指定する,というプロセスがない場合どうなるでしょうか?
宣言された変数はどんな型のデータが入ってもいいように、一番大きくメモリを使うデータ型の分,メモリを占有します。
ユーザーが少ないWebアプリの場合なら一つ一つのメモリが無駄にスペースを取っていても処理結果の差を感じる事はありませんが,TwitterやYouTube等の大型サービスになっていくと無視できない存在になってきます。
ですので,自分の開発アプリが大規模なユーザーを抱えていくであろう事を期待しつつ,丁寧に一つ一つのカラムにデータ型を記述していきましょう。
とりあえずよく使うデータ型について復習しよう
個人的によくみるデータ型を列挙してみますので復習がてらに確認していきましょう。
データ型 特殊能力 string 文字列(1〜255文字) text 文字列(1〜4294967296文字) integer 整数(4バイト) bigint 整数(8バイト) 上記のデータ型だけマスターすればもう貴方はデータ型マスターです。
さよならバイバイして旅に出た甲斐がありました。お疲れ様です。文字列,整数の長さによってデータ型を選択しないといけないので,それぞれの注意点について解説します。
文字列
これに関してはあまり深く考えなくても大丈夫です。
単語の記入を促す場合はstringを使用する。
文章の記入を促す場合はtextをしようして下さい。
日本語ならピカソのフルネームでもstringで格納できるのでnameカラムの場合もstringでLGTMです。
整数(重要)
半角数字の場合,integerは8桁,bigintは16桁まで格納できます。
クレジットカードの番号は8桁超えるのでbigintで登録して下さい。
※これを伝えたかったまた,idも将来的にユーザーが増えると膨大な桁数になる可能性があります。
railsではデフォルトでbigintになっているので,bigintをチョイスする事をお勧めします。参考文献
Ruby on Rails のドキュメント
https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_column
- 投稿日:2020-04-30T00:57:50+09:00
【Favorite】Rails いいね機能 実装
【ゴール】
ユーザーに投稿に対していいね機能を実装する
いいねを押すとハートが赤くなる参考:https://qiita.com/nojinoji/items/2c66499848d882c31ffa
【メリット】
UI、UXの向上
アソシエーションの理解度向上【開発環境】
■ Mac OS catalina
■ Ruby on Rails (5.2.4.2)
■ Virtual Box:6.1
■ Vagrant: 2.2.7【実装】 "user" "post"機能実装は割愛
- favorite model作成
mac.terminal$ rails g model Favorite
- アソシエーション 追記
※ user : favorite = 1 : 多
※ post : favorite = 1 : 多config/post.rbhas_many :favorites def favorited_by?(user) favorites.where(user_id: user.id).exists? endconfig/user.rbhas_many :favoritesconfig/favorite.rbbelongs_to :user belongs_to :postroute 追記
※ "favorite" は "post" に関連しているのでルートをネスト(親子)させるconfig/routes.rbresources :posts do resources :favorites , only: [:create , :destroy] endfavorite controller作成
※ "create" , "destroy"も一緒に作成mac.terminal$ rails g controller Favorites create destroyfavorite controller記述
① , ②で user_id post_id をparameterに渡すfavorites_controller.rbclass FavoritesController < ApplicationController def create @post = Post.find(params[:post_id]) ① favorite = @post.favorites.new(user_id: current_user.id) ② favorite.save flash[:success] = "Liked post" redirect_to request.referer end def destroy @post = Post.find(params[:post_id]) ① favorite = current_user.favorites.find_by(post_id: @post.id) ② favorite.destroy redirect_to request.referer end endview記述
※ modelで記述 ”@post.favorited_by?” を使用post/show.html/erb<% if @post.favorited_by?(current_user) %> <%= link_to post_favorite_path(@post), method: :DELETE do %> <i class="fa fa-heart" aria-hidden="true" style="color: red;"></i> <%= @post.favorites.count %>like <% end %> <% else %> <%= link_to post_favorites_path(@post) , method: :POST do %> <i class="fa fa-heart-o" aria-hidden="true"></i> <%= @post.favorites.count %>like <% end %> <% end %>以上
- 投稿日:2020-04-30T00:05:53+09:00
docker-composeでアプリサーバーコンテナからMySQLサーバーコンテナに接続する。
実行環境
Docker for Mac
Docker version 19.03.8簡単な事だけどかなり手こずったのでまとめ。
Dockerfile
FROM ruby:2.7.1-buster RUN gem install rails # node.jsをインストール RUN apt-get update && \ apt-get install -y node.js # yarnをインストール RUN apt-get update && apt-get install -y curl apt-transport-https wget && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && apt-get install -y yarn RUN rails webpacker:install RUN yarn install --check-files COPY Gemfile /Gemfile COPY Gemfile.lock /Gemfile.lock RUN bundle install *開発環境には node.js、 yarn、 webpackerのインストールが必要なので先にインストールしておく。docker-compose.yml
version: "3" services: mysql: image: mysql:8.0.20 command: --default-authentication-plugin=mysql_native_password environment: MYSQL_ROOT_PASSWORD: root app: build: . volumes: - ".:/app" ports: - "3000:3000" tty: true depends_on: - mysql working_dir: "/app"これらを元にdocker-composeでコンテナを立ち上げていきます。
$ docker-compose up立ち上がったらコンテナ内にアクセス。
$ docker exec -it (立ち上げたコンテナのNAMES) /bin/bashmariadb-clientをインストール
$ apt install mariadb-clientmysqlにアクセス
$ mysql -u root -proot -h mysql * docker-compose.yml参照 -u = ユーザーを指定 -p = 指定したユーザーのパスワード -h = ホスト、mysqlコンテナの名前?MySQL [(none)]> *アクセス成功一度ログアウトしconfig/database.ymlを編集します。
具体的にはdatabaseがsqliteになっていたのでmysql2に変更します。# SQLite. Versions 3.8.0 and up are supported. # gem install sqlite3 # # Ensure the SQLite 3 gem is defined in your Gemfile # gem 'sqlite3' # default: &default adapter: mysql2 encording: utf8 username: root password: root host: mysql pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 development: <<: *default database: rails_development # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default database: rails_test production: <<: *default database: rails_productionGemfileもsqliteからmysqlに変更
source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.7.1' gem 'rails', '~> 6.0.2', '>= 6.0.2.2' # sqliteからmysql2へ gem 'mysql2' gem 'puma', '~> 4.1' gem 'sass-rails', '>= 6' gem 'webpacker', '~> 4.0' gem 'turbolinks', '~> 5' gem 'jbuilder', '~> 2.7' ~省略~$ rake db:create $ mysql -u root -proot -h mysql * もう一度mysqlに接続 $ show databases; * rake db:createが出来ているか確認MySQL [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | rails_development | | rails_test | | sys | +--------------------+ 6 rows in set (0.011 sec)一応ここまでやっとけば開発できると思う。完全に自分用で参考にならないかもしれません。
参考: Docker超入門 Part03 - 複数コンテナを動作させる








