- 投稿日:2020-03-21T23:41:01+09:00
rbenvを利用してRubyのバージョンを最新安定版にする
環境
- macOS Mojave 10.14.6
- rbenv 1.1.2
- Homebrew 2.2.10
方法
1. 公式サイトで最新版を確認する。
https://www.ruby-lang.org/ja/downloads/
2. rbenvのインストール可能なバージョン一覧に、1.で確認したバージョンがあるか確認する。
$ rbenv install --list(もし確認したバージョンが無い場合)
以下のコマンドで、rbenvとruby-buildを更新する。
$ brew upgrade rbenv ruby-build再度、rbenvのインストール可能なバージョン一覧に、1.で確認したバージョンがあるか確認する。
$ rbenv install --list3. rbenvで1.で確認したバージョンをインストールする。
※今回はバージョン2.7.0
$ rbenv install 2.7.0インストールされているか確認する。
$ rbenv versions4. インストールしたバージョンは適用させる。
(環境全体に適用)
$ rbenv global 2.7.0適用されているか確認する。(適用されていない場合はカレントディレクトリに適用させる。)
$ rbenv versions(カレントディレクトリに適用)
$ rbenv local 2.7.0適用されているか確認する。
$ rbenv versionsおわりに
『もっと簡単にできる方法あるよーーー!』
『ここわかりにくいよーーー!』
『ここ間違っているよーーー!』
等あればコメントいただけるとめちゃくちゃ嬉しいです!!!
twiiter → https://twitter.com/jiko797torayo
- 投稿日:2020-03-21T22:54:52+09:00
railsストロングパラメータについて
はじめに
ストロングパラメータについて調べたので備忘録として記事にしました。
対象読者
プログラミング勉強始めたての方。
題材
自分のポートフォリオのUserオブジェクト周りを題材としています。
ストロングパラメータとは
ユーザー登録フォームなどによって送られてきた情報を限定して取得し、データベースに一気に保管出来るようにした処理のことです。なぜ、情報を限定するかというとユーザー側にいじって欲しくない情報をデータベースに保存させないようにするためです。
例えば管理者情報などをいじられて勝手に管理者にならないようにしています。
また、複数カラムにデータを保存できるようにする役割もあります。
実際に設定しているものがこちらです。app/controllers/users_controller.rbdef create @user = User.new(user_params) if @user.save log_in @user flash[:success] = 'ユーザー登録完了' redirect_to root_url else render 'new' end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation)基本的にはコントローラーのprivate内(カプセル化)で定義し、create等のアクション渡します。(private内に定義する理由はこのコントローラないでしか参照しない、コードがすっきりするからです。)
ストロングパラメータ内では3つのメゾットが定義されておりそれぞれに以下のような役割があります。
params:フォームなどで送られてきたメゾットを取得
require:送られてくる値が二次元ハッシュのときに使い引数に渡されたものがキーとなっているもののみ取得する。
permit:引数に渡されたもののみデータベースに保存するのを許可する。paramsについて
送られてきたメゾットを取得します。
フォームからのpostメゾットや検索フォームなどのgetメゾットでURLのクエリに入るデータがparamsで取得できるデータです。
※検索機能についてはこちら
https://qiita.com/E6YOteYPzmFGfOD/items/dc1ab3c19d4718a0edc8
実際に新規ユーザーを登録する時にはこんな感じでフォームからコントローラへ送られます。Parameters: {"utf8"=>"✓", "authenticity_token"=>"OSab8g1vpkYUMQI74VcZX08Ci82gTPxBCK/ YOZ766OzRmPuM/pYW5+ZX8gh/l+87UPpag69De8f+NjhCs+SqmA==", "user"=>{"name"=>"test", "email"=>"foo@bar.com", "password"=>"[FILTERED]", "password_confirmation"=> "[FILTERED]"}, "commit"=>"作成"}パラメータを取り出す際はこのように指定すれば取り出せます。
params[:user] <ActionController::Parameters {"name"=>"test", "email"=>"foo@bar.com", "password"=>"123456", "password_confirmation"=>"123456"} permitted: false> params[:user][:name]※二次元ハッシュ キーのnameにさらにuserがキーになっている。 "test"このようにして値を取り出せますが、このままcreateメゾットに渡してもエラーになります。
app/controllers/users_controller.rbdef create @user = User.new(user_params)※エラーになる。なぜエラーになるのかというと先ほどパラメータで取得した値の中に「permitted: false」とありますがこれがfalseになっているせいです。primittedはマスアサイメント機能を許可する部分になります。マスアサイメントとはdbに値を保存する時に複数のカラムを一括で指定できる機能になります。これをtrueにかえるのがpermitメゾットです。
permit
実際にpermitでdbに保存する値を限定することによってpermitがtrueになります。
※まさにストロングパラメータの形です。params[:user] <ActionController::Parameters {"name"=>"test", "email"=>"foo@bar.com", "password"=>"123456", "password_confirmation"=>"123456"} permitted: false> params.require(:user).permit(:name,:email,:password,:password_confirmation) <ActionController::Parameters {"name"=>"test", "email"=>"foo@bar.com", "password"=>"123456", "password_confirmation"=>"123456"} permitted: true>これでpermitted: trueになったのでストロングパラメータで取得したものをcreateアクションに渡すことで複数カラムに情報を保存できるようになりました。
requireについて
このメゾットは値が二次元ハッシュで送られる時(post)に必要となり、引数に渡したキーの値だけを取得できるようになります。
params <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"OSab8g1vpkYUMQI74VcZX08Ci82gTPxBCK/YOZ766OzRmPuM/pYW5+ZX8gh/l+87UPpag69De8f+NjhCs+SqmA==", "user"=><ActionController::Parameters {"name"=>"test", "email"=>"foo@bar.com", "password"=>"123456", "password_confirmation"=>"123456"} permitted: false>, "commit"=>"作成", "controller"=>"users", "action"=>"create"} permitted: false> params.require(:user) <ActionController::Parameters {"name"=>"test", "email"=>"foo@bar.com", "password"=>"123456", "password_confirmation"=>"123456"} permitted: false>最後に
ここまでお付き合いいただきありがとうございました。
また、何か気になったことがあれば記事にしたいと思います。
間違い等コメントいただけると幸いです。
それではありがとうございました。
- 投稿日:2020-03-21T22:33:24+09:00
LoadError, Unable to autoload constant ~
本記事投稿のいきさつ
railsでアプリ作成をしていたところLoadErrorが発生し基礎知識がなかったためにハマったため忘れないように、書き残します。
また、同じエラーで困っている初心者のためになれば幸いです。エラー発生
itemモデルとitem_imageモデルでアソシエーションを組み,以下の記述をしたところエラーが発生
items_controller.rbdef new @item = Item.new @item_images = Item_image.new endエラー表示は以下です。
LoadError in ItemsController#newUnable to autoload constant Item_image, expected *****/models/item_image.rb to define it解決まで
なるほど。アソシエーションの記入を間違えたのか。
と初学者の自分は考えitem_image.rbを確認します。
item_image.rbの記述は以下です。item_image.rbclass ItemImage < ApplicationRecord belongs_to :item endあれ?ちゃんと書けている。
と初学者の自分は思いました。自分の仮説が外れたので、Google先生に聞いてみました。解決
Googleで調べたところどうやら
モデル名にアンダーバーを使ってもクラス名にアンダーバーはつかないとのことです。
ということでitems_controller.rbを編集。
items_controller.rbdef new @item = Item.new @item_images = ItemImage.new end無事解決することができました。
とても基本的なことですが、今までモデル名にアンダーバーを使っていなかったため、気づくこと出来なかった自分にとってはいい経験になりました。おわり
最後まで見ていただき、ありがとうございました。
- 投稿日:2020-03-21T21:50:41+09:00
ダックタイピング
ダックタイピングとは
もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルに違いない
(wikipediaより)
Rubyの例def test(foo) puts foo.sound end class Duck def sound 'quack' end end class Cat def sound 'myaa' end end test(Duck.new) test(Cat.new)出力結果quack myaawikipedia読んでもだからなんなのというか、なんにも特別なことをしているように感じなかったのですが、調べるとどうやらそうではないことに気づきました。
型を意識しなくて良い
Javaと比較しているサイトがあり、そのコード例によりメリットが理解できました。
rubydef test(foo) puts foo.sound endjavavoid test(Duck foo) { foo.sound(); }もしもそのオブジェクトが Duckオブジェクト のように Walk()メソッド を呼び出すことができ、Duckオブジェクトのように Sound()メソッド を呼び出すことができるのなら、それは Duckオブジェクト として扱える。
私はpythonを主に使うので、型に対して意識することがほぼありません。rubyも同じでしょう。
しかし、Javaは違います。上記のコードでは、testは受け取るDuckの型を予め指定しています。これにより、型がなんであれ、振る舞いが同じならそれは問題ないという処理ができないわけです。
「引数 foo がどのようなオブジェクトであれ、 sound メソッドを呼び出せれば良い」と割り切っていることが、ダックタイピングです。
なるほどと思いました。
Rustは静的型付け言語ですが、トレイトという機能を使うことによりダックタイピングに似たコーディングができます。参考文献
https://ja.wikipedia.org/wiki/ダック・タイピング
https://blog.mmmcorp.co.jp/blog/2018/10/26/go-duck-typing/
- 投稿日:2020-03-21T21:29:40+09:00
Pay.jpを用いた購入機能の実装
概要
Pay.jpを用いた購入機能の実装を備忘録としてまとめます。
修正点ありましたらご指摘お願いいたします。
Transaction(取り引き)テーブルおよびProduct(商品)テーブルをもとに作っていきます。前提
- Pay.jpのアカウント作成済み
- Pay.jpにてクレジットカード登録機能は実装済み
- ビューはHamlで記載
- deviseにてログイン済み
手順
- Transactionテーブルを作成(購入済みの場合SOLD OUTを表示させるため)
- アソシエーションの設定
- Transactionコントローラーを作成
- 環境変数の設定
- ルーティングの設定
- マークアップ:購入内容確認画面
- マークアップ:購入完了画面
- マークアップ:購入済みの場合SOLD OUTを表示
- 購入データの確認
Transactionテーブルを作成
今回は購入済みの場合SOLD OUTを表示させるためにTransactionテーブルを作成します。
$ rails g model Transactiondb/migrate/20200000000000_create_transactions.rbclass CreateTransactions < ActiveRecord::Migration[5.2] def change create_table :transactions do |t| t.references :product, null: false, foreign_key: true t.references :user, null: false, foreign_key: true t.timestamps end end endマイグレートを実行
$ rails db:migrateアソシエーションの設定
transaction.rbclass Transaction < ApplicationRecord belongs_to :user, optional: true belongs_to :product, optional: true endTransactionコントローラーを作成
$ rails g controller transactionstransactions_controller.rbclass TransactionsController < ApplicationController require 'payjp' before_action :set_card, only: [:pay_index, :pay] before_action :set_product def pay_index @top_image = @product.images.first @card = @set_card.first if @card.blank? redirect_to controller: "cards", action: "new" else Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"] customer = Payjp::Customer.retrieve(@card.customer_id) @default_card_information = customer.cards.retrieve(@card.card_id) end end def pay @card = @set_card.first Payjp.api_key = ENV['PAYJP_PRIVATE_KEY'] Payjp::Charge.create( :amount => @product.price, :customer => @card.customer_id, :currency => 'jpy', ) redirect_to action: 'done', product_id: @product end def done @top_image = @product.images.first Transaction.create(product_id: @product.id, user_id: current_user.id) end private def set_card @set_card = Card.where(user_id: current_user.id) end def set_product @product = Product.find(params[:product_id]) end end環境変数の設定
コントローラ内のENV["PAYJP_PRIVATE_KEY"]は環境変数でテスト秘密鍵を設定し読み込む。
今回はdotenvとgonを利用する。dotenv:Railsの環境変数管理
gon:JSにてRailsで定義した環境変数を使用
参考:https://qiita.com/3443/items/44202ff6504210592570#comments※gonはCard登録機能にて使用したため今回は関係ありません
ルーティングの設定
routes.rbRails.application.routes.draw do devise_for :users root "products#index" resources :users, only: [:edit, :update] resources :products resources :cards, only: [:new, :show, :destroy] do collection do post 'pay_show', to: 'cards#pay_show' post 'pay', to: 'cards#pay' end end ##今回の該当箇所 resources :transactions, only: [:index] do collection do get 'pay_index', to: 'transactions#pay_index' post 'pay', to: 'transactions#pay' get 'done', to: 'transactions#done' end end endマークアップ:購入内容確認画面
pay_index.html.haml.transaction-pay .transaction-pay__content %h2.transaction-pay__title 購入内容の確認 .transaction-pay__item .transaction-pay__item-box = image_tag @top_image.image.url, alt:"商品画像", class: "transaction-pay__item-image" .transaction-pay__item-detail %p.transaction-pay__item-detail--name = @product.name .transaction-pay__item-detail-price .transaction-pay__item-detail-price--text ¥ .transaction-pay__item-detail-price--text = @product.price .transaction-pay__item-detail-price--shipping (税込)送料込み .transaction-pay__table .transaction-pay__table-inner .transaction-pay__table-form .transaction-pay__table-content .transaction-pay__table-pay %p.transaction-pay__table-pay--title 支払い金額 .transaction-pay__table-price %p.transaction-pay__table-price--title ¥ %p.transaction-pay__table-price--title = @product.price .transaction-pay__table-way %h3 支払い方法 .transaction-pay__table-register - if @default_card_information.blank? %i.fas.fa-plus-circle %span.icon-register = link_to "登録してください", new_card_path - else = "**** **** **** " + @default_card_information.last4 - exp_month = @default_card_information.exp_month.to_s - exp_year = @default_card_information.exp_year.to_s.slice(2,3) = exp_month + " / " + exp_year .transaction-pay__table-buy = form_tag(action: :pay, method: :post, product_id: @product) do %button.transaction-pay__table-buy-button 購入するマークアップ:購入完了画面
done.html.haml.transaction-done .transaction-done__content .transaction-done__text 購入が完了しました! .transaction-done__image = image_tag @top_image.image.url, alt:"商品画像", class: "transaction-done__image--img" .transaction-done__title = @product.name .transaction-done__price .transaction-done__price--text = @product.price .transaction-done__price--info (送料込み)マークアップ:購入済みの場合SOLD OUTを表示
show.html.haml.product-show .product-show__main .product-show__content .product-show__top-content .product-show__item-box .product-show__item-box--name = @product.name .product-show__item-box__body .product-show__item-box__body--top-img = image_tag @top_image.image.url, alt:"トップ画像", class: "product-show__item-top-img" .product-show__item-box__body--list - @images.each do |image| .product-show__item-box__body--sub-img = image_tag image.image.url, alt:"サブ画像", class: "product-show__item-sub-img" .product-show__item-box--price %span = "#{@product.price}円" .product-show__item-box--price-detail %span.product-show__item-box--price-detail-text (税込) %span.product-show__item-box--price-detail-text = @product.delivery_charge .product-show__item-box--item-detail = @product.name -# 商品出品者であれば表示させない - if user_signed_in? && (current_user.id == @product.user_id) - else .product-show__transaction .product-show__transaction-box -# 商品購入済みであればSOLD OUT - if @product_id.present? .product-transaction-btn SOLD OUT - else = link_to "購入画面に進む", pay_index_transactions_path(product_id: @product), class: "product-transaction-btn"購入データの確認
購入ができていれば下記のURLにて履歴が確認できます。
https://pay.jp/d/charges以上です
- 投稿日:2020-03-21T21:28:27+09:00
docker-compose buildでYou must use Bundler 2 or greater with this lockfile.とエラーが出た話
経緯
「既存の作成済のrailsアプリケーションにDockerを導入してみたい!!でも、いきなり導入していろいろ変なことになったら嫌だな」ということで、Railsチュートリアルの開発環境をDockerにしてみなイカ?という記事を参考にさせていただき、まずはrailsチュートリアルをdockerにのせようと、奮闘している最中、
You must use Bundler 2 or greater with this lockfile. ERROR: Service 'app' failed to build: The command '/bin/sh -c bundle install --jobs=4' returned a non-zero code: 20
というエラーが。。
解決した方法
You must use Bundler 2 or greater with this lockfile.
これは、Bundlerのバージョンが2以上を使わなければならなかったのに、Dockerのimageで1.X.Xを利用していたことが原因だったみたいです。
確かに、Gemfile.lockを見ると、一番最後の行に、BUNDLED WITH 2.1.4の記載が。。。
そこで、docker-compose buildした際に、bundlerをinstallすれば問題ないと知り、
Dockerfileにて~~~略~~~ RUN bundle installとしていたところを
~~~略~~~ RUN gem install bundler && bundle installのように、bundlerをインストールすることで解決しました!!
- 投稿日:2020-03-21T19:50:26+09:00
#Ruby の tap で ネストされたハッシュのキーを削除しつつ返り値で変更後の値を受け取る
- 投稿日:2020-03-21T18:57:25+09:00
[Rails]いいねした商品をマイページに一覧表示する
ユーザー(user)のマイページ(show)にいいね(like)した商品一覧を表示させます。
モデルの指定はこちらに記載してます。ルーティング
routes.rbresources :users, only: [:index, :show] do collection do get :likes end enduserのshowアクションにネストさせます。
モデル
user.rbhas_many :likes, dependent: :destroy has_many :like_items, through: :likes, source: :item※今回のポイント
like_items
でuserがどのitemにいいねしているか取得できます。ビュー
users/_side-bar.html.haml.side-bar %section.side-bar__group %h2.side-bar__group__title マイページメニュー %li.side-bar__group__list = link_to "お知らせ", "#" %li.side-bar__group__list = link_to "いいねした商品", likes_users_pathリンク先
likes_users_path
指定users/likes.html.haml.container-show = render "side-bar" .main %section.main__group %h2.main__group__title 〇〇さんのマイページ %section.main__table %h2.main__table__header いいね!一覧 %ul.main__table__list - current_user.like_items.each do |item| %li =link_to item_path(item), class: "main__table__list__item" do %figure = image_tag asset_path(item.images[0].content), :size =>'48x64' .main__table__list__item__body .main__table__list__item__body__text = item.name %br = item.price 円 %i.fas.fa-chevron-rightlikeファイルを作成
- current_user.like_items.each do |item|
で現在ログインしているuserがいいねしたitemを取得しています。
=link_to item_path(item)
で各商品詳細ページに遷移できるようにしてます。完成イメージ
ご指摘ありましたらぜひコメントよろしくおねがいします!!
- 投稿日:2020-03-21T18:26:27+09:00
[Rails]非同期のいいね機能実装
ユーザー(user)が出品した商品(item)にいいねできる機能を実装してます。
Likeモデル、テーブル作成
rails g model Like
like.rbclass Like < ApplicationRecord endXXXXXXXXXXX_create_likes.rbclass CreateLikes < ActiveRecord::Migration[5.2] def change create_table :likes do |t| t.integer :user_id t.integer :item_id t.timestamps end end end
rails db:migrate
マイグレーションファイル実行モデル
通常はuserとitemは1対多の関係ですが、いいね機能実装時に関してはlikeテーブルが加わるので、多対多の関係になります。
user.rbhas_many :likes, dependent: :destroy has_many :like_items, through: :likes, source: :itemitem.rbhas_many :likes, dependent: :destroy has_many :liking_users, through: :likes, source: :user
dependent: :destroy
はいいねを外した時に、中間likesテーブルにある該当userとitemのレコードを一緒に削除してくれます。
:like_items
はuserがどのitemをいいねしているのかを取得
:liking_users
はitemがどのuserによっていいねされているのか取得
through: :likes
は多対多の関係で中間likeテーブルを経由するための関連付けで記述
source:
オプションは関連付け元の名前を指定するため記述like.rbclass Like < ApplicationRecord belongs_to :item, counter_cache: :likes_count belongs_to :user end
counter_cahce: :likes_count
はリレーションされているlikeの数の値をリレーション先のlikes_countというカラムの値に入れるという意味です。なのでlikes_countカラムをitemsテーブルに追加しましょう。itemsテーブルにlikes_countカラム追加
rails g migration AddLikes_countToItems
XXXXXXXXXXX_add_likes_count_to_items.rbclass AddLikesCountToItems < ActiveRecord::Migration[5.2] def change add_column :items, :likes_count, :integer end end
rails db:migrate
マイグレーションファイル実行ルーティング設定
routes.rbresources :items member do post '/like/:item_id' => 'likes#like', as: 'like' delete '/like/:item_id' => 'likes#unlike', as: 'unlike' endいいねをつける時→like 外す時→unlike
as:でルーティングに名前を付けれる。この二つはlike_path,unlike_pathとして使えるようになります。コントローラー
rails g contoller likes
likes_controller.rbclass LikesController < ApplicationController before_action :set_variables def like like = current_user.likes.new(item_id: @item.id) like.save end def unlike like = current_user.likes.find_by(item_id: @item.id) like.destroy end private def set_variables @item = Item.find(params[:item_id]) @id_name = "#like-link-#{@item.id}" end end
@id_name
は非同期で使用します。ビュー
items/show.html.haml.option = render partial: 'likes/like', locals: { item: @item }
render
を使用し、部分テンプレートへ誘導
likesディレクトリに部分テンプレート_like.html.haml
ファイルを作成likes/_like.html.haml.option__like{:id => "like-link-#{@item.id}"} - if current_user.likes.find_by(item_id: item.id) = link_to unlike_item_path(@item.id, @item.id), method: :delete, remote: true, class: "option__like-on" do .fas.fa-star .option__like-on__text いいね! .option__like-on__count =item.likes.count - else = link_to like_item_path(@item.id, @item.id), method: :post, remote: true, class: "option__like-off" do .fas.fa-star .option__like-off__text いいね! .option__like-off__count =item.likes.countいいねボタンのビューを記述します。
{:id => "like-link-#{@item.id}"}
をつけることで@itemのボタンであることを指定します。
remote: true
をつけることでリンクを押した時、ajaxを発火させます。
=item.likes.count
でいいねされた数を表示します。いいねボタンの非同期化
like.js.haml
とunlike.js.haml
ファイル作成likes/like.js.haml$("#{@id_name}").html('#{escape_javascript(render("likes/like", item: @item ))}');likes/unlike.js.haml$("#{@id_name}").html('#{escape_javascript(render("likes/like", item: @item ))}');コントローラーで定義した
@id_name
を指定し、escape_javascript
で先ほど作成した_likeファイルを埋め込んでます。Sass
item.show.scss.option { display: flex; justify-content: space-between; &__like { &-on { text-decoration: none; padding: 11px 10px; border-radius: 40px; color: #3CCACE; border: 1px solid #ffb340; display: flex; line-height: 16px; .fas.fa-star { padding-right: 5px; } &__text { padding-right: 5px; } } &-off { text-decoration: none; padding: 11px 10px; border-radius: 40px; color: #333; border: 1px solid #f5f5f5; display: flex; line-height: 16px; background: #f5f5f5; .fas.fa-star { padding-right: 5px; } &__text { padding-right: 5px; } } } }sassの説明は省略します。
完成イメージ
ユーザーがいいねした商品一覧を表示させたい方はこちらをご覧ください
間違えている部分があったらぜひコメントよろしくお願いします!!
- 投稿日:2020-03-21T18:22:08+09:00
[Ruby on Rails]enumを用いたselectフォームの作成
selectを作る際に、選択肢が3つ程度のものであればoptionで記載しても良いかとは思いますが、多くなればコードが冗長になってしまいます。
enumを用いているカラムに対してであれば、スッキリ綺麗なコードで実装できます。実装した機能
gyazoリンク
https://gyazo.com/67a692c100281014ff59426fa6eb1a53enumとは
列挙型、列挙クラスといわれる。
本記事はenumについてではないため、ザックリとした説明になりますが、
自分の認識では、
わざわざ、tableを作成し、外部キーとして呼ばなくとも中身を持ったidとして管理できるものどんなものに使うのか?
enumを使う代表的なものといえば、都道府県でしょうか
optionで書くのも面倒ですし、テンプレを使ったとしても冗長で読みやすいコードとは言い難いですね。product.rbenum delivery_prefecture:{ "北海道":1,"青森県":2,"岩手県":3,"宮城県":4,"秋田県":5,"山形県":6,"福島県":7, "茨城県":8,"栃木県":9,"群馬県":10,"埼玉県":11,"千葉県":12,"東京都":13,"神奈川県":14, "新潟県":15,"富山県":16,"石川県":17,"福井県":18,"山梨県":19,"長野県":20, "岐阜県":21,"静岡県":22,"愛知県":23,"三重県":24, "滋賀県":25,"京都府":26,"大阪府":27,"兵庫県":28,"奈良県":29,"和歌山県":30, "鳥取県":31,"島根県":32,"岡山県":33,"広島県":34,"山口県":35, "徳島県":36,"香川県":37,"愛媛県":38,"高知県":39, "福岡県":40,"佐賀県":41,"長崎県":42,"熊本県":43,"大分県":44,"宮崎県":45,"鹿児島県":46, "沖縄県":47 }このように記載することで、今回でいうdelivery_prefectureがidで管理されるようになります
migrationファイルはintegerにしておきましょうselectフォームの作成
products/new.html.haml.form__group = f.label :delivery_prefecture do 発送元の地域 %span.form-description.form-require 必須 = f.select :delivery_prefecture, Product.delivery_prefectures.keys,{include_blank: '選択してください'},{class: "exhibition__select"}今回であれば
Product.delivery_prefectures.keys
モデル.カラム名(複数形).keys
この記述で選択肢に先ほどのenumの記述部分が適用されます。
注意としては、複数形にすることです。ちなみに
{include_blank: '選択してください'}
によって何も選択されていない時に 選択してください と表示されるようにしています
おまけ
products/new.html.haml.form__group = f.label :delivery_days do 発送までの日数 %span.form-description.form-require 必須 = f.select :delivery_days, Product.delivery_days.keys,{include_blank: '選択してください'},{class: "exhibition__select"}product.rbenum delivery_days:{ "1~2日で発送": 1, "2~3日で発送": 2, "3~7日で発送": 3, }このようにカラム名に複数形が使われている場合(あまり望ましくないが、dayだと変なので今回は止むを得ず、、)は、そのままカラム名を記載するだけでうまく行きます。
最後に
本記事がQiita初投稿になります
アドバイス等いただけたら幸いです!
- 投稿日:2020-03-21T17:03:45+09:00
Rubyの基本的なメソッドと参照について学んだこと
目次
- Rubyのメソッド
- 参照の概念
- ライブラリ
Rubyのメソッド
Rubyには標準でいろんなメソッドがあります。
また、自分でメソッドを定義することも可能です。
メソッドに引数を設定する
cry.rbdef cry(animal) if animal == 'dog' puts 'woof woof!' elsif animal =='cat' puts 'meow meow!' end end cry('dog') # -> woof woof! cry('cat') # -> meow meow! # 引数に過不足があるとエラーになる # cry -> `cry': wrong number of arguments (given 0, expected 1) (ArgumentError)メソッドを定義する際引数を設定できます。
今回はcryというメソッド名で引数によって動物の鳴き声を出力するメソッドを定義しました。
引数にはデフォルト値をつけることも可能
cry.rbdef cry(animal: 'cat') if animal == 'dog' puts 'woof woof!' elsif animal =='cat' puts 'meow meow!' end end cry(animal: 'dog') # -> woof woof! # 引数がない場合でもエラーにならない! cry # -> meow meow!通常引数は呼び出し側(実引数)とメソッド定義側(仮引数)で数が一致している必要があります。
ですが、メソッド定義側でデフォルト値を設定することが可能です。
今回はcryというメソッド名で引数によって動物の鳴き声を出力するメソッドに
引数が存在しない場合はデフォルト値をcatとして定義しました。
標準出力で使われるメソッド
puts 'Hello World' Hello World => nil print 'Hello World' Hello World=> nil p 'Hello World' "Hello World" => "Hello World"メソッドを定義してターミナルに出力確認をする際今回の記事ではputsメソッドを使用していますが他にもターミナルに出力できるメソッドがあります。
irbを使用して確認して見た結果
puts
引数のオブジェクトをto_sメソッドで文字列に変換し、改行を加えて出力する。
戻り値: nil
引数のオブジェクトをto_sメソッドで文字列に変換し、改行ををせず出力する。
戻り値: nil
p
引数のオブジェクトをinspectメソッドで文字列に変換し、改行ををせず出力する。
戻り値: 文字列
真偽値を返すメソッド
boolean.rb# ?で終わるメソッドを自作する場合 def what_name?(name) name == 'bob' end p what_name?('tom') # -> false p what_name?('bob') # -> true真偽値を返すメソッドとしてメソッド名の終わりに?をつけたメソッドがあります。
※"".empty?
や"Hello World".include?(Hello)
など自作する場合でもメソッド名に?をつけたほうが戻り値がわかりやすくなります。
エイリアスメソッド
alias.rb# メソッドを定義する def hello puts 'Hello World!' end # aliasを設定する alias greeting hello # 元のメソッド名でも呼び出せ、aliasで設定した別名でも同様に呼び出すことができる hello # -> Hello World! greeting # -> Hello World!Rubyにはメソッドに複数の名前をついている場合、自分で任意の名前
で定義することができます。
今回はhelloメソッドの名前をgreetingと別名で定義しました。
Rubyの戻り値
expression.rbdef expression hello = 'Hello World' end # retern分を記載しなくても最後に評価された式が戻り値として取得できる p expression # -> Hello Worldexpression.jsfunction expression() { let hello = "Hello World" // return hello } // return文を記載しなければ戻り値を取得できない console.log(expression()) // -> undefined function expression() { let hello = "Hello World" return hello } // return文を記載すれば戻り値を取得できる console.log(expression()) // -> Hello WorldRubyのメソッドでは
return
を記載しない場合、
最後に評価されたものが戻り値になります。
これは他の言語と少し違います。
試しにrubyでreturn
を記載しないで定義したメソッドと
javascriptでreturn
を記載しないで定義したメソッドを比較してみます。
擬似変数
pseudo_variable.rbp true # -> true p self # -> main p __FILE__ # -> ファイル名 p __LINE__ # -> 行番号 p __ENCODING__ # -> エンコーディング # 擬似変数に代入しようとすることはできない # p __ENCODING__ = 'test' # -> Can't assign to __ENCODING__Rubyには擬似変数と呼ばれる特殊な変数が存在します。
擬似変数は値を変更することはできません。
破壊的メソッド
destroy.rblang = 'ruby' # upcaseだと呼び出した文字列自身は変化しない p lang.upcase # -> RUBY p lang #-> ruby #upcase!だと呼び出した文字列自身が変化する p lang.upcase! # -> RUBY p lang # -> RUBYRubyのメソッドにはオブジェクトの値そのものを変更してしまうメソッドが存在します。
今回はupcase
,upcase!
を使用して'ruby'という文字列を'RUBY'に変換します。
以下の出力結果を確認するとupcase
の場合、変数aの値は変化していません。
しかし、upcase!
の場合変数aの値が変わっています。
このように破壊的メソッドを使用すると呼び出したオブジェクトの状態を変更することができます。
参照の概念
Rubyのメソッドが色々あるなか破壊的メソッドを用いた場合、値が書き換わりました。
実際にはRubyの変数に代入すると変数に値が格納されるわけではありません。
変数にはオブジェクトの参照情報が格納されます。
メモリ領域
パソコンがしてくれる作業を僕ら人間に当てはめるとこんな感じになります。
1. 考える脳みそ -> CPU
2. 作業する机 -> メモリ
変数に値を格納した時パソコンのメモリ領域(作業する机の領域)がどうなるかというとこんなイメージになります。
destroy.rblang = 'ruby' # upcaseだと呼び出した文字列自身は変化しない p lang.upcase # -> RUBY # upcaseした際のオブジェクト番号を確認 p lang.upcase.object_id # -> 70178687801560 p lang #-> ruby # 変数のオブジェクト番号を確認 p lang.object_id # -> 70178687801780 # upcase!した際のオブジェクト番号を確認 p lang.upcase!.object_id # -> 70178687801780 p lang # -> RUBY # 変数のオブジェクト番号を確認 p lang.object_id # -> 70178687801780ここで先ほどの破壊的メソッドについて戻ろうと思います。
upcase
とupcase!
でのオブジェクト番号を確認すると
upcase
ではオブジェクト番号が違うため、新しくオブジェクトを生成し、そのオブジェクトの参照情報を格納しております。
upcase!
ではオブジェクト番号が同一であることがわかります。
このことから変数にはオブジェクトへの参照が格納されており破壊的メソッドを使用することで、指定のオブジェクトの中身を書き換えているということがわかりました。
ガベージコレクション(GC)
パソコンがいろんな処理を行う際、作業机(メモリ領域)の場所を確保していきます。
作業机(メモリ領域)が場所が減っていくとそのうちスペースがいっぱいになってしまいます。
スペースがいっぱいになると僕ら人間が効率よく作業できないのと同様にパソコンも作業スペース
(メモリ領域)が減っていくと何もできなくなり処理が重たくなったり、最悪システムが停止したりします。
このようにメモリ領域が減っていく現象をメモリリークと言います。このような状態にならないようにRubyにはガベージコレクションという機能が備わっています。
ガベージコレクションのおかげで僕らが作業スペースの後片付け(メモリの解放)をしなくても
使用されなくなったオブジェクトを片付けてくれます。
※家事代行サービスにお願いすればプロがよしなにやってくれる感じみたいですね。
ライブラリ
Rubyでは最初から便利なプログラムがたくさん用意されています。
その便利なプログラムを寄せ集めたものをライブラリと言います。
組み込みライブラリ
embedded_library.rbtext = 'Hello World' p text.class # -> String p text.methods.include?(:length) # -> true p text.length # -> 11人間でいうと本人の習得しているスキルのイメージです。
英語をネイティブレベルまで習得しているなら海外旅行に行って話す際、教科書を見なくても話せると思います。
※僕は英語話せませんが、、、組み込みライブラリは Ruby 本体に組み込まれているため、わざわざ処理を実装しなくても
同様の処理をするプログラムが組み込みライブラリに存在していればそれを使用すれば良いのです。今回は文字列の長さを取得する処理を実装するために、
String
クラスのlength
メソッドを使用しました。
標準ライブラリ
スキルはまだ身についてないけど家にある本棚から書籍を使えばアプリ開発ができるのと同じように
標準ライブラリではあるものの、組み込みライブラリでないものについてはライブラリを読み込むことで使用することができます。今回はTimeクラスに定義されているstrptimeメソッドを使用します。
standard_library.rbrequire 'Time' p Time.strptime('2020-03-21T01:58:30+09:00', '%Y-%m-%dT%H:%M:%S%z') # -> 2020-03-21 01:58:30 +0900
gem
スキルが身についていない、家の本棚にもない場合でも問題ありません。
Rubyでは偉大な先輩エンジニアの方々が外部ライブラリとして、RubyGemsにアップロードしてくれています。
僕らは使いたいgemをそこからダンロードして、自分の端末にインストールすることで使用することができます。今回はrails 5.2.3というgemをインストールして見ました。
gem i -v 5.2.3 rails
参考
プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで
- 投稿日:2020-03-21T16:01:33+09:00
複数画像投稿で盛大に自爆した時の確認事項[備忘録]
はじめに
某フリマアプリの模倣アプリを開発中、出品機能実装で複数画像の登録に死ぬほど手を焼いたので、備忘録として掲載します。
誤った記述などあればご指摘いただけると幸いです。
開発環境・前提
Ruby 2.5.1p57
Ruby on rails 5.2.3
jquery-rails 4.3.5
haml-rails 2.0.1
sass-rails 5.1.0
CarrierWave 2.1.0完成コード
先に完成コードを載せておく。
image.rbbelongs_to :item, optional: true validates_presence_of :item validates :content, presence: true mount_uploader :content, ImageUploaderitem.rbbelongs_to :brand, optional: true belongs_to :user, optional: true belongs_to :category, optional: true has_many :images, dependent: :destroy accepts_nested_attributes_for :images, allow_destroy: trueitems_controller.rbdef new @item = Item.new @brands = Brand.all @category_parent_array = ["指定なし"] Category.where(ancestry: nil).each do |parent| @category_parent_array << parent.name end @item.images.build end def create @item = Item.new(item_params) if @item.save! @image = @item.images.create redirect_to :root else render :new end end private def item_params params.require(:item).permit( :name, :description, :condition, :price, :fee, :brand_id, :area, :shipping_days, images_attributes: [:content, :id, :_destroy] ).merge(user_id: current_user.id, category_id: params[:category_id], brand_id: params[:item][:brand_id]) endnew.html.haml#画像投稿フォームの記述部分 .main-items = form_with model: @item, local: true do |f| .wrapper.image-wrapper #image-box.image-wrapper__image-box = f.fields_for :images do |i| .image-wrapper__image-box__js.js-file_group{data:{index: "#{i.index}"}} = i.label :content, class: "image-wrapper__image-box__js__label" do .image-wrapper__image-box__js__label__image.img_field{id: "img_field--#{i.index}", onClick: "$('#file').click()"} - if @item.images[i.index][:content].present? = image_tag(f.image.content) - else = image_tag 'icon_camera.png', class: "image-wrapper__image-box__js__label__image__url" = i.file_field :content, class: "image-wrapper__image-box__js__label__file js-file", id: "item_images_attributes_#{i.index}_content" .js-remove %span.js-remove__text 削除モデルへのmout_uploaderの記述
before
image.rbmount_uploaders :content, ImageUploaderafter
image.rbmount_uploader :content, ImageUploadermount_uploaderとするかmount_uploadersか。
error.messageNoMethodError (undefined method `map' for #<ActionDispatch::Http::UploadedFile......> #省略 Did you mean? tap): app/controllers/items_controller.rb:68:in `create'mount_uploadersにすると、デフォルトでmapメソッドが使われてしまう。
つまり、1つのfile_fieldに複数の画像データが入っている配列である必要があるのだ。
そういう時は、file_fieldにmultiple: trueを記載する必要がある。
multiple: true
multiple: true を記述すると、一つのfile_fieldに複数画像をアップロードしようとする。
修正前の記述
new.html.haml= form_with model: @item, local: true do |f| .wrapper.image-wrapper #image-box.image-wrapper__image-box = f.fields_for :images do |i| .image-wrapper__image-box__js.js-file_group{data:{index: "#{i.index}"}} = i.label :content, class: "image-wrapper__image-box__js__label" do .image-wrapper__image-box__js__label__image.img_field{id: "img_field--#{i.index}", onClick: "$('#file').click()"} - if @item.images[i.index][:content].present? = image_tag(f.image.content) - else = image_tag 'icon_camera.png', class: "image-wrapper__image-box__js__label__image__url" = i.file_field :content, multiple: true, class: "image-wrapper__image-box__js__label__file js-file", id: "item_images_attributes_#{i.index}_content", required: "required" .js-remove %span.js-remove__text 削除inputタグのtype[file]部分のHTML(検証)
multiple有り
<input multiple="multiple" class="image-wrapper__image-box__js__label__file js-file" id="item_images_attributes_0_content" type="file" name="item[images_attributes][0][content][]">multiple無し
<input class="image-wrapper__image-box__js__label__file js-file" id="item_images_attributes_0_content" type="file" name="item[images_attributes][0][content]">デフォルトで設定されるname属性が変わる
私の場合は、各file_fieldに一つずつ保存させるようなコードを書いていたのにもかかわらず、multipleの記述をしてしまっていて、エラーが起きた。
labelタグのfor属性
labelタグのfor属性は、連動させたい子要素のidの値を記述する必要がある。
修正前のlabel部分の記述
html.haml%label.image-wrapper__image-box__js__label .image-wrapper__image-box__js__label__image.img_field{id: "img_field--#{i.index}", onClick: "$('#file').click()"} - if @item.images[i.index][:content].present? = image_tag(f.image.content) - else = image_tag 'icon_camera.png', class: "image-wrapper__image-box__js__label__image__url" = i.file_field :content, multiple: true, class: "image-wrapper__image-box__js__label__file js-file", id: "item_images_attributes_#{i.index}_content", required: "required" .js-remove %span.js-remove__text 削除修正後
html.haml= i.label :content, class: "image-wrapper__image-box__js__label" do .image-wrapper__image-box__js__label__image.img_field{id: "img_field--#{i.index}", onClick: "$('#file').click()"} - if @item.images[i.index][:content].present? = image_tag(f.image.content) - else = image_tag 'icon_camera.png', class: "image-wrapper__image-box__js__label__image__url" = i.file_field :content, multiple: true, class: "image-wrapper__image-box__js__label__file js-file", id: "item_images_attributes_#{i.index}_content", required: "required" .js-remove %span.js-remove__text 削除labelタグの性質をよく理解せずに使っていた。
修正前の記述だと、検証でみてみるとわかるが、labelタグにfor属性が付与されておらず、inputタグのid属性(ここでは、item_images_attributes_0_content)に対応しておらず、不具合がおきた。後からわかったことだが、、hidden_fieldの記述を消してやれば、%labelのままでも支障はないことがわかった。
hidden_fieldの記述
修正前の記述
new.html.haml= form_with model: @item, local: true do |f| .wrapper.image-wrapper #image-box.image-wrapper__image-box = f.fields_for :images do |i| .image-wrapper__image-box__js.js-file_group{data:{index: "#{i.index}"}} = i.label :content, class: "image-wrapper__image-box__js__label" do .image-wrapper__image-box__js__label__image.img_field{id: "img_field--#{i.index}", onClick: "$('#file').click()"} - if @item.images[i.index][:content].present? = image_tag(f.image.content) - else = image_tag 'icon_camera.png', class: "image-wrapper__image-box__js__label__image__url" = i.file_field :content, multiple: true, class: "image-wrapper__image-box__js__label__file js-file", id: "item_images_attributes_#{i.index}_content", required: "required" = i.hidden_field :item_id, value: @item.id .js-remove %span.js-remove__text 削除imagesのitem_idをparamsに送るための記述をしていたが、idや外部キーはデフォルトで送られるようになっているため、必要なかった。逆に、これがあることによって、:contentが入っていない空のfile_fieldがhidden_fieldと共にparamsに送られてしまうため、validationに引っかかってしまう。
最後に
チーム開発で商品出品機能を担当したことにより、HTML&CSS, jQuery, Rubyについての知識がかなり深まった。欲張りな性格なので、いろんな記事のいいとこ取りをしようとした結果、こんなにもの何重もの罠を自分で仕掛けて自分でハマるということになってしまった。次からは是非とも一つ一つの用法や性質を理解した上で、実装していきたい。
でも、何かしらの初学者ってこういう風に泥臭く成長していくのかなぁとも思った。
諦めたら、そこで試合終了だよ。
- 投稿日:2020-03-21T15:58:16+09:00
Railsチュートリアルメモ - 第13章
サマリ
- マイクロソフトの表示、投稿、削除
- モデルの関連付け(
has_many
およびbelongs_to
)- モデルを使ったレコードの取得(取得条件、並び順、取得件数の指定)
- ラムダ式 (Stabby lambda) を使ったProcオブジェクトの生成
- Homeページの動的な出し分け
- CarrierWaveを使った画像ファイルのアップロード
- ImageMagick(+MiniMagick)を使った画像ファイルのリサイズ
- 本番環境でのfogを使ったS3への画像アップロード
ポイント
rails generate model
の際、references
を指定するとFKの指定を行ってくれるe.g.
rails generate model Micropost content:text user:references
を実行した場合class Micropost < ApplicationRecord belongs_to :user end
モデルの関連付けを行うと、1対Nの1側からN側のオブジェクトを生成することができ、N側のオブジェクトには1側のオブジェクトのidが設定される。
- e.g.
user.microposts.create
user.microposts.create!
=> !をつけると生成失敗時に例外を発生させるuser.microposts.build
build
メソッドはオブジェクトを返すがデータベースに反映はしないモデル内で
default_scope
を指定することで、並び順を指定することができるdefault_scope -> { order(created_at: :desc) }
- ->というラムダ式は、ブロックを引数に取り、Procオブジェクトを返す
- Procオブジェクトは、callメソッドが呼ばれたとき、ブロック内の処理を評価する
- モデルの関連付けをした1対多の1側に
dependent: :destroy
を付与しておくと、1側のオブジェクトが削除された際に、多側のオブジェクトも一緒に削除される- orderメソッド、takeメソッドを使って取得するレコードの並び順と件数を指定できる
User.order(:created_at).take(6)
- whereメソッドでレコードの取得条件を指定できる。?句を使うことで、変数をエスケープし、SQLインジェクションを防ぐことができる。
def feed Micropost.where("user_id = ?", id) end
- フォーム内でバリデーションエラーがあった場合、form_forのブロック変数のobject属性にエラーが入る
- errorパーシャルなどにrenderから変数を引き渡す場合、第二引数にハッシュを指定する e.g.
<%= form_for(@user) do |f| %> <%= render 'shared/error_messages', object: f.object %> <% end %><% if object.errors.any? %> <div id="error_explanation"> <ul> <% object.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %>renderには以下の使い方がある
- 引数ががアクション名(new, editなど) => アクションに対応したerbの描画
- 引数がパーシャル => パーシャルの描画(第二引数に与えた変数をパーシャル内で使用できる)
- 引数がインスタンス変数 => インスタンス変数に対応したパーシャルを探して描画
- e.g.
render @feed_items
で@feed_itemsの中身がmicropostであれば_micropostパーシャルを探して描画
- フォームが含まれる画面を描画する際は、form_for(@インスタンス変数)の@インスタンス変数をbuildして空のオブジェクトを用意してから描画する必要がある。
- フォームが送信されたら改めてparamsから取得した値を使用して@インスタンス変数をbuildしsaveする。
- erb内の
link_to
メソッドにdata: { confirm: "You sure?" }
を渡すとリンククリック時に確認のダイアログが表示される
redirect_to request.referrer
と記載すると、一つ前のページにリダイレクトさせられるCarrierWaveを使った画像ファイルの取り扱い手順
- Gemfileに
carrierwave
を追加し、bundle installrails generate uploader Xxx
でアップローダーを作成- モデルに
mount_uploader :picture, PictureUploader
を追加- ビューにimage_tagを追加
<%= image_tag micropost.picture.url if micropost.picture? %>
<span class="picture"> <%= f.file_field :picture %> </span>
- モデルに独自定義したバリデーションを追加する場合は、
validates
ではなくvalidate
を使用する感想
- 終盤のコンテンツだけあってなかなか内容が盛りだくさんだった。
- リスト13.50で空の配列(@feed_items = [])を追加している箇所は、
_feed.html.erb
の方を以下のように変えた方がわかりやすい気がした。<% if @feed_items && @feed_items.any? %>
ただ、これだと空の配列追加と同様、フィードの一覧が表示されないので、普通に
redirect_to root_url
でHomeにリダイレクトすればよいのではと思ってやってみたが、リダイレクトするとflashメッセージが表示されずエラーが発生したことがわからない。やはりrender 'static_pages/home'
は必要なよう。uploader導入後のローカルテストがredになり以下のERRORが表示された。
- NameError: uninitialized constant Micropost::PictureUploader app/models/micropost.rb:4:in
<class:Micropost>' app/models/micropost.rb:1:in
'サーバーを再起動しても解消せず原因が分からなかったが、一度VSCodeのすべてのターミナルを閉じてから再度開き直して実行したところgreenになった。
herokuにpushした際、以下のエラーが発生した。
remote: ! remote: ! Failed to install gems via Bundler. remote: ! (省略) To https://git.heroku.com/xxx.git ! [remote rejected] master -> master (pre-receive hook declined) error: failed to push some refs to 'https://git.heroku.com/xxx.git'
- herokuはpushされた際にbundle installも実行するようで、そこでこけるとpushがエラーになる模様(たしかにここまで一度もherokuでbundle installをしなかったが、勝手にやってくれていたらしい)
- bundle installがこけた原因は
heroku config:set
でAWSクレデンシャルを環境変数に設定していなかったことが原因のようで設定してからpushすると正常に動作した。
- 投稿日:2020-03-21T15:32:30+09:00
Leet文字列への置換問題
Leet文字列とは
Leetとはアルファベットを似た形の数字や記号などに置き換えて表記するネットスラングです
初めて解いた問題だったので、忘れないようにメモしておきます!問題
入力されたアルファベット大文字の文字列を、上記に該当するアルファベットの場合、数字に置換して出力せよ。解法
Leet文字列を置換するためには、
gsub
を使用します。
gsub
は、正規表現にマッチした全ての部分を置き換えてくれるメソッドです。まず、入力される文字列を変数(ここではstring)に定義します。
string = getsそして、複数のパターンにおいてgsubを使う今回の場合、
puts string.gsub(/A|E|G|I|O|S|Z/, "A" => "4", "E" => "3", "G" => "6", "I" => "1", "O" => "0", "S" => "5", "Z" => "2")これで解になります
e.g.)string = "HOGEFUGA" puts string.gsub(/A|E|G|I|O|S|Z/, "A" => "4", "E" => "3", "G" => "6", "I" => "1", "O" => "0", "S" => "5", "Z" => "2") => "H063FU64"
ちなみに、一つのワードだけ置換したい場合、
"hogehoge".gsub("hoge", "fuga") => "hugafuga"はじめにマッチしたワードのみ置換したい場合
sub
メソッドを使います。"fugafuga".sub("fuga", "hoge") => "hogefuga"
- 投稿日:2020-03-21T14:57:26+09:00
jwtで認証を実装する時のrspecテスト
はじめに
今参加させていただいているスタートアップでapi実装をしており、認証をfirebase authenticationに頼っているのですが、rspecでテストを行うときにjwtの認証をよしなにスキップする方法でめちゃめちゃハマったのでその備忘録です
元々のコード(説明のためかなり省略しています)
applicatioion_controller.rbclass ApplicationController < ActionController::Base before_action :authenticate! private def authenticate! if request.headers['Authorization'].present? jwt = request.headers['Authorization'] # jwtを渡すと検証を行いユーザーの情報を返してくれる独自モジュールを呼び出し @user_info = Firebase::JwtAuth.authenticate(jwt) else render json: { type: '401', message: 'not authorized' }, status: 401 end end enduser_controller.rbclass UsersController < ApplicationController # ユーザー一覧を持ってくる def index users = User.all render json: user status: :ok end endspec/requests/user_spec.rbdescribe UsersController, type: :request do let(:headers) { { CONTENT_TYPE: 'application/json', Authorization: 'hoge_token' } } describe 'GET /users' do it '全てのユーザーを取得する' do # header情報をくっつけてリクエストする get "/users", headers: headers # ステータスコード200が返ってくる、、、はずだった expect(response.status).to eq(200) end end end問題点
最初はこんな感じで実装してたのですが、、、これだと色々と問題があります
- jwtは有効期限が決められているため、実装した瞬間は通ることはあっても一定の時間が経つと通らなくなってしまう
- テストをするたびにfirebase側に不要なリクエストを送ってしまう
もっとあるとは思いますが、ざっとこんなところでしょうか?
対処法
これの対処法としては
テスト時にauthenticate!
メソッドが呼ばれた時はあらかじめ設定しておいた@user_info
を返すようなスタブを作成するというものです※スタブってなんぞ?って人は↓この辺を見てあとは自分で調べてくださいw
https://wa3.i-3-i.info/word14933.htmlってことなのでそのスタブを作っていきます
/support/authenticated_helper.rbmodule AuthenticationHelper def authenticate_stub # 渡したいインスタンス変数を定義 @user_info = [ { 'name' => 'kosuke', 'email' => 'kosuke@example.com', 'email_verified' => true, } ] # allow_any_instance_ofメソッドを使ってauthenticate!メソッドが呼ばれたら # ↑のインスタンス変数を返す allow_any_instance_of(ApplicationController).to receive(:authenticate!).and_return(@user_info) end endそして作ったスタブをテストコードから呼び出します
spec/requests/user_spec.rbdescribe UsersController, type: :request do let(:headers) { { CONTENT_TYPE: 'application/json', Authorization: 'hoge_token' } } describe 'GET /users' do it '全てのユーザーを取得する' do authenticate_stub # ←追記 # header情報をくっつけてリクエストする get "/users", headers: headers # ステータスコード200が返ってくる expect(response.status).to eq(200) end end endこうしてあげることで
authenticate!
メソッドが呼ばれた時に用意しておいたインスタンス変数が帰るので
無事テストを通すことができます以上!
- 投稿日:2020-03-21T14:49:43+09:00
[PostgreSQL]テーブルの項目の型の調べ方/確認の仕方
はじめに
PostgreSQLで実装中に「今のテーブルのそれぞれの項目の状態ってどうなってたっけ?」
となったときに、カラムの型の確認の仕方がまとまっていなかったので、まとめる環境
macOS Catalina
Ruby 2.5.1
Rails 5.0.7.2
PostgreSQL 12.2確認方法
1.
psql -l
で、確認したいテーブルが含まれるデータベースの名前を確認するPostgreSQLにあるデータベースが一覧表示されるので、確認したいテーブルが含まれるデータベース名をコピーしておく
ternminal$ psql -l #PostgreSQLのDBを一覧で表示する ##実行結果 (今回は「app-name_development」が対象) List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -------------------------+--------+----------+---------+-------+------------------- app-name_development | user | UTF8 | C | C | app-name_test | user | UTF8 | C | C | postgres | user | UTF8 | C | C | template0 | user | UTF8 | C | C | =c/user + | | | | | user=CTc/user template1 | user | UTF8 | C | C | =c/user + | | | | | user=CTc/user (5 rows)2.
psql -d データベース名
とコマンド入力コンソール状態のようになる
ternminal$ psql -d app-name_development #1.でコピーしたデータベース名 psql (12.2) Type "help" for help. app-name_development=#3.
\d テーブル名
とコマンド入力入力したテーブル名のカラム、インデックス、外部キーが一覧表示される
ternminal$ psql -d app-name_development psql (12.2) Type "help" for help. app-name_development=# \d users #確認したいテーブル名 Table "public.users" Column | Type | Collation | Nullable | Default ------------+-----------------------------+-----------+----------+---------------------------------- id | integer | | not null | nextval('woms_id_seq'::regclass) name | character varying | | not null | group_id | integer | | | created_at | timestamp without time zone | | not null | updated_at | timestamp without time zone | | not null | Indexes: "users_pkey" PRIMARY KEY, btree (id) "index_users_on_group_id" btree (group_id) Foreign-key constraints: "fk_rails_b5bbe7a612" FOREIGN KEY (group_id) REFERENCES groups(id) app-name_development=# \q #\qで終了追記(2020/03/21)
これ書いた後に気付いたが、普通に
db/schema.rb
を確認するだけでよかった気もする...
- 投稿日:2020-03-21T14:44:44+09:00
GoogleMapAPIでマーカーに数値を表示する方法
GoogleMapAPIでマーカーに数値を表示する方法
結論
google.maps.Markerのインスタンスを作成する際に、label: に値を入れてあげる。
その際には文字列でないと、デフォルトのマーカーが表示される。new google.maps.Marker({ position: { lat: 12.97, lng: 77.59 }, label: '1', map: map, });感想
ネットで探しても探し方の問題か、あまり良い記事がなかったので公式リファレンスをみたら一発だった。
今後は公式リファレンスを見る!(Google翻訳で問題なくみれるレベルでした)
https://developers.google.com/maps/documentation/javascript/examples/marker-labels?hl=ja#maps_marker_labels-css
- 投稿日:2020-03-21T14:39:06+09:00
フリマアプリの出品テストが上手く書けない人へ
初投稿です!
どうか優しい目で見てあげて下さい。お願いします!さてさて、今回はテストコードの初歩的な事について備忘録的に書き残していこうかと思います。
フリマアプリを開発上で、商品(product)の出品時の
「必須項目が全て入力してある際は登録できる」
といったテストコードを書こうと思います!
今回登録する中身はこちら↓
productsテーブル
カラム名 型 オプション name string null: false price integer null: false description(商品説明) string null: false status(商品の状態) string null: false size string null: false judgment integer days(発送までの日にち) string null: false cost(配送料負担者) string null: false prefecture_id integer null: false category_id integer null: false, foreign_key: true brand_id integer foreign_key: true user_id integer null: false, foreign_key: true テーブルから
name,
price,
description,
status,
size,
days,
cost,
prefecture_id,
category_id,
user_id
のカラムの値があれば登録できそう( ^ω^ )というわけで、今回はFactoryBotを用いて、下記の様にテストコードを書きました!!
spec/factories/product.rbFactoryBot.define do factory :product do #値は適当です name {"tomato"} price {111} description {"aaa"} status {"aaa"} size {"aaa"} days {"aaa"} cost {"aaa"} prefecture_id {1} category_id {1} user_id {1} end endspec/models/product_spec.rbrequire 'rails_helper' describe Product do describe '#create' do it "is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id" do product = FactoryBot.build(:product) expect(product).to be_valid end end endさてこれで、【bundle exec rspec】っと( ^ω^ )
結果
ターミナルProduct #create is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id (FAILED - 1) Failures: 1) Product#create is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id Failure/Error: expect(product).to be_valid expected #<Product id: nil, name: "abe", price: 111, description: "aaa", status: "aaa", size: "aaa", judgment: nil, days: "aaa", cost: "aaa", prefecture_id: 1, category_id: 1, brand_id: nil, user_id: 1, created_at: nil, updated_at: nil> to be valid, but got errors: Userを入力してください, Categoryを入力してください # ./spec/models/product_spec.rb:7:in `block (3 levels) in <top (required)>' Finished in 0.18668 seconds (files took 3.15 seconds to load) 1 example, 1 failure失敗( ´ ▽ ` )
エラー分を見てみると、
「UserとCategoryってどこのどいつ誰だよ!そんなのどこにもいねぇぞ!」
と怒られてます。それもそのはず…
user_idとcategory_idを外部キーで指定しているのにその先が居ないからね…。( ˊ̱˂˃ˋ̱ )そこで、
FactoryBotにUserとCategoryも追記します!!
まずここでUserとCategoryのテーブルを確認↓Usersテーブル
カラム名 型 オプション nickname string null: false string null: false encrypted_password string null: false user_image (プロフィール画像) string introduction (自己紹介) text family_name (姓) string null: false first_name (名) string null: false family_name_kana (セイ) string null: false first_name_kana (メイ) string null: false birth_day (生年月日) date null: false Categoriesテーブル
カラム名 型 オプション name string null: false ancestry string なので、FactoryBotに以下の様に追記!
spec/factories/product.rb# ----------追記部分ここから-------------- FactoryBot.define do factory :user do #値は適当です nickname {"sasa"} email {"kkk@gmail.com"} password {"00000000"} #登録の際に必要なので追記! encrypted_password{"00000000"} family_name {"sasaki"} first_name {"goro"} family_name_kana {"sasaki"} first_name_kana {"goro"} birth_day {"1990-08-24"} end factory :category do #値は適当です name {"aaa"} end # ----------追記部分ここまで-------------- factory :product do #値は適当です name {"tomato"} price {111} description {"aaa"} status {"aaa"} size {"aaa"} days {"aaa"} cost {"aaa"} prefecture_id {1} category_id {1} user_id {1} end endそしてuserとcategoryはこのテスト内で一旦保存されないと、
また「UserとCategoryってどこのどいつ誰だよ!そんなのどこにもいねぇぞ!」
と怒られてしまうので、
buildではなくcreateを使って行きます!!spec/models/product_spec.rbrequire 'rails_helper' describe Product do describe '#create' do it "is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id" do user = create(:user) category = create(:category) product = FactoryBot.build(:product) expect(product).to be_valid end end endこれでいける!!
【bundle exec rspec】っと( ^ω^ )結果
ターミナルProduct #create is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id (FAILED - 1) Failures: 1) Product#create is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id Failure/Error: expect(product).to be_valid expected #<Product id: nil, name: "abe", price: 111, description: "aaa", status: "aaa", size: "aaa", judgment: nil, days: "aaa", cost: "aaa", prefecture_id: 1, category_id: 1, brand_id: nil, user_id: 1, created_at: nil, updated_at: nil> to be valid, but got errors: Userを入力してください, Categoryを入力してください # ./spec/models/product_spec.rb:8:in `block (3 levels) in <top (required)>' Finished in 0.17322 seconds (files took 2.77 seconds to load) 1 example, 1 failure…えっ?_:(´ཀ`」 ∠):
同じエラーでとる…何故…??
もしかして、userもcategoryもcreateできてない?
と思い、【binding.pry】を【category = create(:category)】の直下に記入し、
確かめてみると、、、Product #create From: /Users/hoge/Desktop/GitHub/hogehoge/spec/models/product_spec.rb @ line 7 : 2: describe Product do 3: describe '#create' do 4: it "is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id" do 5: user = create(:user) 6: category = create(:category) => 7: binding.pry 8: product = build(:product) 9: expect(product).to be_valid 10: end 11: 12: # it "is invalid without a name" do [1] pry(#<RSpec::ExampleGroups::Product::Create>)> user => #<User id: 15, nickname: "sato", email: "kkk@gmail.com", user_image: nil, introduction: nil, family_name: "sato", first_name: "kenta", family_name_kana: "sato", first_name_kana: "kenta", birth_day: "1990-08-24", created_at: "2020-03-21 05:17:39", updated_at: "2020-03-21 05:17:39"> [2] pry(#<RSpec::ExampleGroups::Product::Create>)> category => #<Category:0x00007fe4caab5138 id: 7, name: "aaa", ancestry: nil, created_at: Sat, 21 Mar 2020 05:17:39 UTC +00:00, updated_at: Sat, 21 Mar 2020 05:17:39 UTC +00:00> [3] pry(#<RSpec::ExampleGroups::Product::Create>)>なんてことない、userとcategoryのidが違っていただけでした。( ´ ▽ ` )
そりゃ常にidが1な訳ないよね。。。と言うことでさらにテストコードを下記の様に修正!!
spec/models/product_spec.rbrequire 'rails_helper' describe Product do describe '#create' do it "is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id" do user = create(:user) category = create(:category) #修正点!! user_id: user[:id], category_id: category[:id]を追記、これでテスト時に保存されたuserとcategoryのidが呼び出され、上書きされる product = FactoryBot.build(:product, user_id: user[:id], category_id: category[:id]) expect(product).to be_valid end end endこれでどうかな?
( ^ω^ )つ【bundle exec rspec】結果
ターミナルProduct #create is valid with a name, price, description, status, size, days, cost, prefecture_id, category_id, user_id Finished in 0.07648 seconds (files took 2.63 seconds to load) 1 example, 0 failures無事テスト成功!!
やったぜ!✌︎('ω'✌︎ )( ✌︎'ω')✌︎
まとめ
テスト内容は単純でも、
アプリごとにテーブルなどの制約(NotNullや、外部キーなど)も異なるので、
そこに気をつけてテストコードを書いていかないと、
私の様に、テストコードの沼にハマる事になります。この記事が少しでも初学者の役に立ちます様に。
ここまで読んでくれて
ありがとう。
また次の記事でお会いしましょう!!♪( ´θ`)ノそれでは
- 投稿日:2020-03-21T12:30:43+09:00
[Rails]記事の「投稿フォーム」と「編集フォーム」をパーシャル化させた
前提
現在作成している記事投稿型のアプリで、記事の投稿フォームと編集フォームが全く同じ内容なのにパーシャル化していなかった。
悩み
submitボタンだけ、「投稿する」と「更新する」で表記を分けたかったため、
ほぼ同じ内容にも関わらず、下記のような2つのviewファイルを作成していました。※実際には、下記コードに色々とオプションをつけていますが、分かりやすくするため簡略化しています。
app/views/articles/new.html.erb<%= form_with model: @article, local: true do |f| %> <%= f.label :title, "タイトル" %> <%= f.text_area :title %> <%= f.label :content, "記事内容" %> <%= f.text_area :content %> <%= f.submit "投稿する" %> <% end %>app/views/articles/edit.html.erb<%= form_with model: @article, local: true do |f| %> <%= f.label :title, "タイトル" %> <%= f.text_area :title %> <%= f.label :content, "記事内容" %> <%= f.text_area :content %> <%= f.submit "更新する" %> <% end %>やったこと
①ja.ymlファイルの修正
submitボタンのvalue(投稿する/更新する)を、viewファイルに直接書くのではなく、
ja.ymlファイルで管理するようにしました。そもそも、Railsを日本語対応にしている必要がありますが、そのあたりは下記記事を参考にしました。
Railsで日本語化対応にする方法
[初学者]Railsのi18nによる日本語化対応ja.ymlを下記のように修正しました。
「article:」以下を追記しています。ymlはインデントを間違えるとうまく機能しないので注意!config/locales/ja.yml#〜省略〜 submit: create: 登録する submit: 保存する update: 更新する article: create: 投稿する update: 更新する #〜省略〜これで、
記事の投稿(create)の時には、submitボタンが「投稿する」
記事の編集(update)の時には、submitボタンが「更新する」
と表示されるようになりました。②viewファイルのパーシャル化
・パーシャルファイルを作成(f.submitのvalueを削除)
app/views/articles/_article_form.html.erb<%= form_with model: @article, local: true do |f| %> <%= f.label :title, "タイトル" %> <%= f.text_area :title %> <%= f.label :content, "記事内容" %> <%= f.text_area :content %> <%= f.submit %> <% end %>・「new.html.erb」と「edit.html.erb」をrender partialに書き換える。
app/views/articles/new.html.erb<%= render partial: 'article_form' %>app/views/articles/edit.html.erb<%= render partial: 'article_form' %>
以上です。
これでコードもスッキリしたし、
フォームの編集をしたい時に「_article_form.html.erb」だけを変更すれば、
投稿フォームと編集フォームのどちらにも変更が反映されるようになりました!初めての投稿で、至らぬ点もありますがご参考にしていただければ幸いです。
- 投稿日:2020-03-21T12:30:43+09:00
[Rails]記事の「投稿フォーム」と「編集フォーム」をパーシャル化する
前提
現在作成している記事投稿型のアプリで、記事の投稿フォームと編集フォームが全く同じ内容なのにパーシャル化していなかった。
悩み
submitボタンだけ、「投稿する」と「更新する」で表記を分けたかったため、
ほぼ同じ内容にも関わらず、下記のような2つのviewファイルを作成していました。※実際には、下記コードに色々とオプションをつけていますが、分かりやすくするため簡略化しています。
app/views/articles/new.html.erb<%= form_with model: @article, local: true do |f| %> <%= f.label :title, "タイトル" %> <%= f.text_area :title %> <%= f.label :content, "記事内容" %> <%= f.text_area :content %> <%= f.submit "投稿する" %> <% end %>app/views/articles/edit.html.erb<%= form_with model: @article, local: true do |f| %> <%= f.label :title, "タイトル" %> <%= f.text_area :title %> <%= f.label :content, "記事内容" %> <%= f.text_area :content %> <%= f.submit "更新する" %> <% end %>やったこと
①ja.ymlファイルの修正
submitボタンのvalue(投稿する/更新する)を、viewファイルに直接書くのではなく、
ja.ymlファイルで管理するようにしました。そもそも、Railsを日本語対応にしている必要がありますが、そのあたりは下記記事を参考にしました。
Railsで日本語化対応にする方法
[初学者]Railsのi18nによる日本語化対応ja.ymlを下記のように修正しました。
「article:」以下を追記しています。ymlはインデントを間違えるとうまく機能しないので注意!config/locales/ja.yml#〜省略〜 submit: create: 登録する submit: 保存する update: 更新する article: create: 投稿する update: 更新する #〜省略〜これで、
記事の投稿(create)の時には、submitボタンが「投稿する」
記事の編集(update)の時には、submitボタンが「更新する」
と表示されるようになりました。②viewファイルのパーシャル化
・パーシャルファイルを作成(f.submitのvalueを削除)
app/views/articles/_article_form.html.erb<%= form_with model: @article, local: true do |f| %> <%= f.label :title, "タイトル" %> <%= f.text_area :title %> <%= f.label :content, "記事内容" %> <%= f.text_area :content %> <%= f.submit %> <% end %>・「new.html.erb」と「edit.html.erb」をrender partialに書き換える。
app/views/articles/new.html.erb<%= render partial: 'article_form' %>app/views/articles/edit.html.erb<%= render partial: 'article_form' %>
以上です。
これでコードもスッキリしたし、
フォームの編集をしたい時に「_article_form.html.erb」だけを変更すれば、
投稿フォームと編集フォームのどちらにも変更が反映されるようになりました!初めての投稿で、至らぬ点もありますがご参考にしていただければ幸いです。
- 投稿日:2020-03-21T11:46:20+09:00
【ruby】クラスの定義方法(3つ)
備忘録用に書いていきます。
①
class Sample . . . end②
Sample = Class.new do . . . end↓
メリット…ブロックの外の変数が呼び出せるvar = 'hogehoge' class Sample # classブロックの内部からは、ブロックの外で定義されたvarは呼び出せない puts var end Sample = Class.new do # Class.newブロックの内部からは、varを呼び出すことができる puts var end③
self.class.const_set :'Sample', Class.new do . . . end↓
メリット…クラスを動的に定義できるclass Sample def self.create_new_class(class_name) # 引数の値に応じて、クラスを作成する self.class.const_set :"#{class_name}", Class.new end end
- 投稿日:2020-03-21T10:59:04+09:00
【解決方法】gem ffi のインストール(アップデート)に失敗する
問題
bundle update
を実行した際に、ffi のインストール(アップデート)に失敗した$ bundle update # ...(略) Fetching ffi 1.12.2 (was 1.10.0) Installing ffi 1.12.2 (was 1.10.0) with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. # ...(略) extconf failed, exit code 1 Gem files will remain installed in /Users/xxxxx/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/ffi-1.12.2 for inspection. Results logged to /Users/xxxxx/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/ffi-1.12.2/gem_make.out An error occurred while installing ffi (1.12.2), and Bundler cannot continue. Make sure that `gem install ffi -v '1.12.2' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: middleman was resolved to 4.3.6, which depends on middleman-core was resolved to 4.3.6, which depends on listen was resolved to 3.0.8, which depends on rb-inotify was resolved to 0.10.1, which depends on ffi試したこと
ffi をバージョン指定でインストール(アップデート)しようとしても失敗した
$ gem install ffi -v '1.12.2' Building native extensions. This could take a while... ERROR: Error installing ffi: ERROR: Failed to build gem native extension. # ...(略)解決方法
Xcode Command Line Tool をインストールした上で、ffi をインストール(アップデート)したら成功した
$ xcode-select --install xcode-select: note: install requested for command line developer tools$ gem install ffi -v '1.12.2' Building native extensions. This could take a while... Successfully installed ffi-1.12.2 Parsing documentation for ffi-1.12.2 Installing ri documentation for ffi-1.12.2 Done installing documentation for ffi after 41 seconds 1 gem installed
- 投稿日:2020-03-21T10:59:04+09:00
【解決方法】Macで gem ffi の インストール (アップデート) に 失敗する
問題
bundle update
を実行した際に、ffi のインストール(アップデート)に失敗した$ bundle update # ...(略) Fetching ffi 1.12.2 (was 1.10.0) Installing ffi 1.12.2 (was 1.10.0) with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. # ...(略) extconf failed, exit code 1 Gem files will remain installed in /Users/xxxxx/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/ffi-1.12.2 for inspection. Results logged to /Users/xxxxx/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/ffi-1.12.2/gem_make.out An error occurred while installing ffi (1.12.2), and Bundler cannot continue. Make sure that `gem install ffi -v '1.12.2' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: middleman was resolved to 4.3.6, which depends on middleman-core was resolved to 4.3.6, which depends on listen was resolved to 3.0.8, which depends on rb-inotify was resolved to 0.10.1, which depends on ffi試したこと
ffi をバージョン指定でインストール(アップデート)しようとしても失敗した
$ gem install ffi -v '1.12.2' Building native extensions. This could take a while... ERROR: Error installing ffi: ERROR: Failed to build gem native extension. # ...(略)解決方法
Xcode Command Line Tool をインストールした上で、ffi をインストール(アップデート)したら成功した
$ xcode-select --install xcode-select: note: install requested for command line developer tools$ gem install ffi -v '1.12.2' Building native extensions. This could take a while... Successfully installed ffi-1.12.2 Parsing documentation for ffi-1.12.2 Installing ri documentation for ffi-1.12.2 Done installing documentation for ffi after 41 seconds 1 gem installed
- 投稿日:2020-03-21T10:52:20+09:00
FizzBuzz問題のリファクタリング【Ruby】
修正ポイント
- if文のネストをなくす
- 条件が当てはまる確率が低い方から先に記述
- while分をeachメソッドに変更
- 変数の数を減らす
- コードを減らす
リファクタリング前
def fizzBuzz(count) i = 1 while i < count + 1 do if i % 3 == 0 then if i % 5 == 0 then puts 'FizzBuzz' else puts 'Fizz' end elsif i % 5 == 0 then puts 'Buzz' else puts i end i += 1 end end fizzBuzz(20)リファクタリング後
def fizzBuzz(count) (1..count).each do |c| if c % 15 == 0 puts 'FizzBuzz' elsif c % 5 == 0 puts 'Buzz' elsif c % 3 == 0 puts 'Fizz' else puts c end end end fizzBuzz(20)
- 投稿日:2020-03-21T08:32:38+09:00
サンプルアプリケーションを作ろう!!〜Railsチュートリアル3章〜
ほぼ性的なページの作成
あのーうち実家暮らしで家でUDEMYとかYOUTUBEとかでプログラミング動画みることあるんだけど、その時に「静的なページが作れます〜静的なページが〜」とか連呼されると若干気まずくなるからほんと辞めてほしいと思う今日この頃、、、NSぱんだまんです。アニメとか映画とかはそういうシーン来るのだいたい分かるからボリューム落としたりするんだけどまさかこんな真面目な動画でくると思わなかったからいちいち弁明するのもあれだし、すぐ自分の部屋に逃げました。
さて今回は第3章〜ほぼ静的なページの作成〜ですね。
まず静的、動的ってようわからんかったので調べました。
静的、、、何度アクセスしても同じものが表示されるWebページ
動的、、、アクセスした時の状況に応じて異なる内容が表示されるページ
ということですね。静的なページは企業紹介のサイトとか見るユーザーに同じものを見せたいときに使用される特に動きのないページ。動的ページはSNSサイトとか掲示板とかユーザー毎によって表示される内容が異なるページのことを指すんだって。まずセットアップします〜ここは何回もやってるから少しずつ慣れていってる気がする。立ち上げのスピードも上がってきてる感じします。
- 投稿日:2020-03-21T08:09:36+09:00
よくわかんないけどToyアプリを作ろう!!(Railsチュートリアル2章)
前回までのあらすじ
やりたくねーなと目を背けていたRailsチュートリアル。。真剣に取り組み始めました。。
なんとか環境構築、railsの導入、git.GitHubの導入に成功しました。
*ちなみにHerokuは一旦とばしました。とりあえず一周して余裕でたらやります。
今回から第2章やります。さあやります。
よーし頑張ってくぞー!!
内容としてはscaffoldっていうスクリプトを使ってTOYアプリっていうのを作っていくみたい。
うーん安定の意味わからんなー。。
とりあえずscaffold(スキャフォールド)っていうのは。。。railsアプリケーションの開発をする際にはMVCを作っていき、更に必要なルーティングを作成していく必要がある。これらの作業をまとめて行って、簡単にアプリケーションの雛形を作ってくれる機能のこと。scaffoldを使用することで素早くrailsアプリケーションを作ることができる。
なるほどねー。とりあえず内容を深くっていうよりはrailsのアプリケーションを素早く作って慣れましょう、みたいな章なのかな?
アプリケーションの計画
はじめにどんなアプリにするか計画を建てると。
まずrailsインストール$ cd ~/environment $ rails _5.1.6_ new toy_app $ cd toy_app/んでbundleで扱うgemfileをテキストエディタで編集。
$ bundle install --without production bundleインストールします。んでgit githubの登録。ここら辺は前回の内容と同じですね。
*Herokuはとばします。ユーザーのモデル設計
ここでユーザーのデータモデルの説明が入ります。
各ユーザーには重複のない一意のキーとなるinteger型のID番号(idと呼ぶ)を割り当て、このIDに加えて一般公開されるstring型の名前(name)そして同じくstring型のメールアドレス(email)をもたせる。メールアドレスはユーザーとしても使われる。と。
ここら辺はprogateでもなんとなくやったな。要するにユーザーというモデルにどんな概念にするのか。ここでの情報はDBのテーブルというところに保存されて必要があれば取り出すことができるんだよね。
んで、id name emailは属性っていってテーブルの中の縦の列のなるんだよね。マイクロソフトのモデル設定
マイクロソフトはidとマイクロポストのテキスト内を格納するtext型のcontentだけで構成されている。それとマイクロポストをユーザーと関連付ける必要があるためuser_idも必要となる。
ここで気になったんだけどデータ型っていっぱいあるじゃん?
これまとめてみた。string 文字列型(1~255文字) text テキスト(不定長文字列)型(1~4294967296文字) integer 整数型(整数:4バイト) bigint(整数:8バイト) float 浮動小数点数型(浮動小数) decimal 固定長整数型(精度の高い小数) datetime 日時型(日時) time 時刻型(時間) date 日付型(日付) binary バイナリ文字列型(バイナリーデータ) boolean 真偽値型(Boolean型)とまあこんな感じ。多いね。笑 若干よくわかんないのもあるし、これが全部ってわけじゃないけど主にrailsだとここらへんが使われてるらしい。文字を扱う場合stringとtextが対応しているけどstringはtextに比べると扱える文字数が少し短め、名前とかemailとかの文字情報はstringで扱って、本文や備考などの文章はtextつ合うのが一般的みたいだよ。
Userリソース
ここではさっきのユーザー用のデータモデルを、そのモデルを表示するためのWebインターフェイスに従って実装します。
このデータモデルとWebインターフェイスは、組み合わさってUsersリソースとなり、ユーザーというものを、HTTPプロトコル経由で自由に作成/取得/更新/削除できるオブジェクトとみなすことができるようになります。「はじめに」で約束したとおり、このUsersリソースはすべてのRailsプロジェクトに標準装備されているscaffoldジェネレータで生成します。scaffoldで生成された膨大なコードを今詳細に読む必要はありません。今の段階ではおそらく混乱するだけでしょう。
(〜Railsチュートリアルより〜)これそのままrailsチュートリアルの文章コピペしたんだけどさ。
もうこの文章が混乱するわ笑
わからない単語が多すぎる、、一回一回ポケモン図鑑開くマサラタウンの某少年のような気分だよ。一個一個分解していこう。データモデルはさっきの情報がつまってる一つの塊だよね。
webインターフェースはWebページおよびWebブラウザを用いてソフトウェアの表示、操作を行うもののこと(IT用語辞典参照)つまり処理の方法、手段のことかな。
これが組み合わさってUserリソース(動作の実行に必要な処理システムの要素)が出来上がる。これをhttpプロトコル(インターネット上で、Webサーバーとユーザーが、相互に通信するための仕組み)経由でいろいろな編集ができるオブジェクトとみなすことができる。オブジェクトっていうのはデータと、それに対する処理(メソッド)をひとまとめにしたもののこと。
これをすべてscaffoldジェネレータで全部生成しちまおうってことなんだね。
いわゆるチート武器ってやつだ。無限ロケランみたなもんだね。
Railsのscaffoldはrails generateスクリプトにscaffoldコマンドを渡すことで生成される。scaffoldコマンドの引数には、リソース名を単数形にしたもの(この場合はUser)を使い、必要に応じてデータモデルの属性をオプションとしてパラメータに追加できる。(下のやつだとまず引数にUserを入れて、中にデータ型がStringのname emailのパラメーターも入れて作ってくださいねー!)って意味になる。$ rails generate scaffold User name:string email:stringあとこれにプラスしてDBをmigrateしなくちゃいけない。
$ rails db:migrate$ rails server画面見えるようになります。
本日のエラー発生
翌日CLOUD9を起動したらサーバーがつながらないってかプレビュー見れない。
oops!!みたな青白の画面出る。
原因、、、cloud9を落としたことでダウンした?
解決策、、、 $ cd 指定したいapp
からの〜 $ rails update
最後にー $ rails server
でできた!!updateとrails serverするときはcdにて指定したディレクトリになっているか確認しよう。memo
HTTPリクエスト URL アクション 用途
GET /users index すべてのユーザーを一覧するページ
GET /users/1 show id=1のユーザーを表示するページ
GET /users/new new 新規ユーザーを作成するページ
POST /users create ユーザーを作成するアクション
GET /users/1/edit edit id=1のユーザーを編集するページ
PATCH /users/1 update id=1のユーザーを更新するアクション
DELETE /users/1 destroy id=1のユーザーを削除するアクションあとは同じようにmicropostっていうデータベースをマイグレーションしてUSERとMICROPOSTのデータベースの情報をくっつけるみたいな感じの流れで2章は終了しました。
Progateやってたからここらへんは割とすんなり理解できました。
次回は3章目に進んでいきたいと思います。では今日はここまで