- 投稿日:2020-04-02T23:36:11+09:00
【Rails】hoge.herokuapp.comへのアクセスをリダイレクトさせる
環境設定
Rails 6.0.0
ruby 2.6.5リダイレクトさせるために必要なコードとは?
お名前.comでせっかく独自ドメインを買ったのに、
hogehoge.heroku.comでアクセスできてしまう。。。これを解消するのがリダイレクト処理。
gemで、rack-rewriteというのもあるようですが、
コードを足すだけでも実現可能とのことでgemは使わず実装してみました。application_controller.rbclass ApplicationController < ActionController::Base #herokuapp.comから独自ドメインへリダイレクト before_action :ensure_domain FQDN = 'www.hogehoge.net' # redirect correct server from herokuapp domain for SEO def ensure_domain return unless /\.herokuapp.com/ =~ request.host # 主にlocalテスト用の対策80と443以外でアクセスされた場合ポート番号をURLに含める port = ":#{request.port}" unless [80, 443].include?(request.port) redirect_to "#{request.protocol}#{FQDN}#{port}#{request.path}", status: :moved_permanently end end参考記事では
before_filter
となっていましたが、Rails4以降は使えなくなっているので、before_action
で書きます。
FQDN
は取得した独自ドメインを定義してあげます。他はコピペでも大丈夫です(僕はこれでうまくリダイレクトしてくれています)
参考記事
【Rails】herokuapp.comから独自ドメインに301リダイレクトを行う方法
今回はこれで以上です。
- 投稿日:2020-04-02T23:11:43+09:00
railsでffiをインストールできない
環境
Mac
Ruby 2.6.0
Rails 6.0.0エラー
Fetching ffi 1.12.2 Installing ffi 1.12.2 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension.解決策
以下をターミナル上で実行
> brew install libffi > export LDFLAGS="-L/usr/local/opt/libffi/lib" > export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"
- 投稿日:2020-04-02T21:20:03+09:00
Rails 自作アプリへの道 Part2
Rails 自作アプリを作った時の経過をまとめていきます。
環境
OS Ruby Rails Mac Mojave 10.14.16 2.6.3p62 5.0.7.2 参考
https://qiita.com/cigalecigales/items/f4274088f20832252374前提
環境構築済【conformableの設定】
1.送信メールアドレスの登録
①設定ファイルの追記/編集
config/environments/depelopment.rbconfig.action_mailer.raise_delivery_errors = true config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { :address => "smtp.gmail.com", :port => 587, :user_name => "Gメールアドレス", # メアドを書く :password => "Gメールパスワード", :authentication => :plain, :enable_starttls_auto => true }config/initialiezers/devise.rbconfig.mailer_sender = 'Gメールアドレス' # メアドを書く②gmailアプリパスワードの取得、追記
config/environments/development.rb(省略) :password => "Gメールパスワード", # Gmailのアプリパスワードを書く (省略)③サインアップ、ログインの検証
サーバーを起動し、サインアップ。
確認メールをMacで開き、『Confirm my accout』をクリック
その後、ログイン可能か確認する【lockableの設定】
1.設定値の登録
①設定ファイルの編集 ※ 必要に応じて、設定値やコメントの有無を変更
config/initializers/devise.rb(省略) config.lock_strategy = :failed_attempts config.unlock_keys = [:email] config.unlock_strategy = :both config.maximum_attempts = 20 config.unlock_in = 1.hour config.last_attempt_warning = true (省略)【timetableの設定】
1.設定値の登録
①設定ファイルの編集 ※ 必要に応じて、設定値やコメントの有無を変更
config/initializers/devise.rb(省略) # config.timeout_in = 30.minutes (省略)【その他の設定】
1.サインアップ画面で入力させたい項目の追加
①設定ファイルの編集 ※ 必要に応じて、入力させたい項目を追加
app/views/devise/registrations/new.html.erb<h2>サインアップ</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <!-- 省略 --> <div class="field"> <%= f.label :sellername, '取扱者' %><br /> <%= f.text_field :sellername, autofocus: true, autocomplete: "sellername" %> </div> <!-- 省略 --> <% end %> <%= render "devise/shared/links" %>2.変更できるようにしたい項目の追加
①設定ファイルの編集 ※ 必要に応じて、入力させたい項目を追加
app/views/devise/registrations/edit.html.erb<h2>取扱者情報編集</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <!-- 省略 --> <div class="field"> <div class="field"> <%= f.label :sellername, '取扱者' %><br /> <%= f.text_field :sellername, autofocus: true, autocomplete: "sellername" %> </div> <!-- 省略 --> <% end %> <%= render "devise/shared/links" %>3.ストロングパラメータの設定
①データベースに登録したい項目をストロングパラメータで指定する
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:sellername]) devise_parameter_sanitizer.permit(:account_update, keys: [:sellername]) end end
- 投稿日:2020-04-02T21:17:17+09:00
gem ancestry + seedファイルを利用した、データベースへの複数カラム挿入
本記事について
Ruby on Railsのseedファイルを使って、ancestryのデータを挿入するとき、カラムを複数同時に挿入したいと思い、その実装ができたので解説させていただきます。
(とあるプログラミングスクールのカリキュラムによって、某フリマアプリのカテゴリーに関する記事がたくさんありますが、そちらはカラムが1つしかなかったため投稿しようと考えました。)目的
- seedファイルを使ってデータベースを作成すること
- データベース作成時に複数のカラムを同時に生成すること
参考資料
Qiita参考記事
・【Rails】ancestryで簡単に多階層型データの作成し呼び出す
・railsのseedの書き方いろいろ
・Rails・seedファイルを分割して管理する事前準備
ancestryの基本的な導入方法はたくさん記事があるので、割愛させていただきます。
gemのインストール、モデルの定義、テーブルの作成まで終わったものとします。実践
今回はfood(食材)のテーブルを作成し、seedファイルで複数のカラムを同時に挿入してみます。
完成後のテーブルはこのような感じです。
ancestryのgemを使っているので、「ancestry」のカラムはこのように自動的に入ります。
今回実践するカラムの同時挿入は、「name」と「description(説明)」です。
ではいきましょう。seedファイルにデータの書き込み
テーブルに登録するデータを書き込み、データを作成するようにcreateメソッドで定義してあげます。
今回はこのようになります。db/seeds.rbparent_array = [ {name: "野菜", description: "健康を保つための栄養が取れる食材"}, {name: "果物", description: "食を彩る栄養価も高い食材"} ] vegetable_child_array = [ {name: "根菜類", description: "根っこの部分を食べる野菜"}, {name: "葉菜類", description: "葉っぱの部分を食べる野菜"} ] vegetable_grandchild_array = [ [ # 野菜 >> 根菜類 {name: "大根", description: "火を通すと甘味が増す野菜"}, {name: "にんじん", description: "鮮やかな橙色の野菜"} ],[ # 野菜 >> 葉菜類 {name: "ほうれん草", description: "鉄分が豊富な野菜"}, {name: "レタス", description: "シャキシャキとした食感が特徴の野菜"} ] ] parent = Food.create(parent_array[0]) vegetable_child_array.each_with_index do |child,i| child = parent.children.create(name: child[:name], description: child[:description]) vegetable_grandchild_array[i].each do |grandchild| child.children.create(name: grandchild[:name], description: grandchild[:description]) end end fruit_child_array = [ {name: "仁果類", description: "花の先端部分が膨らんで果実になる果物"}, {name: "柑橘類", description: "ビタミンCやクエン酸を多く含む果物"} ] fruit_grandchild_array = [ [ # 果物 >> 仁果類 {name: "りんご", description: "甘い蜜を含んだ果実"}, {name: "なし", description: "水分を多く含んだ甘い果物"} ],[ # 果物 >> 柑橘類 {name: "みかん", description: "橙色の甘い果物"}, {name: "レモン", description: "酸味が特徴的な果物"} ] ] parent = Food.create(parent_array[1]) fruit_child_array.each_with_index do |child,i| child = parent.children.create(name: child[:name], description: child[:description]) fruit_grandchild_array[i].each do |grandchild| child.children.create(name: grandchild[:name], description: grandchild[:description]) end end少し長いですが、このようになります。
記述の方法はいろいろあるので、一例と思って見てください。ここで大事なのが、createする時に、
~ xx.create(name: child[:name], description: child[:description])と記述することで、カラムを指定して登録できます。実は結構簡単でした。
データの挿入
続いて、データを挿入していきます。
ターミナルで、以下のコマンドを実行します。$ rails db:seedこれで、エラーメッセージが出なければ、データが挿入されているのができるはずです。
データの読み込みが成功したときは、何もメッセージが出ないはずです。注意点
seedファイルを読み込むときは、テーブルに作成済みのレコードがないか確認してから行いましょう。
重複するデータがあるとエラーで弾かれてしまいます。最後に
seedファイルの読み込みは、慣れるまで結構大変に感じました。
エラーの原因がわかりにくいので、根気よくがんばってください!
- 投稿日:2020-04-02T20:47:19+09:00
【Docker】コンテナ内のデータベース閲覧(ローカル,EC2)
はじめに
ローカル環境/本番環境(EC2)の其々でコンテナを起動させた際のデータベース閲覧方法と
環境による閲覧方法の違いがあるのか気になったので、調べてみました。環境
- Rails:5.0.7
- MySQL:5.6
- Docker:19.03.8
- EC2(AMI):Amazon Linux AMI
ソースコード
DockerfileFROM ruby:2.5.1 RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && apt-get update && apt-get install -y nodejs --no-install-recommends && rm -rf /var/lib/apt/lists/* RUN mkdir /app WORKDIR /app COPY Gemfile /app/Gemfile COPY Gemfile.lock /app/Gemfile.lock RUN gem install bundler RUN bundle install COPY . /app RUN mkdir -p tmp/socketsdocker-compose.ymlversion: '2' services: db: image: mysql:5.6 environment: MYSQL_ROOT_USER: root MYSQL_ROOT_PASSWORD: password command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci volumes: - mysql-data:/var/lib/mysql - ./mysql/init:/docker-entrypoint-initdb.d ports: - "3306:3306" app: build: context: . command: bundle exec puma -C config/puma.rb volumes: - .:/app - public-data:/app/public - tmp-data:/app/tmp - log-data:/app/log depends_on: - db depends_on: - web web: build: context: containers/nginx volumes: - public-data:/app/public - tmp-data:/app/tmp ports: - 80:80データベース接続
ローカル、EC2共通#起動中のコンテナ名確認 docker-compose ps #DBコンテナに入る docker exec -it DBコンテナNAME bash #mysqlへ接続(パスワードはdocker-compose.ymlに記載したもの) mysql -u root -p Enter password:EC2#DBコンテナのPORT確認 docker ps #確認結果(例) 0.0.0.0:3306->3306/tcp #mysqlへ接続(パスワードはdocker-compose.ymlに記載したもの) mysql -h 0.0.0.0 -P 3306 -u root -p Enter password:データベースの中身閲覧
ターミナル#データベース接続 mysql -u root -p #どんなデータベースがあるか show databases; #使用したいデータベースに切り替え use データベ-ス名; #テーブル一覧 show tables; #テーブルの構造確認 describe テーブル名複数系; #テーブルの中身確認 select * from テーブル名複数系;おわりに
今回ローカルとEC2でそれぞれ起動したコンテナにどのような違いがあるのか、データベースの観点から調べてみました。間違ってる点があれば指摘していただけると幸いです。
同じポート3306で起動しているはずが、ローカルではmysql -h 0.0.0.0 -P 3306 -u root -pのコマンドが効かなかったので引き続き調査します。。参考URL
https://qiita.com/hayabusa3703/items/9893a53c21ddc3c2403a
https://qiita.com/hot_study_man/items/4e129dacb7c3cab4b568
- 投稿日:2020-04-02T19:44:28+09:00
rails whereとfind、find_byの違い
こんにちわ。
未経験から独学でwebベンチャーに入社して3ヶ月のバスケンです。ActiveRecord の where句でオブジェクトを出力した後の挙動がおかしい、、
ruby on railsにて
オブジェクト選択でfindではなくwhereを使う必要があったため
whereを利用して出力したオブジェクトでインスタンス変数を作成したら、
オブジェクトの値が今までどうり取り出せなくなりました。。何故(Why??)
find と where の違い
find:オブジェクトを返す
where:ActiveRecord_Relationを返す※ActiveRecord_Relationに関してはまとめたものを後日投稿します?
対処
オブジェクトが単数の場合は、最後に「.first」を記述すると
findで出力した時と同じように扱うことができます。(例)
object = Object.where(id: 1).first
- 投稿日:2020-04-02T19:33:20+09:00
マイクロサービスとモノレポ
コロナの影響で在宅勤務(テレワーク)も一ヶ月以上も続き環境の変化に慣れてきましたが、
BBCパパ
のように急な家族の割り込みによる対応をどうかわすかを考えている streampack の Tana です。マイクロサービスとモノレポ(Monorepo)の取り組みについて
streampack
は動画配信プラットフォームをお客様の要望にカスタマイズしながら、AWS
などのクラウド上に提供しているサービスです。既存のシステムを最大限に活かしつつ、効率的に適用するためのマイクロサービスとモノレポについての経験談のお話になります。以前は案件やレイヤー毎にリポジトリを切って開発してました。いわゆる
Polyrepo(Multi-Repo)
と呼ばれる方法です。例えば、
- project1_frontend
- project1_cms
- project2_api
- project3_dev
などなど。当時はまだ案件が少なかったり、固有な機能やシステムがあり、案件の影響を避けるという理由もあり、別のリポジトリで管理した方がいいだろうと、当時は判断してました。
管理・保守の問題が発生・・・
しかし、案件が増えるたびにリポジトリの管理が複雑になり、セキュリティアップデート、機能廃止、バグの修正が入る場合、全てのリポジトリで下記の作業が必要した。
Project-1
レポジトリのチェックアウト、アプリ起動、修正、テスト、レビュー、デプロイProject-2
レポジトリのチェックアウト、アプリ起動、修正、テスト、レビュー、デプロイProject-3
レポジトリのチェックアウト、アプリ起動、修正、テスト、レビュー、デプロイ単純作業かもしれませんが、上記の作業やタスクの切り替えはどうしても時間がかかります。
なぜモノレポの採用に至ったのか?
そこで、調査していく上で、影響を受けたのが、なぜ Google は全てのコードをシングルレポジトリを管理しているのかのYouTubeになります。Facebook, Twitter などの大規模システムでも採用されている手法です。
この手法で重要なのが、
Trunk-based Development
であり、常に Trunk に開発されたコードがマージされるということになります。そうすれば、常に最新なコードで動作確認できます。リリースはリリースブランチがあり、リリースしたいコードのみをCherry Pick
して、リリースブランチに反映してリリースを行います。特別な機能やベータ段階のものは、フィーチャーフラグで制御します。
必要に応じて ON/OFF にすることにより、コードを修正することなく制御できます。また、シングルリポジトリなので、コード、ライブラリの共有ができるのもメリットの一つになります。streampackとしても今後の保守・運用を考慮すると、
Rails
、Golang
、NEXT.js(NodeJS)
などのアプリケーション毎のバージョン・セキュリティアップデートがあることを想定すると、それぞれの一つのモノレポで運用した方がいいと判断し進めることにしました。また、再利用することで開発の効率や無駄な開発を減らすのも目的の一つです。
調査とコード移植
まずは、現状調査ですが、案件ごとに特別な機能やシステムを洗い出しをしました。その特別な機能の移植を
モノレポ
に反映し、フィーチャーフラグとして提供するようにしました。また、設定情報やサービスの固有な情報は環境変数で管理し、ローカル開発の際は、.env
の参照、また本番環境では、ECS(タスク定義)上で汎用的に管理できるようにしてます。例え、ホスト名、AWS環境、API情報が変わったとしても簡単に変更できます。Docker上で開発する上では重要な方法です。Config - The TWELVE-FACTOR APP
DBマイグレーション
モノレポによる移行を考慮する際に重要だったのが、
Backwards Compatibility
です。移行前と移行後でも同様に正常にダウンタイムなく動く必要がありました。ある案件ではある機能不要だからといって、テーブルやカラムを削除したりすると、DBマイグレーション時に移行前の状態だと動かなくなるので、基本は削除しないようにしております。将来的に不要と判断したタイミングで精査して削除するという流れです。また、一部データ移行・更新が必要だったものに関しては、DBマイグレーションで実行のタイミングで、タスク(Script)により、制御し手動対応させず自動化させてます。マイクロサービス
ライブ配信制御機能やライブチャットなど一部のサービスや機能に応じてマイクロサービスとして管理されております。シングルなモノレポなので、ディレクトリを変え環境変数を変えることで、開発環境を立ち上げたり、異なる環境にデプロイし再現したり再利用することができるようにしてます。一部のお客様の要望により、固有な機能なものを幅広く使えるように共通仕様に持っていき再利用できるように心がけてはいますが、共有ライブラリ化できていないのもあるので、今後の課題です。
ビルド&デプロイ
マイクロサービスでのアプリケーションごとに、インストール方法や実行コマンドが違って混乱することがあります。どんな人でも同じコマンドで動かせることで、ハードルを下げ、さらにドキュメント(README.md) などもシンプルになります。以前こちらのブログでも紹介させていただきましたが、make コマンドを使ってアプリケーションの立ち上げ、ビルド、デプロイまでできるようにしてます。
アプリを立ち上げたい場合:
$ make run
ビルドしリリースしたい場合:
$ make release
というイメージです。Code Deploy, Circle CIなどのCI/CDを導入するのも可能ですが、開発・リリース頻度の兼ね合いや
社内用のgit
ではCI/CD
に対応していないため見送り状態です。またBazel
などのビルドツールだと並列処理などメリットはありそうですが要検討が必要そうです。新規・追加開発でのメリット
モノレポ対応できたことで、マイクロサービス間の修正が一貫性の変更がコードレビューで確認できます。それぞれのレポジトリの切り替えが必要なく、コードレビューをそれぞれ出す必要もありません。一つのリポジトリさえクローンして修正すればいいのです。マイクロサービス化では重要な手法かと思っております。
- 投稿日:2020-04-02T19:33:20+09:00
モノレポとマイクロサービス
コロナの影響で在宅勤務(テレワーク)も一ヶ月以上も続き環境の変化に慣れてきましたが、
BBCパパ
のように急な家族の割り込みによる対応で頭を悩まされている streampack の Tana です。モノレポ(Monorepo)とマイクロサービスへの取り組みについて
streampack
は動画配信プラットフォームをお客様の要望にカスタマイズしながら、AWS
などのクラウド上に提供しているサービスです。既存のシステムとマイクロサービスを最大限に活かすために、案件ごとに管理していた複数のレポジトリ管理からモノレポ
へ移管したかについての経験談のお話になります。以前は案件やレイヤー毎にリポジトリを切って開発してました。いわゆる
Polyrepo(Multi-Repo)
と呼ばれる方法です。例えば、
- project1_frontend
- project1_cms
- project2_api
- project3_dev
などなど。当時はまだ管理している案件が少なくまた固有な機能やシステムがあり、
別のリポジトリで管理した方がいいだろうと、当時は短期的な目線で判断してました。がしかし・・・
管理・保守の問題が発生
案件が増えるたびにリポジトリの管理が複雑になり、セキュリティアップデート、機能廃止、バグの修正によって、全てのリポジトリで下記の作業が必要した。
Project-1
レポジトリのチェックアウト、アプリ起動、コード修正、テスト、レビュー、デプロイProject-2
レポジトリのチェックアウト、アプリ起動、コード修正、テスト、レビュー、デプロイProject-3
レポジトリのチェックアウト、アプリ起動、コード修正、テスト、レビュー、デプロイ単純作業のかもしれませんが、数が多いとどうしても時間がかかり非効率です。
また案件によっては、開発環境がないものがあったりなど、それをどう考慮するか、本番直反映でいけるかなど考慮すべき点が多々ありました。なぜモノレポの採用に至ったのか?
そこで、調査していく上で、影響を受けたのが、なぜ Google は全てのコードをシングルレポジトリを管理しているのかのYouTubeになります。Facebook, Twitter などの大規模システムでも採用されている手法です。
この手法で重要なのが、
Trunk-based Development
であり、常に Trunk に開発されたコードがマージされるということになります。そうすれば、常に最新なコードで動作確認できます。リリースはリリースブランチがあり、リリースしたいコードのみをCherry Pick
して、リリースブランチに反映してリリースを行います。特別な機能やベータ段階のものは、フィーチャーフラグで制御します。
必要に応じて ON/OFF にすることにより、コードを修正することなく制御できます。また、シングルリポジトリなので、コード、ライブラリの共有ができるのもメリットの一つになります。streampackとしても今後の保守・運用を考慮すると、
Rails
、Golang
、NEXT.js(NodeJS)
などのアプリケーション毎のバージョン・セキュリティアップデートがあることを想定すると、それぞれの一つのモノレポで運用した方がいいと判断し進めることにしました。また、再利用することで開発の効率や無駄な開発を減らすのも目的の一つです。
調査とコード移植
まずは、現状調査ですが、案件ごとに特別な機能やシステムを洗い出しをしました。その特別な機能の移植を
モノレポ
に反映し、フィーチャーフラグとして提供するようにしました。また、設定情報やサービスの固有な情報は環境変数で管理し、ローカル開発の際は、.env
の参照、また本番環境では、ECS(タスク定義)
上で汎用的に管理できるようにしてます。例え、ホスト名、AWS環境、API情報が変わったとしても簡単に変更できます。Docker上で開発する上では12factorの概念は重要です。Config - The TWELVE-FACTOR APP
DBマイグレーション
モノレポによる移行を考慮する際に重要だったのが、
Backwards Compatibility
です。移行前と移行後でも同様に正常にダウンタイムなく動く必要がありました。ある案件ではある機能不要だからといって、テーブルやカラムを削除したりすると、DBマイグレーション時に移行前の状態だと動かなくなるので、基本は削除しないようにしております。将来的に不要と判断したタイミングで精査して削除するという流れです。また、一部データ移行・更新が必要だったものに関しては、DBマイグレーションで実行のタイミングで、タスク(Script)により、制御し手動対応させず自動化させてます。マイクロサービス
ライブ配信制御機能やライブチャットなど一部のサービスや機能に応じてマイクロサービスとして管理されております。シングルなモノレポなので、ディレクトリを変え環境変数を変えることで、開発環境を立ち上げたり、異なる環境にデプロイし再現したり再利用することができるようにしてます。一部のお客様の要望により、固有な機能なものを幅広く使えるように共通仕様に持っていき再利用できるように心がけてはいますが、共有できない、固有な仕様になっているのが現状で、改善の余地があります。
ビルド&デプロイ
マイクロサービスでのアプリケーションごとに、インストール方法や実行コマンドが違って混乱することがあります。どんな人でも同じコマンドで動かせることで、ハードルを下げ、さらにドキュメント(README.md) などもシンプルになります。以前こちらのブログでも紹介させていただきましたが、make コマンドを使ってアプリケーションの立ち上げ、ビルド、デプロイまでできるようにしてます。
アプリを立ち上げたい場合:
$ make run
ビルドしリリースしたい場合:
$ make release
というイメージです。Code Deploy, Circle CIなどのCI/CDを導入するのも可能ですが、開発・リリース頻度の兼ね合いや
社内用のgit
ではCI/CD
に対応していないため見送り状態です。またBazel
などのビルドツールだと並列処理などメリットはありそうですが要検討が必要そうです。新規・追加開発でのメリット
モノレポ対応できたことで、マイクロサービス間の修正が一貫性の変更がコードレビューで確認できます。それぞれのレポジトリの切り替えが必要なく、コードレビューをそれぞれ出す必要はなくなりました。一つのリポジトリさえクローンして修正すればいいのです。マイクロサービス化では重要な手法かと思っております。
- 投稿日:2020-04-02T18:27:43+09:00
オブジェクト指向とは
オブジェクト指向とはなにか
複数のオブジェクトを組み合わせてプログラムを構築する考え方です。
人をオブジェクトとして考えてみると、人には「名前」、「生年月日」、「年齢」、「住所」などのデータがあります。
オブジェクトはこれらのデータ(状態)の他に振る舞いも持ち、オブジェクトに対して「名前を教えて」と伝えたときにオブジェクト自身が保持している名前を返す動作を指します。
たとえば「鈴木さん」と「佐藤さん」がいるとします。この場合、二人は別々の異なるオブジェクトです。
鈴木さんは「名前が鈴木である」という状態を保持していて、「名前を教えて」と問えば「鈴木」と答える振る舞いを持っています。オブジェクト指向とクラス
例
class Person def initialize(name, birthday, age, address) @name = name @birthday = birthday @age = age @address = address end def answer_name puts @name end end //実行結果 suzuki = Person.new("suzuki", "1988/5/5", "31", "東京都〇〇区〇〇") => #<Person:0x007fc55c1604f8 @name="suzuki", @birthday="1988/5/5", @age="31", @address="東京都〇〇区〇〇"> irb(main):016:0> suzuki.answer_name suzuki人(Person)クラスを定義して、名前や生年月日などのデータを持つようにしています。answer_nameで自分の名前を答えます。クラスの中にそのクラスとして必要なデータや振る舞いを持たせることで、そのオブジェクトの仕事はそのオブジェクトに任せることができます。
ちなみに、オブジェクト指向を全く取り入れずにアプリケーションを作ることもできます。ですが、オブジェクト指向はユーザーのためのではなく、開発者同士の円滑なコミュニケーションのためにあると考えています。手続き型とオブジェクト指向
「手続き型とオブジェクト指向は何が違うのか」というと、手続き型(手続き型言語)とは、「プログラムを順序どおりに実行させるような書き方」のことを言います。
例えば、「Rubyを使ってあるファイルから品物の合計金額を表示する」というタスクを考えた時に以下のように書きます。
出力結果りんご,100,3 ばなな,180,2 ぶどう,240,1 みかん,300,5 いちご,500,2手続き型の場合
手続き型で記述をすると以下のようなコードになります。
手続き型# ファイルを読み込む filename = 'sample.txt' file = File.open(filename) while text = file.gets # 1行ずつ解析する name, price, count = text.chomp.split(',') price = price.to_i count = count.to_i puts "#{name}: 合計#{price * count}円" end file.closeオブジェクト指向の場合
オブジェクト指向で記述すると以下のようなコードになります。Itemクラスを作成し、読み込んだファイルの値をもとにインスタンスを作成し、インスタンスメソッドで合計金額を計算するようにします。
オブジェクト指向# 品物クラス class Item def initialize(name, price, count) @name = name @price = price @count = count end def total @price * @count end end # ファイルを読み込む filename = 'sample.txt' file = File.open(filename) while text = file.gets # 1行ずつ解析する name, price, count = text.chomp.split(',') price = price.to_i count = count.to_i item = Item.new(name, price, count) puts "#{name}: 合計#{item.total}円" end file.close手続き型とオブジェクト指向の比較
オブジェクト指向は手続き型に比べコード行数が増えていて、メリットが少ないように感じます。しかし、このコードに機能追加が増えてくると、「ファイルを読み込む部分」と「品物に関して処理する部分」が分離されているので見通しが良くなることが期待できます。
簡単に記述するなら手続き型風の記述は便利ですが、ロジックが増えることが予想される部分はオブジェクト指向型の記述方法を取り込みます。オブジェクト指向の例
Railsでオブジェクト指向活かしたアプリケーションを作成する例です。
前提として
名刺管理アプリケーションを開発していると想定します。
以下のような機能があるとします。
個人の名前とメールアドレスを登録できる
企業の名前を登録できる
個人は企業と紐づく(所属する)
Railsでは、以下のようなモデルになります。
例class Person < ActiveRecord::Base belongs_to :company # DBにname, emailカラムを持つ end class Company < ActiveRecord::Base has_many :people # DBにnameカラムを持つ end人物情報の表示
例えばあるページで次のような表示とします。
例山田 太郎 (株式会社◯◯ 所属)このためにViewに次のような記述にしてます。
例<%= @person.name %> (<%= @person.company.name %>)このような表示に変えたい箇所がアプリケーション内に複数あります。
もし、すべての箇所でこの記述に変更すると、同じコードがたくさんの場所にコピーされることになります。
今回は、個人が企業に紐付いてる場合です。
しかし、例えばサービスの仕様変更により、企業に紐付かない個人も登録することができる場合になったとします。
個人が企業に紐づくかどうかによって以下のように場合分けが必要です。
例山田 太郎 (株式会社◯◯ 所属) <- 所属がある場合 山田 太郎 (フリーランス) <- 所属が無い場合Viewは以下のように変更します。
例<% if @person.company %> <%= @person.name %> (<%= @person.company.name %>) <% else %> <%= @person.name %> <% end %>変更箇所が1つなら良いですが、既にアプリケーション内の多くの場所にコピーしてたら変更を加えなければなりません。
これでは、変更すべき箇所が抜け漏れたり、多くの箇所が変更されることによりバグが混入可能性があります。
「このサービスには今後このような仕様変更の可能性がある」と予測を立て、変更に強いアプリケーションの設計を考えましょう。
以下のように変更すると、今回のような大規模なViewの変更という事態は防げます。
例class Person < ActiveRecord::Base belongs_to :company def display_info if company "#{name} (#{company.name} 所属)" else "#{name} (フリーランス)" end end end # view <%= @person.display_info %>共通部分を Personクラスのメソッドとして実装すれば、所属情報を変更するときもView側は変更しなくて済みます。
オブジェクト指向のメリット
「人物情報を出力する」という処理をまるごと「人物 (Person)」の中に入れてしまうことで、将来発生するだろう面倒を避けることができます。
これが、オブジェクト指向を活用して得られる多くのメリットの内の1つです。
例えば、開発を行うとしてオブジェクト指向に則ったアプリケーションを開発することで、開発時に現れる課題が自動的に解決されます。クラスとインスタンス
上記の名刺管理アプリケーションの例を使って用語の説明。
Person
クラス。具体的なデータに紐付かない「データの抽象的な振る舞い」を設定するもの。
@person
Personクラスの インスタンス。クラスから生成される「具体的なデータとそれに対する処理」をまとめたもの。
@person.name
プロパティ。インスタンスが持つデータのこと。Ruby on Railsの場合には、データベースのカラムと同一のものを指している事が多い。
@person.display_info
インスタンスメソッド。インスタンスがもつプロパティなどを使ってデータを加工したり処理するもの。
※厳密には、Rubyという言語の性質上、プロパティとメソッドは実は同じ仕組みで成り立っており違いはないのですが、「オブジェクト指向」として考えた時には違いがあるために区別しました。役に立つ原則
DRY
繰り返しを避けるという原則です。アプリケーションのコードはどのコードも将来バグになる可能性があります。重複があると、アプリケーションのコードは不必要に大きくなり、それにつれて、バグが生じる危険性も高まります。また、システムの構造は、そう意図していないにもかかわらず複雑になってしまいます。重複によりコードベースが大きくなれば、開発に携わる人間がシステム全体を完全に理解することも難しくなります。特に困るのはコードに変更を加える時です。どこかに変更を加えた場合、それとロジック等が重複している箇所にも同様の変更が必要かどうか確認しなければなりません。DRY原則を守ればこのような事態を防ぐことができます。
YAGNI
実際に必要になった機能だけを追加すべきという原則です。漠然とした予想や見込みで追加された機能が使われないまま放置されたり、プログラムの規模が必要以上に大きくなることで設計や構造が複雑になり保守や修正が難しくなり、バグや不具合が起きやすくなります。つまり、今現在具体的な必要性がないのに、将来必要になるかもしれない、あれば便利かもしれないなどといった見込みや思い込みで機能や要素を追加するべきではないとうことになります。
単一責任の原則
クラスが果たす役割を一つだけにするという原則です。例えば、Rectangleクラス(四角形クラス)があるとします。このクラスには四角形を描くメソッドと四角形の面積を計算するメソッドがあるとします。Rectangleクラスには描画と計算の2つの役割があることになります。計算方法を変える(単位の変更など)時と、描画方法を変える(描画する正方形に色をつけるなど)時でクラスの記述を変更する理由が2つになります。役割が増えるほど変更理由が増え、変更が起きやすくなります。このような時は役割ごとにクラスを分けるべきで、役割ごとに分けることで変更する際に該当するクラスを変更するだけで済みます。
インターフェイス分離の原則
あるクラスを利用するクライアントが複数存在するような場合に、各クライアントに共通の大きなインターフェイスを使ってしまうと、各クライアント内では使用しないメソッドがあった場合、クラスが使わないメソッドにも依存してしまいます。つまり、各クライアントが利用していないメソッドに対する変更の影響まで受けてしまう可能性があるということになります。そこで各クライアントが呼び出す必要のあるサービスの単位でクライアントをグループ分けし、そのグループに特化したインターフェイスを準備することで、異なるサービス間での関連性を分断することができます。
- 投稿日:2020-04-02T16:12:20+09:00
本番環境で画像が表示されない
ローカルで表示された画像が本番環境だと表示できない
localhostの時は表示されていた画像がデプロイした本番環境だと表示できず、altの文字だけが表示されてしまう状態になりました。
画像はapp/assets/imagesの中に保存されてあります。
画像のpathがおかしいのかな?と狙いをつけて調べたところ解決できたので、記事にします!元のコード
<img src="assets/MHW.jpg" alt="ゲーム画像1">修正後のコード
<%= image_tag asset_path("MHW.jpg", alt: "ゲーム画像1") %>自動デプロイの際に画像がコンパイルされ、パスが変わるのが原因のようです。
背景画像が表示できない場合は、下記を参照してみてください。元のコード
img { background-image: url("MHW.jpg"); }修正後のコード
img { background-image: image-url("MHW.jpg"); }画像が表示されないエラーはよくあるので、今後も何か発見があれば記事にしていきたいと思います。
以上、ここまで閲覧していただきありがとうございました!!
- 投稿日:2020-04-02T14:56:30+09:00
Rails_MySQL_Docker_Vue.jsの環境をシェル一発で始められるようしてみた
■ 何これ?
$ rails new
する機会が久々にあって、諸々込みでもっと簡単に環境構築出来たら良いなと思ったので、@azul915さんの記事のshellを参考にちょっと改変して使えるようにしてみました。Githubにもありますので好きなだけいじってください。
ご指摘などありましたらお気軽に。
■ 最終的なディレクトリ構成
【app_name】 ∟ Dockerfile ∟ docker-compose.yml ∟ src ∟ [rails new で生成されたファイル群]■ Special Thanks
- 丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)
- https://qiita.com/azul915/items/5b7063cbc80192343fc0
- このサイトのshellからスタートしてます。大感謝。
■ 使い方
1. docker / docker-composeが入っている前提
2. 任意のディレクトリを作成
ex. $ mkdir sample_app $ cd sample_app3. shellを配置して実行
$ bash docker-rails-vue.sh
4. 起動確認して接続
$ docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------ sample_app_db_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp, 33060/tcp sample_app_web_1 rails s -p 3000 -b 0.0.0.0 Up 0.0.0.0:3000->3000/tcp5. http://localhost:3000/に接続
6. 生成されたファイル群をGitにあげて開発スタートすれば良かろうもん
■docker-rails-vue.sh
#!/bin/bash echo "----- 1. docker pull ruby:2.7.0 -----" docker pull ruby:2.7.0 echo "-----2. docker pull mysql:5.7 -----" docker pull mysql:5.7 docker images echo "----- 3. create Dockerfile -----" APP_ROOT="/`pwd | xargs basename`" cat <<EOF > Dockerfile FROM ruby:2.7.0 ENV LANG C.UTF-8 RUN 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 build-essential \ libpq-dev \ nodejs \ yarn \ && rm -rf /var/lib/apt/lists/* \ && yarn install --check-files RUN mkdir $APP_ROOT WORKDIR $APP_ROOT ADD ./src/Gemfile $APP_ROOT/Gemfile ADD ./src/Gemfile.lock $APP_ROOT/Gemfile.lock RUN bundle install ADD ./src/ $APP_ROOT EOF echo "----- 4. create Gemfile -----" mkdir src && cd src cat <<'EOF' > Gemfile source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.7.0' gem 'rails', '~> 6.0.2', '>= 6.0.2.1' gem 'mysql2', '>= 0.4.4', '< 0.6.0' gem 'puma', '~> 4.1' gem 'sass-rails', '>= 6' gem 'webpacker', '~> 4.0' gem 'turbolinks', '~> 5' gem 'jbuilder', '~> 2.7' gem 'bootsnap', '>= 1.4.2', require: false gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] group :development, :test do gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] end group :development do gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' end group :test do gem 'capybara', '>= 2.15' gem 'selenium-webdriver' gem 'webdrivers' end EOF touch Gemfile.lock cd ../ echo "----- 5. create docker-compose.yml -----" cat <<EOF > docker-compose.yml version: '3' services: db: image: mysql:5.7 volumes: - ./src/db/mysql_data:/var/lib/mysql environment: - MYSQL_ROOT_PASSWORD=password ports: - "3306:3306" web: build: . command: rails s -p 3000 -b '0.0.0.0' volumes: - ./src:$APP_ROOT environment: RAILS_ENV: development MYSQL_DATABASE: db_dev MYSQL_USERNAME: root MYSQL_PASSWORD: password MYSQL_HOST: db ports: - "3000:3000" links: - db EOF echo "----- 6. create Rails new app -----" docker-compose build docker-compose run web rails new . --force --database=mysql --webpack=vue --skip-bundle --skip-turbolinks echo "----- 7. fix config/database.yml -----" cd src echo "fix config/database.yml" cd config rm database.yml cat <<'EOF' > database.yml default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> socket: /var/run/mysqld/mysqld.sock database: <%= ENV.fetch("MYSQL_DATABASE") %> username: <%= ENV.fetch("MYSQL_USERNAME") %> password: <%= ENV.fetch("MYSQL_PASSWORD") %> host: <%= ENV.fetch("MYSQL_HOST") %> development: <<: *default production: <<: *default EOF cd ../ echo "----- 8. create database -----" docker-compose run web rake db:create echo "----- 9. docker-compose up -d -----" docker-compose up -d■ エラーとか
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
https://wp.tekapo.com/2019/07/15/difference-between-apt-and-apt-get/
aptじゃなくてapt-get使いましょう。
■ 他参考サイト様
■ この後やること
- vue入ってるのにまだ使ってない件
- この辺りとか参考に↓
- Ruby on Rails, Vue.js で始めるモダン WEB アプリケーション入門
- webpackerじゃなくてwebpackで良い感じにしたい件
- docker image 最適化(マルチステージビルド)したい件
- 投稿日:2020-04-02T12:22:42+09:00
【Rails】一対一対多のアソシエーション
結局は基本的なことなのですが、少し変わると途端にハマってしまう。
アソシエーションがうまくいかずに時間を溶かしてしまったので、そんな過去の自分といるかもしれない未来の誰かのために書き残しておきます。テーブル構造
UserモデルとTagモデルの中間テーブルから派生させたTagSettingモデルを作りました。
ただ、今回の話にはUserモデルはあまり関係ありません。
また、この後「tag_usersとtag_settingsを別々にしなくていいんじゃないか?」という指摘を受けてテーブル構造を変えました。なので、例としては少々不適切かもしれませんがご容赦を。モデルのアソシエーション
user.rbclass User < ApplicationRecord has_many :tag_users has_many :tags, through: :tag_users has_many :tag_settings endtag_user.rbclass TagUser < ApplicationRecord belongs_to :user belongs_to :tag belongs_to :tag_setting endtag_setting.rbclass TagSetting < ApplicationRecord has_one :tag_user has_one :tag, through: :tag_user belongs_to :user endtag.rbclass Tag < ApplicationRecord has_many :tag_users has_many :tag_settings, through: :tag_users end注意点
中間テーブルへのアソシエーションを追加する
has_many :tag_users
なしでhas_many :tag_settings, through: :tag_users
を定義することはできない。
また、中間テーブルへのアソシエーションの方を上に記述する必要がある。単数形・複数形に注意する
has_many :tag_settings, through: :tag_users
has_many
のときは:through
も複数形
has_one :tag, through: :tag_user
has_one
のときは:through
も単数形リンク
- 投稿日:2020-04-02T11:57:00+09:00
「brew --prefix」とは何か?
mysql2
のインストール中にエラーが起きた際の対処法で見かけるopenssl
のインストール先を指定する以下の方法brew --prefix openssl
brew --prefix
とは何ぞや?と思ったので調べてみました。ターミナルで。そもそも「--prefix」とは?
言わずとしれたインストール先の指定方法
--prefix='インストール先のアドレス' ex. --prefix=/usr/localbrew --prefix
じゃあ「brew --prefix」は何だと思って試しにターミナルさんに聞いてみた。
% brew --prefix /usr/local
brew
のインストール先のアドレスだった。単純な話だった。
- 投稿日:2020-04-02T11:55:17+09:00
【MySQL】Mysql2::Error::ConnectionError 自分用メモ
rails s
してサーバーを切り忘れてしまった後にmysqlのエラーが出る。
よくやってしまうので、自分用にまとめました。実際にやっていて手順が増えたら随時追加する。エラー
$ rails s => Booting Puma => Rails 5.2.4.2 application starting in development => Run `rails server -h` for more startup options Puma starting in single mode... * Version 3.12.4 (ruby 2.5.3-p105), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://localhost:3000 Use Ctrl-C to stop Started GET "/" for 127.0.0.1 at 2020-04-02 11:39:55 +0900 Mysql2::Error::ConnectionError - Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2):pumaでrailsサーバーを起動することはできるが、実際にアクセスするとmysqlのエラーが出る。
解決法
$ sudo mysql.server start # mysqlサーバーの起動 Password: # アカウントのパスワードを入力 Starting MySQL .. SUCCESS! $ mysql_config --socket # socketの有無を確認 /tmp/mysql.sock $ chmod 777 /tmp/mysql.sock # 権限を付与今回はこれで解決しました。
リンク
- 投稿日:2020-04-02T09:49:30+09:00
PostgreSQLを利用すると、rails db:createでエラーが発生するトラブルシューティング
環境
Vagrant + Ubuntu 16.04.5 LTS
Rails 5.2.4.2
PostgreSQL9.5.19はじめに
データベースにPostgreSQLを指定して、データベースを作成しようとすると、PostgreSQLに、vagrantというロールがありませんというエラーが表示されて、Railsからデータベースが作成できません。
$rails new test_migrate -d postgresql $cd test_migrate $rails db:create FATAL: role "vagrant" does not exist Couldn't create 'test_migrate_test' database. Please check your configuration. rails aborted! ActiveRecord::NoDatabaseError: FATAL: role "vagrant" does not exist bin/rails:4:in `<main>' Caused by: PG::ConnectionBad: FATAL: role "vagrant" does not exist bin/rails:4:in `<main>' Tasks: TOP => db:create (See full trace by running task with --trace)解決方法
PostgreSQLに接続する。
$sudo su - postgresvagrantという名前のロールを作成します。また、予め、パスワードを設定しておかないと、pgAdminから接続ができない事るので注意。オプションの-sは、スーパーユーザーの事。
~$createuser vagrant -s\duで、ロールの一覧を表示して、vagrantが追加されている事を確認する。既に存在しているpostgresは、デフォルトで用意されているものです。
~$psql postgres=#\du終了します。
postgres=#\q ~$exit
- 投稿日:2020-04-02T09:07:23+09:00
【爆速フロント実装】夢と魔法のeach文【Rails-haml】
はじめに
TECH CAMPというプログラミング教室に45日ほど通った添野です。
昨日、教室内で「Rails-hamlを使ったフロントの爆速コーディング法」を同期に紹介したところ、大変ご好評を頂けたので、これについて記事を作成します。
爆速コーディング
今回は「メルカリのマイページ」を模写することについて考えます。
皆さんは下記画像の要素を実装するにあたり、どのようなコードを書くでしょうか?見た瞬間「面倒くさそう!」と感じる方も多いと思います。
今回はこれを爆速で実装する方法を紹介いたします。結論
爆速実装の手順は下記になります。
1.コントローラに配列
@contents = ["マイページ","お知らせ","やることリスト",...]
を定義
2.hamlにeach文を書く
3.cssを整えるこれだけです。実際にコードを見ながら説明していきます。
1.コントローラに配列を定義
ビューを呼び出しているコントローラのアクションに以下の記述をしてください。コピペでOKです。
今回はusersコントローラのindexアクションだと仮定します。users_controller.rbclass UsersController < ApplicationController def index @contents = ["マイページ","お知らせ","やることリスト","いいね!一覧","出品する","下書き一覧","出品した商品-出品中","出品した商品-取引中","出品した商品-売却済み","購入した商品-取引中","購入した商品-過去の取引","ニュース一覧","評価一覧","ガイド","お問い合わせ"] end endここで何をしているかというと、ビューに表示するための文字列を先にコントローラで配列の中に入れたのです。まだメリットは分からないかもですが、あとで説明していきます。これをやると、よく言われる「変更に強いWEBサービス」になります。
2.hamlにeach文を書く
ビューファイルに以下の記述をしてください。これもコピペでOKです。
index.html.haml.wrapper - @contents.each do|c| .content-title = c3.cssを整える
はい。コピペ推奨!
users.scss.wrapper{ display: flex; flex-direction: column; &__content-title{ &:hover{ color:#000; background-color: #aaa; cursor: pointer; } color: #555; display: inline-block; width: 400px; height: 40px; line-height: 40px; padding-left: 20px; margin-bottom: 2px; background-color: #ddd; box-shadow: 0 2px 2px 0 rgba(0,0,0,0.2); } }たった数分で完成
え?これ、ヤバくね・・・?
この記述を使用するメリットは2つあります。メリット1 HTMLが短くなる
ビューがたった4行で書けてしまいます。時短効果ハンパない。
HTML要素をコピペして増やしていく作業は、もうやめましょう。メリット2 変更に強くなる
実際にサービスを開発する上で、後から「あの項目も必要だった!」となることがあります。
今回の実装だと、変更が簡単です。さっきコントローラで定義した配列に何か文字を追加してください。@contents = ["マイページ",..(省略)..,"追加項目1","追加項目2","追加項目3"]そして、もう一度ビューを見にいきます。
なんということでしょう。勝手に項目が増えました。HTML書いてないのに。これが夢と魔法のeach文の力です。科学の力ではどうすることもできない奇怪な輩に立ち向かうことができました。
おわりに
爆速フロントコーディングの手順は下記でした。
1.コントローラに配列を定義
2.hamlにeach文を書く
3.cssを整えるメリットは下記2つです。
1.HTMLが短くなる
2.変更に強くなる以上になります。ここまで読んでいただきありがとうございました!
- 投稿日:2020-04-02T09:07:23+09:00
【爆速実装】夢と魔法のeach文【Rails-haml】
はじめに
TECH CAMPというプログラミング教室に45日ほど通った添野です。
昨日、教室内で「Rails-hamlを使ったフロントの爆速コーディング法」を同期に紹介したところ、大変ご好評を頂けたので、これについて記事を作成します。
爆速コーディング
今回は「メルカリのマイページ」を模写することについて考えます。
皆さんは下記画像の要素を実装するにあたり、どのようなコードを書くでしょうか?見た瞬間「面倒くさそう!」と感じる方も多いと思います。
今回はこれを爆速で実装する方法を紹介いたします。結論
爆速実装の手順は下記になります。
1.コントローラに配列
@contents = ["マイページ","お知らせ","やることリスト",...]
を定義
2.hamlにeach文を書く
3.cssを整えるこれだけです。実際にコードを見ながら説明していきます。
1.コントローラに配列を定義
ビューを呼び出しているコントローラのアクションに以下の記述をしてください。コピペでOKです。
今回はusersコントローラのindexアクションだと仮定します。users_controller.rbclass UsersController < ApplicationController def index @contents = ["マイページ","お知らせ","やることリスト","いいね!一覧","出品する","下書き一覧","出品した商品-出品中","出品した商品-取引中","出品した商品-売却済み","購入した商品-取引中","購入した商品-過去の取引","ニュース一覧","評価一覧","ガイド","お問い合わせ"] end endここで何をしているかというと、ビューに表示するための文字列を、先にコントローラで配列の中に入れたのです。まだメリットは分からないかもですが、あとで説明していきます。これをやると、よく言われる「変更に強いWEBサービス」になります。
2.hamlにeach文を書く
ビューファイルに以下の記述をしてください。これもコピペでOKです。
index.html.haml.wrapper - @contents.each do|c| .wrapper__content-title = c3.cssを整える
はい。コピペ推奨!
users.scss.wrapper{ display: flex; flex-direction: column; &__content-title{ &:hover{ color:#000; background-color: #aaa; cursor: pointer; } color: #555; display: inline-block; width: 400px; height: 40px; line-height: 40px; padding-left: 20px; margin-bottom: 2px; background-color: #ddd; box-shadow: 0 2px 2px 0 rgba(0,0,0,0.2); } }たった数分で完成
え?これ、ヤバくね・・・?
この記述を使用するメリットは2つあります。メリット1 HTMLが短くなる
ビューがたった4行で書けてしまいます。時短効果ハンパない。
HTML要素をコピペして増やしていく作業は、もうやめましょう。メリット2 変更に強くなる
実際にサービスを開発する上で、後から「あの項目も必要だった!」となることがあります。
今回の実装だと、変更が簡単です。さっきコントローラで定義した配列に何か文字を追加してください。@contents = ["マイページ",..(省略)..,"追加項目1","追加項目2","追加項目3"]そして、もう一度ビューを見にいきます。
なんということでしょう。勝手に項目が増えました。HTML書いてないのに。これが夢と魔法のeach文の力です。科学の力ではどうしようもできない、その奇っ怪なる輩に立ち向かうことができました。
おわりに
爆速フロントコーディングの手順は下記でした。
1.コントローラに配列を定義
2.hamlにeach文を書く
3.cssを整えるメリットは下記2つです。
1.HTMLが短くなる
2.変更に強くなる以上になります。ここまで読んでいただきありがとうございました!
- 投稿日:2020-04-02T07:17:04+09:00
attr_accessorについて
attr_accessorとは?
attr_accessorについて理解が不十分であったので紐解きます。
attr_accessorはデータを代入するメソッド(setter)とデータを取り出せるメソッド(getter)を同時に定義できるメソッドである。これは省略形であり、いきなり覚えようとするとかえって混乱するので一個一個分解していく。attr_accessor・setter/getterを使わずに定義する場合
class okashi def name = (name) #どんな処理を行っているのか @name = name → ・いわゆるsetterの部分 end お菓子クラスに名前という情報をセット しますという処理。@を使用しているた め、メソッドの中だけでなく外でも使用できる。 def name → #どんな処理を行っているのか @user ・いわゆるgetterの部分 end お菓子クラスにセットされている end @nameという情報を取り出す(ゲット) しますの処理 oks = Okashi.new #setterにnameの値をいれる oks.name = "クッキー" #getterを取り出す puts oks.nameconsole上ではクッキーと表示される。これだと中の処理を一個一個細かく書いていかなければならない。これをsetter/getterを使って省略する。
setter/getterを使用して定義する場合
class okashi attr_writer :name → setterの部分。この処理だけでクラスに @nameの値をwrite(書き込む)こと ができるようにする処理。 attr_reader :name → getterの部分。@nameという情報を取り出す 処理 end oks = Okashi.new #setterにnameの値をいれる oks.name = "クッキー" #getterを取り出す puts oks.name上記の処理を省略することでかなりわかりやすくなる。
このsetter getterの処理をさらに省略したものがattr_successorである。class okashi attr_successor :name end oks = Okashi.new oks.name = "クッキー" puts oks.nameここまで省略することができる。
- 投稿日:2020-04-02T00:43:16+09:00
[Rails]refileの使い方を初心者がまとめてみた。[refile]
はじめに
私のオリジナルサービスの画像投稿機能にrefileを使用したので、簡単にまとめておきたいと思います。
つまづいたところとかも記載しておくので、参考になれば幸いです。refileの導入
gem
いくつかQiitaやブログなどで参考記事はありますが、gemをinstallできないもののいくつか見受けられました。
githubに記載されている github/refileGemfilegem "refile", require: "refile/rails" gem "refile-mini_magick"↑この記述方法ではbundle install できませんでした。(環境によっては変わるのか?)
なので、私はこの記事(refile使い方)を参考にして、
Gemfilegem "refile", require: "refile/rails", github: 'manfe/refile' gem "refile-mini_magick"としました。そして
$ bundle installで追加したgemをインストールします。
次にgithubを参考にしていくと
We're requiring both Refile's Rails integration and image processing via the MiniMagick gem, which requires ImageMagick (or GraphicsMagick) to be installed. To install it simply run:
と書かれており、ImageMagickをインストールする必要があると言われているので、
$ sudo apt-get install imagemagickとします。
(僕の場合、 apt-get を yum に直して、 imagemagick を ImageMagick に変更するとインストールできました。ちなみにAWSのcloud9で開発しています。)model
インストールが終わったら、次は画像投稿機能を追加したいmodelに
画像投稿機能をつけるmodelclass User < ActiveRecord::Base attachment :image_id end
attachment :画像を入れたいカラム名 + _id
を追記します。
_id
の説明についてはまた後でしますので、ひとまずつけておいてください。カラムの追加
カラムの追加は
rails g migration add_(追加したいカラム名+_id)_to_追加するモデル名 (追加したいカラム名+_id):型
とします。$ rails generate migration add_image_id_to_users image_id:stringポイントは
(追加したいカラム名+_id)
←これです。
refileの決まりで、先ほどのattachment :
くっつけるカラムには_id
が必要になります。
なので、さきほどのmodelでも出てきましたが、カラム名には_id
をつけてあげてください。View
次は画像投稿用のフォームを作成します。
<%= form.attachment_field :カラム名 %>
で投稿用のフォームが完成します!
ややこしいですが、ここでのカラム名には_id
はいりません。<%= form_for @user do |form| %> <%= form.attachment_field :profile_image %> <% end %>Controller
次はストロングパラメータに先ほど追加したカラムをpermit(許可)してあげないといけません。
ここでも_id
は必要なし。users.controllerdef user_params params.require(:user).permit(:name, :email, image ←これを追加) endView
これで最後です。画像を表示したいところに
<%= image_tag attachment_url(@user, :image, :fill, 300, 300, format: "jpg") %>のように追記してあげるだけです!ここでも
_id
は必要なし。
この:fill, 300, 300
の部分で縦横幅を決めれます。(が、レスポンシブ対応にするならCSSとかで指定した方がいいかも?)
これで投稿した画像が表示されるはずです!まとめ
実際、なにもわからない時に画像投稿機能をつけたいな〜と思いながらQiitaの記事を漁ってましたが、ほとんど分からずにかなり苦戦しました…。
なので、初心者の方にもわかるようにできるだけ詳しく解説してみました。
ポイントはなんども出てきた_id
かな〜と個人的には思います。参考記事
正直どんな記事よりもうるぞーさんのyoutubeを見るのが手っ取り早いです。ほんと神。
ほとんどこの動画を参考にしてました。ありがとうございます。
- 投稿日:2020-04-02T00:25:31+09:00
【Rails】孫モデルの数が最大の子モデルの要素を取得する方法(maximum,maxを使わず、sortで実装する)
やりたいこと
食べログ的なサービスを作っているとして、
いいねが最も多い投稿の画像を、お店の画像として表示したいまえがき
今回やりたかったことが、Railsの
maximum
メソッドやRubyのmax
メソッドを使ってもどうしてもできなかった。(やり方あったら教えてください。)
ので、自分でメソッドを作りました。アイデアとしては、最大のものを取ってくるというよりも、「並べ替えて端っこを持ってくる」ってだけです。
sort
メソッドを使いました。
自分的に少し詰まったのでまとめておきます。
誰かの役に立てることを願って。状況
機能
食べログ的なサービスを作っている。機能としては、
- お店に対して
- ユーザーが
- 画像を投稿する
- ユーザーは投稿に対していいねできる
テーブル
テーブル名 カラム1 カラム2 カラム3 カラム4 Shop id name User id name Post id user_id shop_id image Like id user_id post_id アソシエーション
- Shop has many posts
- User has many posts
- User has many likes
- Post has many likes
(belongs toは省略)
概要
- ControllerでShopモデルのインスタンス取得
- Viewで
most_liked_image
メソッドを使って画像を表示- Modelで
most_liked_image
メソッドを定義この順に説明します。
ControllerでShopモデルのインスタンス取得
@shop = Shop.find(params[:id])とか。
変数@shop
にShopモデルのインスタンスが入れる。Viewで
most_liked_image
メソッドを使って画像を表示<%= image_tag @shop.most_liked_image.to_s %>
most_liked_image
メソッドについては次項で説明します。Modelで
most_liked_image
メソッドを定義
most_liked_image
メソッドで、最もいいねが多い投稿の画像を取得することを考えるmodels/shop.rbclass Shop < ApplicationRecord has_many posts, dependent: :destroy def most_liked_imege sorted_posts = self.posts.sort { |a,b| a.likes.count <=> b.likes.count } sorted_posts.last.image end end以上.
間違ってたらごめんなさい。