- 投稿日:2020-09-08T23:34:53+09:00
administrate で refileを使ってファイルを読み込めるようにしたい【rails6】
ハードはMacBook Air, 開発環境はVScodeを用いています。
ruby2.6.5
rails6.0.3.2rails6で管理者gemにadministrate, 画像読み込みgemにrefileを用いた時に, administrateとrefileの連携でハマってしまったので, その詳細と解決方法を紹介します.
ちなみに、administrate_field_refileはrails6に対応していなかったので、使わない方向で頑張りました!
管理者画面(localhost:3000/admin)で, 新しいデータを追加しようとすると, 画像の入力部分がファイル選択ではなく, テキストボックスになってしまっている
localhost:3000/admin へ移動し, 新規Userを作製しようとすると, profile_imageの部分がテキストボックスになっています。(二枚目の画像の一番下)
そこでこれを解決するために, いろいろ調べてみるとadministrate_field_refileというgemがあるらしいのですが、こちらはrails6に未対応だったので、administrateをカスタムする方向で進めることにしました。
administrateをカスタムする
まず先にadministrate内部のコード、カスタムするであろう部分をローカルで表示できるようにします。administrateのドキュメントを参考に、dashbordのコントローラ, views, fieldを追加していきます。
$ rails generate administrate:dashboard User $ rails generate administrate:views User $ rails generate administrate:field refile次に、dashbordの profile_image_id: Field::String, となっているところを次のように書き換えます。参考;http://administrate-prototype.herokuapp.com/adding_custom_field_types
app/dashboards/user_dashboard.rbATTRIBUTE_TYPES = { ~省略~ profile_image_id: RefileField, }.freeze次にフォームのviewsをテキストボックスからファイルを選択に変更します.
app/views/fields/refile_field/_form.html.erb<div class="field-unit__label"> <%= f.label field.attribute %> </div> <div class="field-unit__field"> <%= f.attachment_field :profile_image, direct: field.direct, presigned: field.presigned, multiple: field.multiple %> </div>次に, app/fields/refile_field.rbを次のように書き換えます.
app/fields/refile_field.rbrequire "administrate/field/base" class RefileField < Administrate::Field::Base def to_s data end def direct options.fetch(:direct, false) end def presigned options.fetch(:presigned, false) end def multiple options.fetch(:multiple, false) end endこのままだと、Unpermitted parameters:という赤い文字がコンソールに表示されて画像を設定できないと思うので、以下で許可します。(~~~には, 登録する要素を入れておく。抜けがあると、ターミナルに赤く表示されるので、その都度確認して追加する)
def resource_params params.require(:user).permit(:profile_image,:~~~,:~~~,:~~~) end恐らくこれでadministrateから画像データを登録できるようになると思います。
パスワードとかも設定できるようにしたい、もっと登録画面を見やすくしたいという人は、以下を参考にしてみてください。
http://blog.319ring.net/2016/05/14/custom_view_administrate/
役に立ったら是非LGTMボタンをポチッと押していただけると嬉しいです
- 投稿日:2020-09-08T23:10:12+09:00
【Rails】本番環境でのデータベースをリセット
はじめに
【前提】
・Railsを使用してアプリケーションを開発
・AWSを使用
・EC2(AWSが提供する仮想サーバ)にてWebサーバを作成既存のデータベースをリセット
今まで私自身ローカル環境にて開発を行うにあたり、DBをリセットしたいことがあった場合
rails db:riset
を使用し、DBの再作成を行なっておりました。今回デプロイ後ですが、マイグレーションファイル等に変更を色々と加えたため、
一度本番環境でもリセットし、再構築しようと考えました。本番環境でのデータベースリセット
RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rails db:dropこのコマンドで本番時でのDBをリセットすることができます
(本番環境でのDBリセットは、実務ではありえるのでしょうか・・)再度データベースの内容を反映させる
rails db:migrate RAILS_ENV=productionおそらくデータベースが無いですよ?とエラーが帰ってくる方がいると思いますので、再度createしてあげます。
rails db:create RAILS_ENV=production rails db:migrate RAILS_ENV=production rails db:seed RAILS_ENV=production※シードに情報を記載していない方は、最後の1行は不要です
上記コマンドを使用すれば本番環境へ無事変更点等が反映されているはず・・・上記記載内容では、こういったリスクがあるのでは等の改善案や提案がございましたら、
コメント等にてお伝えいただければありがたいです。以上、ご参考になれば幸いです。
- 投稿日:2020-09-08T22:27:45+09:00
AWSを使ってアプリケーションを公開する方法(3)EC2インスタンスの環境構築
はじめに
AWSを使ってアプリケーションを公開する手順を記載していく。
この記事ではEC2インスタンスの環境構築を行う。必要なツールのインストール
EC2インスタンスの環境構築を行うために様々なツールをインストールする。
「.ssh」ディレクトリに移動する
下記コマンドを実行し「.ssh」ディレクトリに移動する。
cd ~/.ssh/ssh接続
以下のコマンドを実行してEC2インスタンスにsshでアクセスする。
(ダウンロードしたpemファイル名が「xxx.pem」、ElasticIPが123.456.789の場合)ssh -i xxx.pem ec2-user@123.456.789yumコマンドを実行しパッケージをアップデート
以下のコマンドを実行してパッケージをアップデートする。
sudo yum -y updateパッケージとは
- パッケージはLinuxOSの動作に必要な各種プログラムやファイルをまとめたもの。
- バイナリ型式のプログラムおよびそのプログラムを動作させるのに必要なライブラリや設定ファイル、手順書のようなドキュメントで構成される。
yumコマンドとは
- CentOSなどのLinuxディストリビューションでは、基本的にRPM(Red Hat Package Manager)と呼ばれるパッケージ管理システムが使われている。RPMパッケージであれば、「rpm」コマンドで手軽にインストールしたり、アップデートやアンインストールしたりすることができる。
- 「あるソフトウェアを使うにはこのソフトウェアが必要」といった依存関係をチェックして必要なソフトウェアを自動でインストールするなど、RPMをより便利に活用できるようにしたのがYUM(Yellowdog Updater Modified)で、YUMのパッケージ操作はyumコマンドで行う。
- yumコマンドで使えるコマンドやオプションには様々なものがあり、上で行っている「yum -y update」は全ての問い合わせに「yes」で応答しシステムのパッケージを更新するというコマンドである。
yumコマンドを実行し各種パッケージをインストール
以下のコマンドを実行し、その他環境構築に必要なパッケージを諸々インストールする。
sudo yum -y install git make gcc-c++ patch libyaml-devel libffi-develsudo yum -y install libicu-devel zlib-devel readline-devel libxml2-develsudo yum -y install libxslt-devel ImageMagick ImageMagick-develsudo yum -y install openssl-devel libcurl libcurl-devel curlNode.jsをインストール
Node.jsとは、サーバサイドでJavascriptを動かすためのもの。詳しくは別の記事にまとめたい。
今後の作業でcssや画像を圧縮するためにインストールする。以下のコマンドを実行し、Node.jsをインストールする。
sudo curl -sL https://rpm.nodesource.com/setup_6.x | sudo bash -sudo yum -y install nodejscurlコマンドとは
サーバとデータのやりとりを行うコマンド。
よく使うオプションは以下らしい。こちらもあとで詳しくまとめたい。-L -- リダイレクトがあったらリダイレクト先の情報を取る -s -- 余計な出力をしない -o -- レスポンスボディの出力先を指定するbashコマンドとは
bashとはシェルの一種で、ユーザの入力をコンピュータに伝えるもの。
ここではbashを起動している。rbenvとruby-buildをインストールする
以下はRubyを使ってサーバサイドを実装する場合に行う。
以下のコマンドを実行してgitからrbenvをクローンする。
#rbenvのインストール git clone https://github.com/sstephenson/rbenv.git ~/.rbenv以下のコマンドを実行してパスを通す。
パスを通すとは、どのディレクトリからもアプリケーションを呼び出せる状態にすること。#パスを通す echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile #rbenvを呼び出すための記述 echo 'eval "$(rbenv init -)"' >> ~/.bash_profile以下のコマンドを実行して設定したパスを読み込む。
#.bash_profileの読み込み source .bash_profile以下のコマンドを実行してgitからruby-buildをクローンする。
#ruby-buildのインストール git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build以下のコマンドを実行して、rehashを行う。
つまり、rubyやgemをインストールして使えるコマンド(irb, gem, rake, rails, rubyなど)をバージョン毎に振り分け、使用できるようにする。#rehashを行う rbenv rehashRubyをインストールする
今回はバージョン2.5.1をインストールする。
以下のコマンドを実行して、Rubyの2.5.1のバージョンをインストールする。
rbenv install 2.5.1以下のコマンドを実行して、EC2インスタンス内で使用するRubyのバージョンを決める。
rbenv global 2.5.1以下のコマンドを実行して、サイドrehashを行う。
#rehashを行う rbenv rehash最後に以下のコマンドできちんとインストールができているか確認する。
#バージョンを確認 ruby -v参考
- 投稿日:2020-09-08T22:16:59+09:00
ブラウザに表示させるための事前処理(コンパイラ)
複数の静的ファイルがブラウザに適用されるまでの仕組みをまとめました。
大まかに言うと、
ブラウザでは認識できる言語が決まっており、どんな言語も認識できる言語に翻訳する必要があります。
この翻訳作業をコンパイルといい、コンパイルできないものは事前に処理をする必要があります。この事前処理はプリコンパイルと呼ばれ、細かい機能1つ1つをモジュールという処理のまとまりにし、コンパイルしてブラウザに返すといった流れです。前提 プログラミング初学者(2ヶ月)が学んだ内容をまとめたものです。 実際の現場では通用しないことや間違った情報がある可能性があります。 お気づきの方はコメントにてご指摘いただければ幸いです。ブラウザは認識できる言語が決まっている
ブラウザはHTML,CSS,JavaScript,WebAssemblyという言語のみを認識することができます。
サーバーサイドでどんな記述をしていたとしても、最終的にはこの4つでブラウザに返されています。
これ以外の言語ではブラウザはページを描画することができません。開発を便利にする言語
ブラウザでは、上記4つだけを認識してくれますが、開発ではより書きやすく読みやすいように設計されたプログラミング言語があります。
このプログラミング言語を高級言語といいます。高級言語
機械よりも人間が理解しやすいように設計されたプログラミング言語
機械が認識しやすい言語は低級言語と呼ばれます。
高級言語の例
CSS:SCSS、SASS
JavaScript:TypeScript、CoffeeScriptブラウザが認識できる言語に変換する仕組み
開発に便利な言語をブラウザが認識できるように翻訳する作業をコンパイルといいます。
コンパイル
プログラミング言語を動作する機械が理解できるように翻訳する作業
コンパイルはコンパイラというプログラムによって行われる。
コンパイラで認識できない言語がある場合は予めプリコンパイルしておく必要があります。プリコンパイル
コンパイラが翻訳できない言語を翻訳できるようにする事前コンパイルのこと
メインとなる処理に対して行う前処理のこと
このプリコンパイルを行うための手法として、アセットパイプラインという仕組みがある。アセットパイプライン
JavaScriptやCSSなどのアセットと呼ばれる静的ファイルを小さくまとめてくれる機能
アセットパイプラインの処理は、プリコンパイル→連結→圧縮→配置の流れで行われます。
複数の静的ファイルをプリコンパイルして連結したのち、圧縮して軽量化したものをpublicディレクトリに配置して、ブラウザへ渡せるようにします。
プリコンパイルはモジュールバンドラを使って行われます。モジュールバンドラ
モジュールバンドラはJavaScriptのモジュールの依存関係を考慮しながら管理するツール
モジュールは機能を1つずつ分けて他のファイルから読み込めるようにした処理のまとまりのこと
機能のまとまりをモジュール、この1つ1つの機能が依存関係にある場合にモジュールバンドラはこれらを考慮しながら管理してくれます。
モジュールで管理せず、機能をファイルごとに分割してしまうと、最終的に1つのファイルにまとめるときに不具合が生じるためモジュールパンドラが使われています。webpack
モジュールバンドラの中で主流なツール
webpackが行うことは大きく4つ
・Entry
依存関係を解決するためにどのファイルを基準(エントリーポイント)とするかを決める。
・Output
エントリーポイントにされ、webpackによってまとめられたファイルをどこへどのような名前で出力(アウトプット)するのか指定する。
・Loaders
JavaScript以外のCSSやHTMLなどのファイルをモジュールに変換する方法を読み込み(ロード)、指定した処理を行う。
・Plugins
圧縮などのファイルをまとめる以外でローダーが実行できないタスクを導入し、拡張(プラグイン)する。
- 投稿日:2020-09-08T22:04:18+09:00
deviseを用いたユーザー認証機能の実装(1)
今回はdeviseを用いたユーザー認証機能の実装方法について書いていきます。
できるようになること
・ユーザー登録
・ログイン
・ログアウトWebサービスにおいては必須の機能ですね。
では、早速いきましょう。
まずrailsアプリケーションのディレクトリにあるGemfileの一番下に
Gemfilegem 'devise'と記述します。 その後、ターミナルで
% bundle installを行います。 bundle install した後はサーバーの再起動が必要なので、
% rails sを行います。
※サーバーが起動していた場合は一旦 Ctrl + C でサーバーを停止させてから実行してください。
次にdeviseの設定ファイルをrailsアプリケーションにインストールするため、
% rails g devise:installを行います。
このコマンドにより、deviseの設定関連に使用するファイルを自動で生成します。
次にユーザーを管理するモデルを作成します。
通常のモデル作成の手順とはコマンドが異なります。% rails g devise userと実行しましょう。
これでdeviseで使用するモデルファイルやマイグレーションファイルが生成されます。
次に生成されたマイグレーションファイルに必要なカラムを追記しましょう。
※emailとencripted_passwordのみデフォルトで記載されています。必要なカラムを記載したら、ターミナルで
% rails db:createでデータベースを作成し、
% rails db:migrateでマイグレーションを行いましょう。
これでひとまずはUserモデルの作成が完了です。
- 投稿日:2020-09-08T20:24:15+09:00
Rubyのクラスとインスタンスを用いてコードを書く
はじめに
プログラミング学習中の者です。初投稿です。
学習したことを書くことで、自分の中により定着させることができればと思っています。
よろしくお願い致します。早速本題に入ります。
本題
某プログラミングスクールで出たRubyの問題について、解答に少し手間取ってしまったので忘れないためにメモします。
すごく初歩的な問題ではあるのですが・・
問題と正解は下記の通り(問題の内容がそのままだと宜しくないのでちょっとだけ変えてます)。問題
class Article def initialize(author, title, content) @author = author @title = title @content = content end end # クラスとインスタンスを使用して、上記のコードに追加を行い、以下の出力結果を得られるようにする 書いた人: 鈴木 タイトル: はじめまして 本文: 初投稿です正解
class Article def initialize(author, title, content) #3行目 @author = author @title = title @content = content end def author #9行目 @author end def title #13行目 @title end def content #17行目 @content end end article1 = Article.new("鈴木", "はじめまして", "初投稿です") #23行目 puts "書いた人: #{article1.author}" #25行目 puts "タイトル: #{article1.title}" puts "本文: #{article1.content}"自分のために解説してみる
まず最初に・・
* インスタンスメソッドはクラスの中で定義する
* initializeメソッドもインスタンスメソッドの1つ
* インスタンス変数は、そのクラス内すべてのインスタンスメソッドで使える(スコープ)それぞれの行について
(3〜7行目)
initializeメソッドの中で定義したインスタンス変数に、引数で受け取った、鈴木
、はじめまして
、初投稿です
という3つの値をそれぞれのインスタンス変数に代入する。(9〜19行目)
インスタンス変数の値を返すためのインスタンスメソッドをそれぞれ定義する。
当然ながら、例えば、これらのインスタンスメソッドを定義しない状態で、25行目をarticle1.author
ではなく@author
と書いたところで鈴木
とは出力されない。(23行目)
Articleクラスのインスタンスを生成し、変数article1に代入。
その際に実引数として鈴木
、はじめまして
、初投稿です
という3つの値を、仮引数author
、title
、content
にそれぞれ渡している。(25〜27行目)
9〜19行目で定義したインスタンスメソッドを呼び出す。
インスタンスメソッドはインスタンス名.メソッド名
で呼び出せる。おわり
この記事を書いたおかげで、クラスとインスタンスに関することを忘れないようにできたのではないかと思います。
いい機会になりました。また何かあったら書いてみます。ここまでお付き合いしてくださった方ありがとうございました。
- 投稿日:2020-09-08T20:05:00+09:00
(ギリ)20代の地方公務員がRailsチュートリアルに取り組みます【第5章】
前提
・Railsチュートリアルは第4版
・今回の学習は3周目(9章以降は2周目)
・著者はProgate一通りやったぐらいの初学者基本方針
・読んだら分かることは端折る。
・意味がわからない用語は調べてまとめる(記事最下段・用語集)。
・理解できない内容を掘り下げる。
・演習はすべて取り組む。
・コードコピペは極力しない。さて第5章。こっから本格的な開発フェーズですね。
本日の一曲はこちら。
Luby Sparks "Pop.1979"
ルビー違い。この初期衝動たっぷりのサウンドがたまらん。第1章で予告した通り、ProgateのSassコースやってなかったので、さくっと終わらせてきました。コードの重複を無くして記述を楽に、そして変更にも対応しやすくするための記法ですね。
【5.1.1 ナビゲーション メモと演習】
Bootstrapが登場しました。概要はこの記事が分かりやすいかも。
要するに、あらかじめ動作が定義されたものを呼び出すことで、Web開発を楽にするためのもの。レスポンシブデザインにも難なく対応。1. Webページと言ったらネコ画像、というぐらいにはWebにはネコ画像が溢れていますよね。リスト 5.4のコマンドを使って、図 5.3のネコ画像をダウンロードしてきましょう8 。
→ 下記コマンドでダウンロードするだけ。(猫かわいいですよね)$ curl -OL cdn.learnenough.com/kitten.jpg
2. mvコマンドを使って、ダウンロードしたkitten.jpgファイルを適切なアセットディレクトリに移動してください (参考: 5.2.1)。
→ 下記コマンドでimagesディレクトリへ$ mv kitten.jpg app/assets/images3. image_tagを使って、kitten.jpg画像を表示してみてください (図 5.4)。
→ 下記をhomeの一番最後に追記すればOK。home.html.erb<%= link_to image_tag("kitten.jpg", alt: "cute kitten") %>
【5.1.2 BootstrapとカスタムCSS メモと演習】
まだまだCSSもおぼつかないので、時間がかかるけど、一つ入力するごとに動作を確認していこう。全コピしていちいちコメントアウトするよりこっちのが楽でしょ。
そして、うっとおしいのでこの時点でネストできるもんはしていきます。たしかこの後どっかでネストしてたと思うけど。先にやっといて、あとで答え合わせと行こうか。1. リスト 5.10を参考にして、5.1.1.1で使ったネコ画像をコメントアウトしてみてください。また、ブラウザのHTMLインスペクタ機能を使って、コメントアウトするとHTMLのソースからも消えていることを確認してみてください。
→ 指示通りやるだけ。消えろキトゥン!!!!!
2. リスト 5.11のコードをcustom.scssに追加し、すべての画像を非表示にしてみてください。うまくいけば、Railsのロゴ画像がHomeページから消えるはずです。先ほどと同様にインスペクタ機能を使って、今度はHTMLのソースコードは残ったままで、画像だけが表示されなくなっていることを確認してみてください。
→ そらっそすよね。CSSで非表示にしてるだけだし。これもやるだけなので細かいことは割愛。
【5.1.3 パーシャル(partial) メモと演習】
パーシャル=部分的な といった意味。冷蔵庫のパーシャルをイメージすると分かりやすいかも。あそこにガシャコンと分けて収納するイメージ。他のページでも使う部分や、すべてのページで共通して使うものを、切り出して個別保存すると。必要に応じて呼び出す(render)わけか。
1. Railsがデフォルトで生成するheadタグの部分を、リスト 5.18のようにrenderに置き換えてみてください。ヒント: 単純に削除してしまうと後でパーシャルを1から書き直す必要が出てくるので、削除する前にどこかに退避しておきましょう。
→ とりあえず適当に避難しといて指示どおり記入。
2. リスト 5.18のようなパーシャルはまだ作っていないので、現時点ではテストは redになっているはずです。実際にテストを実行して確認してみましょう。
→ そらREDです。
3. layoutsディレクトリにheadタグ用のパーシャルを作成し、先ほど退避しておいたコードを書き込み、最後にテストが green に戻ることを確認しましょう。
→ 下記ファイルを作成してパーシャル!(テストもGREENです)_rails_default.html.erb<%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
【5.2.1 アセットパイプライン メモ】
今一つ分かりにくいなあと思うアセットパイプライン。重要なのはこの一文か。「『開発効率と読み込み時間のどちらを重視するか』という問題について悩む必要がなくなります。開発環境ではプログラマにとって読みやすいように整理しておき、本番環境ではAsset Pipelineを使ってファイルを最小化すればよいのです。」
要は、散らばったものを一つの細い管に通してやるイメージでしょうか。その過程でファイルを整理して無駄なものを省き、最小化してくれると。
【5.2.2 素晴らしい構文を備えたスタイルシート メモと演習】
LESS変数一覧をみると、@gray-lightが#777じゃなくて、lighten(@gray-base, 46.7%)になってるんですが、バージョンの違いでしょうか?実際の色は変わっていないようにみえるのでいいんですが(他の既定の色も同じか)
。1. 5.2.2で提案したように、footerのCSSを手作業で変換してみましょう。具体的には、リスト 5.17の内容を1つずつ変換していき、リスト 5.20のようにしてみてください。
→ はじめに書いたときから実践済みです。合ってました。(見やすいかと思ったのでネストに改行入れてます)custom.scss/* footer */ footer { margin-top: 45px; padding-top: 5px; border-top: 1px solid $gray-medium-light; color: $gray-light; a { color: $gray; &:hover { color: $gray-darker; } } small { float: left; } ul { float: right; li { float: left; margin-left: 15px; } } }
【5.3 レイアウトとリンク】
最初、名前付きルート(〇〇_path)ってのがしっくりこなかったけど、慣習としてこう書くっていうのと、そういう機能がrailsに備わっていて、変更にも対応しやすいからこうしましょってことと理解。ルーティングを設定することで使えるようになると。
【5.3.2 RailsのルートURL メモと演習】
〇〇_path:ルートURL以下の文字列を返す。基本はこっちを使用
〇〇_url :完全なURLの文字列を返す。リダイレクトの場合のみ使用。1. 実は名前付きルートは、as:オプションを使って変更することができます。有名なFar Sideの漫画に倣って、Helpページの名前付きルートをhelfに変更してみてください (リスト 5.29)。
→ リスト5.29のとおりas: 'helf'を追記。
2. 先ほどの変更により、テストが redになっていることを確認してください。リスト 5.28を参考にルーティングを更新して、テストを greenにして見てください。
→ 当然RED。テストをhelf_pathに変更するとGREENになります。
3. 比較演算子==を使って、上記2つの課題で作ったそれぞれのオブジェクトが同じであることを確認してみてください。
→ 戻しときましょう。
【5.3.3 名前付きルート 演習】
1. リスト 5.29のようにhelfルーティングを作成し、レイアウトのリンクを更新してみてください。
2. 前回の演習と同様に、エディタのUndo機能を使ってこの演習で行った変更を元に戻してみてください。
→ helf好きやな。ルートにas: 'helf'つけて、ヘッダーのhelp_pathをhelf_pathにして終わり!そして戻す!(この演習要る?)
【5.3.4 リンクのテスト メモと演習】
統合テスト(integration test)が登場。「統合テストを使うと、アプリケーションの動作を端から端まで (end-to-end) シミュレートしてテストすることができます。」ということです。動作の流れを考えながら書きましょう。
テストについては、Railsドキュメントが分かりやすいかも?(リンク先はRails6のものです)
assert_selectは柔軟な機能があるが、レイアウト内で頻繁に変更されるHTML要素 (リンクなど) をテストするぐらいに抑えておく方が賢明と。第3章の用語集でも取り上げてましたね。
おっと、ここでエラーが?調べると、リンク先を'root_path'のようにしていました。〇〇_pathはメソッドなので''は不要とのこと。単純な見落としでした。1. footerパーシャルのabout_pathをcontact_pathに変更してみて、テストが正しくエラーを捕まえてくれるかどうか確認してみてください。
→ /aboutにマッチする要素が一つもないよーと教えてくれます。
2. リスト 5.35で示すように、Applicationヘルパーで使っているfull_titleヘルパーを、test環境でも使えるようにすると便利です。こうしておくと、リスト 5.36のようなコードを使って、正しいタイトルをテストすることができます。ただし、これは完璧なテストではありません。例えばベースタイトルに「Ruby on Rails Tutoial」といった誤字があったとしても、このテストでは発見することができないでしょう。この問題を解決するためには、full_titleヘルパーに対するテストを書く必要があります。そこで、Applicationヘルパーをテストするファイルを作成し、リスト 5.37のFILL_INの部分を適切なコードに置き換えてみてください。ヒント: リスト 5.37ではassert_equal <期待される値>, <実際の値>といった形で使っていましたが、内部では==演算子で期待される値と実際の値を比較し、正しいかどうかのテストをしています。
→ 3周目でやっと内容についてこれた感があります。まずtest環境でApplicationヘルパー(のfull_titleメソッド)を使えるようにincludeする。そうすっとレイアウトの統合テストでページタイトルが合ってるかどうかテストできる。ただ誤字とかは発見できないから、Applicationヘルパー自体をテストしてやろうというわけか。FILL_INの部分は下記のとおり。テストはGREENです。test/helpers/application_helper_test.rbrequire 'test_helper' class ApplicationHelperTest < ActionView::TestCase test "full title helper" do assert_equal full_title, "Ruby on Rails Tutorial Sample App" assert_equal full_title("Help"), "Help | Ruby on Rails Tutorial Sample App" end end
【5.4.1 Usersコントローラ 演習】
1. 表 5.1を参考にしながらリスト 5.41を変更し、users_new_urlではなくsignup_pathを使えるようにしてみてください。
2. 先ほどの変更を加えたことにより、テストが redになったことを確認してください。なお、この演習はテスト駆動開発 (コラム 3.3) で説明した red/green のリズムを作ることを目的としています。このテストは次の5.4.2で greenになるよう修正します。
→ users_controller_test.rbのusers_new_urlをsignup_pathに変更するだけ。当然REDになります。
フライングですが、signup_pathを使えるようにするにはどうするか。ルーティングを設定する必要がありますね。以下で合ってるはず。テストはGREENになりました。routes.rbRails.application.routes.draw do get 'users/new' root 'static_pages#home' get '/help', to: 'static_pages#help' get '/about', to: 'static_pages#about' get '/contact', to: 'static_pages#contact' get '/signup', to: 'users#new' end次読むと、合ってましたね。
【5.4.2 ユーザー登録用URL 演習】
1. もしまだ5.4.1.1の演習に取り掛かっていなければ、まずはリスト 5.41のように変更し、名前付きルートsignup_pathを使えるようにしてください。また、リスト 5.43で名前付きルートが使えるようになったので、現時点でテストが greenになっていることを確認してください。
→ さっきやりました。
2. 先ほどのテストが正しく動いていることを確認するため、signupルートの部分をコメントアウトし、テスト redになることを確認してください。確認できたら、コメントアウトを解除して greenの状態に戻してください。
→ 試すだけー。
3. リスト 5.32の統合テストにsignupページにアクセスするコードを追加してください (getメソッドを使います)。コードを追加したら実際にテストを実行し、結果が正しいことを確認してください。ヒント: リスト 5.36で紹介したfull_titleヘルパーを使ってみてください。
→ たぶんいらんけど、ついでにSing upリンクがあるか確かめるテストも追記してみました。自分の知識を確かめるために要らんこともしていきます。site_layout_test.rbrequire 'test_helper' class SiteLayoutTest < ActionDispatch::IntegrationTest test "layout links" do get root_path assert_template 'static_pages/home' assert_select "a[href=?]", root_path, count: 2 assert_select "a[href=?]", help_path assert_select "a[href=?]", about_path assert_select "a[href=?]", contact_path assert_select "a[href=?]", signup_path get contact_path assert_select "title", full_title("Contact") get signup_path assert_select "title", full_title("Sign up") end end
第5章まとめ
・Bootstrapは便利やけど、使われすぎておもんないとも聞く。
・猫は万国共通でかわいい。
・Sassは便利ですね。コードがスッキリする。
・パーシャルでまとめて見た目スッキリ。
・Asset Pipelineが勝手にassets(画像とかCSSとかJSとか)を最適化してくれる。
・ルーティングを設定すると〇〇_pathと〇〇_urlが使えるようになる。
・統合テストはページ間移動とかの動作をテストできる。動作をシミュレートしよう。
第5章はわりとさっくり終了。3周目にして内容がやっと掴めるようになってきました。嬉しい。第6章ではユーザーモデルを作成していきます。
⇦第4章はこちら
学習にあたっての前提・著者ステータスはこちら
なんとなくイメージを掴む用語集
・条件付きコメント
Microsoft Internet Explorerに対して、コードを渡したり隠したりするのに使用できるHTMLソースコード中にある条件付きのステートメントのこと。IE10以降は廃止されている。・レスポンシブ(ウェブ)デザイン
表示する端末・ブラウザによって表示形式が変わるデザインのこと。同じwebサイトでも、スマホとPCでは文字やコンテンツの大きさが変わったりするアレ。レスポンシブ対応とかよく言われるやつ。・assert_template
そのアクションで指定されたテンプレートが描写されているかをテスト。・assert_equal
assert_equal <期待される値>, <実際の値> の形で、両者の値が等しいかテスト。
- 投稿日:2020-09-08T20:01:26+09:00
ERROR: In file ./.env: environment variable name 'THOR_SILENCE_DEPRECATION ' may not contain whitespace. への対処法
タイトルの通りですが、今回は
.envERROR: In file ./.env: environment variable name 'THOR_SILENCE_DEPRECATION ' may not contain whitespace.というエラーが出た際の対処法について、私の環境下でのソリューションを共有したいと思います。
私はRuby on Railsでプログラミング学習を開始して1ヶ月ほどの初学者ですので、至らない点や説明不足の点等もあるかと思います。
お気づきの点等ございましたらご指摘いただけると幸いです。※できるだけ初学者の方にも分かりやすく説明する事を心がけているため、やや冗長に感じる部分もあるかもしれませんがご了承くださいませ。
環境
・Ruby 2.6.5
・Rails 5.2.3
・MySQL 5.7
・Docker
・Dokcer-compose version: '3'まずは解決した方法から
早速ですが解決方法から述べたいと思います。
私の環境下では、ルートディレクトリ
(DockerfileやGemfile等のファイルと同じ階層)
に存在する.envファイルの記述が間違っていた事が原因でした。.env#こちらがエラーが出てしまう記述 THOR_SILENCE_DEPRECATION = true #以下の記述に修正すればエラーは解消される THOR_SILENCE_DEPRECATION=trueエラーが出てしまう記述では、余計な空白が入ってしまっていますね。
空白を除去する事で、上記エラーは解消されます。エラーの深掘り
エラーの内容を再度見てみましょう。
.envERROR: In file ./.env: environment variable name 'THOR_SILENCE_DEPRECATION ' may not contain whitespace.こちらの文章をGoogle翻訳で日本語に修正してみると、
エラー:ファイル./.env:環境変数名 'THOR_SILENCE_DEPRECATION'に空白が含まれていない可能性があります。
と変換されます。
日本語としては若干分かりづらいのですが、なんとなく
「空白の関係でエラーが出ているのだな」
とアタリをつける事ができます。
エラー文本文でググってみると、完全に同じエラー文が出てきた方はいらっしゃいませんでしたが、解決にあたっては以下のブログを参考にさせていただきました。
Composerで.env内のスペースはクォートで囲む必要があるエラーが発生
https://awesome-linus.com/2019/04/07/composer-install-error-need-quotes/エラー文でググったところ情報が少なかったため、おそらくそう頻繁に出るエラーではないのだと予測できますが、初学者の方がエラーに遭遇した際の一つのソリューションとして参考になれば幸いです。
エラーが起きた背景を詳しく
エラーが起きた背景について、もう少し詳しく記述していきます。
このエラーは「.envファイル」の記述が間違えているのが原因なのですが、そもそも.envファイルを触った事がないという方もいらっしゃるかも知れません。
私も約1ヶ月ほどRailsを勉強してきた中で、.envファイルを触る機会というのは一度もなかったのですが、ログイン機能を実装するGem「sorcery」を導入する過程で、以下のエラーを解決するために.envファイルを触る必要が出てきました。
Deprecation warning: Expected string default value for '--test-framework'; got false (boolean). This will be rejected in the future unless you explicitly pass the options `check_default_type: false` or call `allow_incompatible_default_type!` in your code You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.こちらのエラーは、
・Gemfileにsorceryを追加
・bundle install
・sorceryを使用するためのコマンド「rails g sorcery:install」を実行という過程の中で発生したものです。
エラーの詳細については私もよく分かってはいないのですが、どうやらシェルスクリプトを生成するためのGemからエラーが出ているらしいとのこと。
このエラーを解決するための方法として、.envファイルに
.env#正しい記述 THOR_SILENCE_DEPRECATION=trueの記述を追加する必要があり、
誤って以下のコードを記述。.env#不要な空白があるためエラーが出る記述 THOR_SILENCE_DEPRECATION = trueそして、rails g controller ~~
を実行しようとしたところ、タイトルのエラーが発生したという経緯です。ちなみに、「Deprecation warning〜〜〜」のエラーに関しては、以下の記事
[Ruby on Rails]環境変数の設定方法(.bash_profile、Dotenv-rails)
https://qiita.com/yuichir43705457/items/7cfcae6546876086b849RSpecを導入する
https://qiita.com/d0ne1s/items/1ecd114b33e80058215fを参考に解決する事ができました。
ありがとうございました。おしまい
以上が、今回のエラーの解決方法と周辺情報です。
あまり情報が多くないエラーでしたので、もし遭遇して困っている方は参考にしていただけると幸いです。
また、説明が分かりづらい点等があれば、ご指摘いただければと思います。それでは、最後までお付き合いいただきありがとうございました。
- 投稿日:2020-09-08T19:14:50+09:00
JSON でdiff をとった
JSON matcher を使って rspec を書いてたけど JSON の要素が多くてどこが違うかわからなかった
a.rb#!/usr/bin/env ruby def main ARGF.each do |line| line.match(/expected (.*) to be JSON matching (.*)/) do |m| e, r = m[1, 2] r.gsub!(/(At=>)([^"](?:[^,]+|,[^ ]|, [^:])+)(, :)/) do "#{$1}\"#{$2}\"#{$3}" end r.gsub!(/(\(an instance of String\))/, "\"\\1\"") r = eval(r) puts e puts r.to_json end end end main$ rspec aaa_spec.rb:xxx >! out $ ./a.rb out | jq -s '.[0]' >! b $ ./a.rb out | jq -s '.[1]' >! c $ vimdiff b cみたいに書いてみたけど,結局見つけたのは部分部分ケズってみて原因を特定したりした.
記事を書いて供養しておこう.
- 投稿日:2020-09-08T19:14:50+09:00
JSON でdiff を取った
JSON matcher を使って rspec を書いてたけど JSON の要素が多くてどこが違うかわからなかった
a.rb#!/usr/bin/env ruby def main ARGF.each do |line| line.match(/expected (.*) to be JSON matching (.*)/) do |m| e, r = m[1, 2] r.gsub!(/(At=>)([^"](?:[^,]+|,[^ ]|, [^:])+)(, :)/) do "#{$1}\"#{$2}\"#{$3}" end r.gsub!(/(\(an instance of String\))/, "\"\\1\"") r = eval(r) puts e puts r.to_json end end end main$ rspec aaa_spec.rb:xxx >! out $ ./a.rb out | jq -s '.[0]' >! b $ ./a.rb out | jq -s '.[1]' >! c $ vimdiff b cみたいに書いてみたけど,結局見つけたのは部分部分ケズってみて原因を特定したりした.
記事を書いて供養しておこう.
- 投稿日:2020-09-08T18:23:29+09:00
ELBを経由したリクエストでCSRF対策エラーが起こったのでデバッグと解決まで
背景
AWSで Proxy ELB -> Nginx -> ELB -> Taget Group -> ECS でリクエストを飛ばしてRailsのサービスを動かしたところ、 CSRFトークン対策でエラーになったのでそのデバッグと解決策までの道のり。
CSRFトークン対策でエラーになる
エラー概要
起こっていたエラーは
ActionController::InvalidAuthenticityToken
。CSRFトークン対策とは
https://railsguides.jp/security.html#クロスサイトリクエストフォージェリ-csrf
Railsが標準搭載しているセキュリティ対策です。
セッションに保存されてるtokenとPOST時のauthencity_token
が一致しているかを検証し、一致していない場合にエラーを吐く。解決策
nginx.confに
proxy_set_header X-Forwarded-SSL on;
を追加する。nginx.conf# もっと本当は書いてあるけど省略 server { listen 80; server_name hoge.jp; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; # これを追加する proxy_set_header X-Forwarded-SSL on; }エラー検証
tokenが異なっている?
セッションに保存されてるtokenとPOST時の
authencity_token
が一致しているかを検証し、一致していない場合にエラーを吐くならセッションに保存されているtokenと
authencity_token
が異なっているのか、通常の操作でそうなることがあるのだろうか、ということで実際に検証しているRailsのコードをみてみた。rails/actionpack/lib/action_controller/metal/request_forgery_protection.rbdef verified_request? # :doc: !protect_against_forgery? || request.get? || request.head? || (valid_request_origin? && any_authenticity_token_valid?) endこの
verified_request?
がfalseの時にInvalidAuthenticityToken
のエラーが投げられる。
tokenが異なるということはany_authenticity_token_valid?
がfalseということになるので、その予想でデバッグをしてみた。が、any_authenticity_token_valid?
はtrueだった。
valid_request_origin?
がfalseになっている?上のコードを見ると、
valid_request_origin?
がfalseの時にもverified_request?
がfalseになる可能性があるので、確認してみた。
すると確かに、valid_request_origin?
がfalseだった。
valid_request_origin?
の中身を見てみる。rails/actionpack/lib/action_controller/metal/request_forgery_protection.rbdef valid_request_origin? # :doc: if forgery_protection_origin_check # We accept blank origin headers because some user agents don't send it. raise InvalidAuthenticityToken, NULL_ORIGIN_MESSAGE if request.origin == "null" request.origin.nil? || request.origin == request.base_url else true end end
valid_request_origin?
がfalseになるにはrequest.origin
とrequest.base_url
の中身がわかれば理由が分りそうなので出力してみた。
するとrequest.origin
はhttps://〜
なのに対しrequest.base_url
がhttp://〜
となっていた。つまり上のコードの
request.origin == request.base_url
の検証部分でfalseになっていることがわかった。NginxのconfでX-Forwarded-Protoを設定する?
この時点でいろいろ調べると、「NginxからRailsにリクエストが渡される時にHTTPSでNginxにアクセスしてもHTTPとしてRailsに渡されてしまうらしく、これを防ぐために Nginxのconfで
X-Forwarded-Proto
を使ってRailsにHTTPSであることを知らせる」、という方法がすぐ出てくる。やってみた。nginx.conf# もっと本当は書いてあるけど省略 server { listen 80; server_name hoge.jp; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # これを追加 proxy_set_header X-Forwarded-Proto https; }けどダメだった。
試しにRailsでリクエストヘッダを出力してみると"X-Forwarded-Proto": "http"
となっていた。どこかでhttpsからhttpに上書きされている?
その通りで、これはELBの性質上でした。
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/userguide/how-elastic-load-balancing-works.html
今回、ProxyとなるELBから動かしているRailsのサービスに紐づくELBに対してリクエストが送られてくるが、ここはHTTPで送られてくる。
Application Load Balancer および クラシックロードバランサー は、クライアントに返信する応答のプロキシの後のクライアントの入力リクエストからの接続ヘッダーを優先します
とのことで、NginxからELB間のHTTP通信が優先されてリクエストヘッダの
X-Forwarded-For
、X-Forwarded-Proto
、X-Forwarded-Port
が書き換えられてしまっていた。じゃあどうする
requestオブジェクトはRackで作られているらしいのでそこのコードを見てみた。
rack/lib/rack/request.rbdef scheme if get_header(HTTPS) == 'on' 'https' elsif get_header(HTTP_X_FORWARDED_SSL) == 'on' 'https' elsif forwarded_scheme forwarded_scheme else get_header(RACK_URL_SCHEME) end end # 省略 def base_url "#{scheme}://#{host_with_port}" endhttps://github.com/rack/rack/blob/649c72bab9e7b50d657b5b432d0c205c95c2be07/lib/rack/request.rb
base_url
の作られ方から、scheme
がhttps
になれば良い。
schema
がhttps
になるにはいくつか条件があるけれど 、今回はget_header(HTTP_X_FORWARDED_SSL) == 'on'
になるようにすればいけそう!
(HTTP_X_FORWARDED_SSL
はELBに書き換えられる心配もない)
ということで、NginxのリクエストヘッダにX_Forwarded_SSL
を追加してみた。nginx.conf# もっと本当は書いてあるけど省略 server { listen 80; server_name hoge.jp; proxy_set_header Host $host; # この下2つはELBに書き換えられちゃう proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; # これを追加する proxy_set_header X-Forwarded-SSL on; }結果
エラーが出なくなった!
デバッグしてみたらちゃんとリクエストヘッダにX_Forwarded_SSL
が追加されてscheme
はhttps
になっていた。
- 投稿日:2020-09-08T17:42:50+09:00
【Rails DM】DMが送信された時の通知機能を作ろう!
【Rails DM】通知機能を作ろう!
ステップ
1:DM機能を実装しよう
2:通知機能を実装しよう
2−1:モデルを作成しよう
rubyrails g model Notification visitor_id:integer visited_id:integer room_id:integer message_id:integer action:string checked:boolean2−2:作成した通知モデルを、User、Post、Commentと紐付け
UserモデルとNotificationモデルとの関連付け
app/models/user.rbhas_many :active_notifications, class_name: 'Notification', foreign_key: 'visitor_id', dependent: :destroy has_many :passive_notifications, class_name: 'Notification', foreign_key: 'visited_id', dependent: :destroyRoomモデルとNotificationモデルとの関連付け
app/models/room.rbhas_many :notifications, dependent: :destroyMessageモデルとNotificationモデルとの関連付け
app/models/message.rbhas_many :notifications, dependent: :destroyNotificationモデルとUser,Room,Messageモデルとの関連付け
app/models/notification.rbdefault_scope -> { order(created_at: :desc) } belongs_to :room, optional: true belongs_to :message, optional: true belongs_to :visitor, class_name: 'User', foreign_key: 'visitor_id', optional: true belongs_to :visited, class_name: 'User', foreign_key: 'visited_id', optional: true2−3:DM通知の作成メソッド
messages_controller.rbclass MessagesController < ApplicationController def create if Entry.where(user_id: current_user.id, room_id: params[:message][:room_id]).present? @message = Message.new(message_params) # ここから @room=@message.room # ここまでを追加 if @message.save # ここから @roommembernotme=Entry.where(room_id: @room.id).where.not(user_id: current_user.id) @theid=@roommembernotme.find_by(room_id: @room.id) notification = current_user.active_notifications.new( room_id: @room.id, message_id: @message.id, visited_id: @theid.user_id, visitor_id: current_user.id, action: 'dm' ) # 自分の投稿に対するコメントの場合は、通知済みとする if notification.visitor_id == notification.visited_id notification.checked = true end notification.save if notification.valid? # ここまでを追加 redirect_to "/rooms/#{@message.room_id}" end else redirect_back(fallback_location: root_path) end end private def message_params params.require(:message).permit(:user_id, :body, :room_id).merge(user_id: current_user.id) end end2−4:通知の一覧画面の作成
terminalrails g controller notifications indexcontroller/notifications_controller.rbclass NotificationsController < ApplicationController def index @notifications = current_user.passive_notifications @notifications.where(checked: false).each do |notification| notification.update_attributes(checked: true) end end endviews/notifications/index.html.erb<% notifications = @notifications.where.not(visitor_id: current_user.id) %> <% if notifications.exists? %> <%= render notifications %> <% else %> <p>通知はございません</p> <% end %>views/notifications/_notificastion.html.erb<% visitor = notification.visitor %> <% visited = notification.visited %> <div> <%= link_to user_path(visitor) do %> <%= visitor.name %>さんが <% end %> <% if notification.action=='dm' %> あなたにDMを送りました <% end %> </div>参考記事
- 投稿日:2020-09-08T16:06:40+09:00
【Ruby on Rails】ブックマーク(お気に入り登録)機能
目標
投稿に対して、ブックマーク(お気に入り登録)機能を実装します。
開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina前提
※ ▶◯◯ を選択すると、説明等が出てきますので、
よくわからない場合の参考にしていただければと思います。モデルの作成
ターミナル$ rails g model Bookmark user:references post:referencesnull: falseを追加し、データベースへの空の保存を防ぐ。
db/migate/xxxxxxxxxxxxxx_create_bookmarks.rbclass CreateBookmarks < ActiveRecord::Migration[5.2] def change create_table :bookmarks do |t| t.references :user, foreign_key: true, null: false t.references :post, foreign_key: true, null: false t.timestamps end end endターミナル$ rails db:migrate各モデルにそれぞれ追加。
app/models/bookmark.rbvalidates :user_id, uniqueness: { scope: :post_id }
補足
上記validatesを追加することで、重複しての登録を防ぎます。
具体的には、ロード中に2度以上連続で登録しようとすることを防ぎます。app/models/post.rbhas_many :bookmarks, dependent: :destroy def bookmarked_by?(user) bookmarks.where(user_id: user).exists? endapp/models/user.rbhas_many :bookmarks, dependent: :destroy
補足
bookmarked_by?(user)を追加することで、
既にブックマークしているかを検証します。コントローラーの作成
ターミナル$ rails g controller bookmarksapp/controllers/bookmarks_controller.rbclass BookmarksController < ApplicationController before_action :authenticate_user! def create @post = Post.find(params[:post_id]) bookmark = @post.bookmarks.new(user_id: current_user.id) if bookmark.save redirect_to request.referer else redirect_to request.referer end end def destroy @post = Post.find(params[:post_id]) bookmark = @post.bookmarks.find_by(user_id: current_user.id) if bookmark.present? bookmark.destroy redirect_to request.referer else redirect_to request.referer end end end
補足
まずはpost_idを取得し、その後user_idにcurrent_userを紐付けています。
bookmark.present?を挟んでいるのは、2度押しのエラーを回避するためです。config/routes.rbresources :posts, except: [:index] do resource :bookmarks, only: [:create, :destroy] end
補足
postにネストさせています。viewの修正
app/views/posts/show.html.erb<tbody> <tr> <td><%= @post.user.name %></td> <td><%= @post.title %></td> <td><%= @post.body %></td> <td><%= link_to "編集", edit_post_path(@post) %></td> <% if @post.bookmarked_by?(current_user) %> <td><%= link_to "ブックマークを外す", post_bookmarks_path(@post), method: :delete %></td> <% else %> <td><%= link_to "ブックマーク", post_bookmarks_path(@post), method: :post %></td> <% end %> </tr> </tbody>一覧表示させるためには
表示したい場所のコントローラーで下記を記述。
今回はapp/views/homes/mypage.html.erbに表示することとする。app/views/homes/mypage.html.erb<table> <caption>ブックマーク一覧</caption> <thead> <tr> <th>投稿者名</th> <th>タイトル</th> <th>本文</th> </tr> </thead> <tbody> <% @bookmarks.each do |bookmark| %> <tr> <td><%= bookmark.post.user.name %></td> <td> <%= link_to post_path(bookmark.post) do %> <%= bookmark.post.title %> <% end %> </td> <td><%= bookmark.post.body %></td> </tr> <% end %> </tbody> </table>app/controllers/homes_controller.rbdef mypage @bookmarks = Bookmark.where(user_id: current_user.id) end
- 投稿日:2020-09-08T10:45:17+09:00
Rubyの古いgemで自動ファイルアップロード Watirでの対処法
本稿について
WatirでWebサイトに対してファイルアップロードするスクリプトを書いていましたが、
古い環境で情報が見つけづらく困ったところ解決したので備忘録です。環境
CentOS Linux 7
Ruby 2.0.0p648
仕様gemはWatir
ブラウザはFirefoxを使っていますが、Chromeなど、別のブラウザでもやりたいこと
あるWebサイトに対して、Watirをつかって自動スクリプト起動でファイルアップロードさせたい。
アップロード画面ではSelect file というボタンを押して、ファイル選択画面が出た際にそこからファイルを選んでアップロードさせる仕様躓いたこと
アップロード画面からファイル選択をする挙動ができておりません。
OS標準のファイル選択画面が開いた時点で、ブラウザ外の動作になってしまうのかスクリプトの操作が及びません。試したこと
- watir内部でjavascriptを実行できるので、 クリップボードなどを使ってコピペができないか など試しましたがそもそも画面の仕様がスクリプトでのクリップボード経由の ペーストを受け付けていないでいるらしく、ペーストがエラーも吐かずに静かに何も起こらず終了してしまいます。
- 強引にキーイベントをjavascriptから発動させる。 下記のようなコマンドを実行して強制的にEngerキーやTabキーなど打つことできないか試しましたが、 ブラウザ自体にフォーカスがあたってしまっている?ようで、ファイル選択画面がキーコマンドを受け付けないでいます。
browser.execute_script(" document.dispatchEvent( new KeyboardEvent( 'keydown', { keyCode: 86 , ctrlKey: true , key: 'V' }) ); ")(参考:https://ameblo.jp/personwritep/entry-12456996738.html)
などなど試しましたが、対象のファイルを読みに行くなどの動作は行ってくれません。Webサイトの仕様・画面イメージ
ファイルアップロード用の画面が下記で、
Select file
ボタン押す事ができます。すると下記のようなOS標準のファイル選択画面が出て、そこからファイルをアップロードするような作りになっています。
人の手で操作する際は
Select file
ボタンを押してからファイルを選択するか、ドラッグ&ドロップでファイルアップロードすることも可能です。出来た
結果、これでできてしまいました。
$browser.file_field(:id, //).set("filepath\/...\/file.png")参考にした記事
https://stackoverflow.com/questions/15163816/automating-a-file-upload-with-watir-in-chrome-on-osx
https://www.rubydoc.info/gems/watir/1.8.1/Watir%2FContainer:file_field最後に一言
いやWatirて。
- 投稿日:2020-09-08T10:44:57+09:00
[rails]gem 'payjp'の実装手順
1.gem 'payjp'をインストールする
2.orderコントローラー作成記述する
def index @order = Order.new end def create @order = Order.new(price: order_params[:price]) #@orderにprice="1000"値段が入る if @order.valid? # 保存するための条件(空欄じゃない)をクリアすれば支払、データー保存される pay_item#支払をする @order.save#データーを保存する return redirect_to root_path else render 'index' end end private def order_params params.permit(:price, :token)#データー保存を許可したカラム end def pay_item Payjp.api_key = ENV["PAYJP_SECRET_KEY"] # PAY.JPテスト秘密鍵 Payjp::Charge.create( amount: order_params[:price], # 商品の値段 card: order_params[:token], # カードトークン currency:'jpy' # 通貨の種類(日本円) ) end end・token(カード情報)はorderテーブルに保存しない。
なので@orderにはprice: order_params[:price]で
ユーザーが入力したprice値段の情報が代入される・pay_itemにより支払完了し
@order.saveでprice:1000、値段の情報をテーブルに保存する3モデルにバリデーションの情報を記述する
class Order < ApplicationRecord validates :price, presence: true end・バリデーションとは?データーをテーブルに保存する際の条件
・今回はpriceの入力欄が空の状態で送信すると
データーを保存させないようにしている。・token(クレジットカード情報)はテーブルに保存しないので、バリデーション
保存の条件を記述しない。
- 投稿日:2020-09-08T10:21:47+09:00
PG::ConnectionBad: could not connect to server: No such file or directory
PG::ConnectionBad: could not connect to server: No such file or directoryというエラーがでた
解決法
1,ターミナルでdesktopの前に行く。
2,
$ cd /usr/local/var/log/
3,
$ cat postgres.log
そうすると以下のようなエラーがでる
dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib
Referenced from: /usr/local/bin/postgres
4,以下の記事を参考に実行
https://qiita.com/eightfoursix/items/bf11693b085eced95e294-1
$ brew upgrade
4-2
$ brew postgresql-upgrade-database
自分の場合は、これで解決しました。
- 投稿日:2020-09-08T10:14:54+09:00
【RSpec】 Factory Botを使いこなそう
FactoryBotの基本のキ
bin/rails g factory_bot:model user
のようにFactoryBotでデータを作成するファイルが生成されます。今回は
spec/factories/users.rb
に以下のようなファイルが生成されると思います。spec/factories/users.rbFactoryBot.define do factory :user do end endこのなかに作りたいデータを詰め込んでいきます。
spec/factories/users.rbFactoryBot.define do factory :user do name {"佐藤"} age {20} height {170} end end実際に使ってみよう。
spec/models/user.rbrequire 'rails_helper' RSpec.describe User, type: :model do it "is valid with a name, age and height" do expect(FactoryBot.build(:user)).to be_valid end endこんな感じで簡潔に書くことができます。ちなみに、FactoryBotを使わない場合は下記のようになります。
spec/models/user.rbrequire 'rails_helper' RSpec.describe User, type: :model do it "is valid with a name, age and height" do user = User.new( name: "佐藤", age: 20, height: 170, ) expect(user).to be_valid end endこんな感じになってしまい、行数が多くなってしまいます。
とはいえ読みやすくなるとはいえ、FactoryBot内にデータの内容が隠されてしまうため、ユースケースによって使うか使わないか選択して行きましょう。
オーバーライド
スペックを書くファイルの中で、データをオーバーライド(上書き)することができます。
spec/models/user.rbrequire 'rails_helper' RSpec.describe User, type: :model do it "is invalid without a name" do user = FactoryBot.build(:user, name: nil) user.vaild? expect(user.errors[:name]).to include("can't be blank") end endFactoryBotの内容に上書きして、
name
をnil
にしています。シーケンスを使ってユニークなデータを
例えば、「メアド」はユニークな値であるべきです。しかし、FactoryBotをそのまま使ってしまうと毎回同じ値が入るため、バリデーションに引っかかってしまいます。(意図せず。)
その問題に対処するために、「シーケンス」が用意されています。
spec/factories/users.rbFactoryBot.define do factory :user do name {"佐藤"} age {20} height {170} #emailにシーケンスが使われています。 sequence(:email) {|n| "test#{n}@example.com"} end endこうするとで新しいユーザーが作成されるたびに
test1@example.com
,test2@example.com
と常にユニークな値を入れることができます。ファクトリーをもっと多様化する
例えば、高齢者の場合をテストしたい、身長が高い人をテストしたい、みたいなことが出たとします。その細かい問題をファクトリー内で吸収することができます。主に二つの方法があります。
継承を使う
spec/factories/users.rbFactoryBot.define do factory :user do name {"佐藤"} age {20} height {170} sequence(:email) {|n| "test#{n}@example.com"} # 高齢者を対象とするデータ factory :senior do age {75} end # 高身長が対象とするデータ factory :tall do height {190} end end end
FactoryBot.build(:user, :senior)
やFactoryBot.build(:user, :tall)
みたいに使うことができます。traitを使う。
僕はこっちの方が好きです。理由はFactoryBot内に書くことで短縮できる,何が「違う」のかわかるからです。とにかく見て行きましょう!
spec/factories/users.rbFactoryBot.define do factory :user do name {"佐藤"} age {20} height {170} sequence(:email) {|n| "test#{n}@example.com"} trait :senior do age {75} end trait :tall do height {190} end end end
FactoryBot.build(:user, :senior)
のように書くことで呼び出すことができます。こうすることで、そのデータの特徴が明示されているので、可読性が高いですよね。
コールバック
FactoryBotでは動的な動きも表現することができます。下記のコードをみてください。
spec/factories/users.rbFactoryBot.define do factory :user do name {"佐藤"} age {20} height {170} sequence(:email) {|n| "test#{n}@example.com"} trait :with_tasks do after(:create) { |user| create_list(:task, 5, user: user) } end end end
FactoryBot.build(:user, :with_tasks)
とすることでuserに関連したtaskを作ることができます。
- 投稿日:2020-09-08T08:38:38+09:00
rails tutorial 第6章
はじめに
独学でrails tutorialを進めていく過程を投稿していきます。
進めていく上でわからなかった単語、詰まったエラーなどに触れています。
個人の学習のアウトプットなので間違いなどあればご指摘ください。
初めての投稿なので読みにくいところも多々あるかと思いますがご容赦ください。
第6章 ユーザーのモデルを作成する
6.2.2 存在性を検証する
存在性の検証は:presenceで行うようです。
tutorialではよく省略されたコードが示されていますのでしっかり理解するまでは自分でフォローもしておこうかと思います。validates :name, presence: true #すべて括弧をつけると validates(:name, {presence: true}) #第一引数には検証するカラム名を、第二引数には検証する内容
問題発生!!
リスト6.13のtestを実行するとRuntimeError: RuntimeError: database is lockedと表示されエラーになってしまう。
解決のために試したこと
参考記事1
https://qiita.com/kambe0331/items/1eaf2383b39c721e7283
こちらの記事を参考にし、dbファイル下のtest.sqlite3というファイルの名前を一旦変更し再度元の名前に戻しました。結果
上手くいかず、、、次に
参考記事2
https://stackoverflow.com/questions/7154664/ruby-sqlite3busyexception-database-is-locked/62730905#62730905
こちらの記事を参考にし、DB Browser for SQlite、サーバー、プロンプトなどを一度全て終了して、改めて起動。結果
テストをクリア出来ました。余談
一時的にテストをクリアできましたが、どうやら根本的には解決出来ていなかったようで、こちらのエラーこれからも頻発します。エラーの解決方法は別の記事にまとめました。
https://qiita.com/shun_study_p/items/fbb4cb2d4c392063c9a96.2.3 長さを検証する
長さの検証は:lengthで行うようです。
validates :name, presence: true, length: { maximum: 50 } #わかりやすく括弧をつけると validates(:name, {presence: true, length: { maximum: 50 }})先程と同様、慣れるまでは括弧を自分でフォローしておきます。
6.2.5 一意性を検証する
一意性の検証は:uniquenessで行うようです。
:case_sensitiveというオプションを使うことで、大文字小文字を区別するか指定が出来るようです。case_sensitive: falseとすることで:uniquenessの値が一意かどうかの検証で大文字と小文字を区別しないというオプションを追加しています。
問題発生!!
最後にrails testを実行したところMigrations are pending. To resolve this issue, run: bin/rails db:migrate RAILS_ENV=testとのエラーが発生しました。
素直に表示されたコマンド実行するとmigrateできないとのエラーが、、、解決
以下の記事を参考にし
http://kzlog.picoaccel.com/post-995/rails db:rollback RAILS_ENV=test rails db:migrate RAILS_ENV=test上記のコマンドを実行すると正常に動作しました。
終わりに
今回は少しエラーに躓きました。
しかし、6章の内容はしっかり理解が出来ました。
- 投稿日:2020-09-08T08:14:25+09:00
Rails 6で認証認可入り掲示板APIを構築する #3 RSpec, FactoryBot導入しpostモデルを作る
←Rails 6で認証認可入り掲示板APIを構築する #2 gitとrubocop導入
RSpec, FactoryBotのインストール
前回の続きから。
テストに使うRSpecとFactoryBotを入れます。Gemfilegroup :development, :test do + gem "rspec-rails" + gem "factory_bot_rails" end
$ bundleインストールできたので初期化をします。
$ rails g rspec:install ... Running via Spring preloader in process 6770 create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb今後modelやcontrollerを生成した時に、一緒に自動生成されるRSpecの制御をします。
最低限のテストに収めるためmodelとrequestのみでいこうと思うので、それ以外を使わないよう設定します。config/application.rbclass Application < Rails::Application ... + config.generators do |g| + g.test_framework :rspec, + view_specs: false, + helper_specs: false, + controller_specs: false, + routing_specs: false + end end ...ついでにFactoryBotをRSpecの中でクラスを書かなくてもメソッドが使える設定をします。
spec/rails_helper.rbRSpec.configure do |config| + config.include FactoryBot::Syntax::Methods ...参考:RailsアプリへのRspecとFactory_botの導入手順
ここまでいったらrubocop動かしてエラー潰し、エラーがゼロになったらgit commitしておきましょう。
なおrubocop -a
の-aは自動修正可能なものを自動修正するコマンドなので、1回目大量のエラーが出て場合、もう1回動かすと自動修正後で数が一気に減るはずです。postモデルの生成
前準備が非常に長かったですが、これでようやく準備が整ったのでmodelを作っていきます。
$ rails g model Post subject:string body:textこちらのコマンドを実行するとmodel, migration, spec, factory_botの4ファイルが
生成されます。$ rails db:migrateもし実行時に以下エラーが出たら、postgresが止まっているので起動します
rails aborted! PG::ConnectionBad: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql ... $ sudo service postgresql95 startpryを入れる
rails consoleコマンドを実行時、標準のirbよりもpryの方ができることが増えます。
Gemfilegroup :development, :test do + gem "pry-rails" + gem "pry-byebug" ... end$ bundlerails consoleでpostの保存ができるか試す
controllerまで実装して動作確認だと手間がかかるので、rails consoleでmodelがDBに保存・読み込みができるか試します。
$ rails c ... [1] pry(main)> Post.create!(subject: "hoge", body: "fuga") [2] pry(main)> posts = Post.all Post Load (0.6ms) SELECT "posts".* FROM "posts" => [#<Post:0x0000000006e89850 id: 1, subject: "hoge", body: "fuga", created_at: Sat, 05 Sep 2020 13:50:01 UTC +00:00, updated_at: Sat, 05 Sep 2020 13:50:01 UTC +00:00>][1]でpostを1件保存し、[2]で全件取得しました。
どうやら正常にcreate, readができていそうですね。続きは次回。
【連載目次へ】
- 投稿日:2020-09-08T01:19:57+09:00
Ruby on RailsにおけるServiceクラスのススメ
こんにちは、@hairgaiです。
今回は、賛否両論あるServiceクラスについての自分的な使い方を書いていこうと思います。Serviceクラスとは
DDD(ドメイン駆動設計)でのサービスから派生している(と勝手に認識している)、ある一つの機能を記述するクラス郡です。
詳しくは説明している人がたくさんいらっしゃるので割愛しますが、ビジネスロジックをモデルとコントローラーの中間でキレイに書けるので、僕はよく使っています。
今回は(僕の使い方は間違ってるかもしれませんが)、自分的な使い方及びそのメリットと思われる部分を書いていきます。基本的な使い方
まず、基本的な使い方を、コード例と共に紹介しようかなと思います。(これが正解かどうかは正直わかりませんが、見やすいのでいいかなと思ってます)
例えば、SNSなどで「フォローをする」という機能をService層として1ファイルに記述すると、こんな感じにになるかと思います。
※重ねていいますが、これが正解とかじゃないです。class FollowService attr_reader :user, :target_user attr_accessor :follow def initialize(user, target_user) @user = user @target_user = target_user end def perform check! create_follow! run_after_worker! end private def check! check_following! check_blocking! end def check_following! return true unless user.following?(target_user) raise ArgumentError, 'User following target user' end def check_blocking! return true unless user.blocking?(target_user) raise ArgumentError, 'User blocking target user' end def create_follow! self.follow = user.follows.create!(target_user: target_user) end def run_after_worker! AfterFollowWorker.perform_in(0.2.seconds, follow.id) end endピュアなRubyのクラスで作る
基本的に何かGem等を使って作ることは、僕はしていないです。
ピュアRubyでの実装にすることで「実装の理解に対する障壁を下げる」効果を狙っています。
Serviceクラスは(重い機能になると)ロジックが複雑になりがちなので、なるべくシンプルに作成し、誰が見てもすぐに理解できるように心がけています。クラス名を定める
命名に好みがあると思いますが、機能を象徴するクラスであるので
[動詞]([目的語])Service
で統一しています。
命名規則をつけることで機能が推論しやすくなるというメリットがあります。publicなメソッドはperformのみにする
ここらへんも好みがあると思います(
call
とかにしたりする人も多いです)が、基本的にはpublicなメソッドを一つだけ生やし、それ以外は呼べないものとします。
これは、Serviceクラスは単一の機能を象徴するクラスであり、それを使用することで実現できる機能を単一のものと限定するためです。
この単一のpublicメソッドは結構いろいろな方が言っていますが、僕も設計時点において迷いが全くなくなり実装スピードが格段に上がったので採用しています。publicなメソッドで呼ぶのはprivateメソッドのみ
これも見通しが良くなる + 1メソッドごとの責務が軽くなり、ガード節が使いやすくなったりするので採用しています。
ここらへんは好みの分かれるところだと思います。後処理等へのアプローチを単一にする
上のFollowServiceでも書いていますが、業務で使用する以上はユーザさんに対するレスポンスを一番に考えます。
そういった場合のアプローチとしては「1レスポンス中には必要な処理のみを行う」というものがあり、後続処理などはジョブとしてキューに格納し、ジョブサーバ等に処理させることになります。
その際に、ControllerやModel等色々な場所にジョブをコールする処理が散らばると、プロジェクト全体での見通しが悪くなります。そこで、
HogeService
の後処理のジョブはAfterHogeJob
にする、というような命名規則にし、Serviceクラスでのみコールするという決まりにすることで、全体の見通しを良くすることができます。Controllerの肥大化の解消
言うまでもないですね。
class FollowsController < ApplicationController def create target_user = user.find(params[:target_user_id]) service = FollowService.new(current_user, target_user) service.perform redirect_to user_path(target_user) end endModelの肥大化の解消
こちらも言うまでもないですね。
Modelに書いていたものを全部Serviceクラスに持っていき、モデルがデータの関連付けやバリデーション、その他単一モデルに関するメソッド等のみになります。
そのため、モデルからロジックの多いメソッドがなくなり、肥大化した見づらいモデルというものがなくなります。あとがき
こうして改めて書いてみると、僕は色々と責任をServiceクラスに負わせている書き方をしているんだなぁ、と思います。
Serviceクラスは必要ない、等々議論の余地はあると思いますが、こういった設計等の話はあくまで手法の一つなので、自分たちのビジネスに合わせて適切に使用できると良いですね。
- 投稿日:2020-09-08T00:17:36+09:00
[ruby]引数をつけた際のメソッドの呼び出し
概要
bitcoinの自動売買ツールを作成している時に、メソッドに引数をつけて使うことがあったので、記録しておきます。
メソッドの定義
メソッドの定義は以下のような式になります。
def メソッド名(変数1, 変数2, ...) 実行する処理 endメソッドの呼び出し
メソッドを呼び出すときの式は以下のような形です。
メソッド名(引数1, 引数2, ...)実際に見てみます
number.rbdef number(a,b) return a * b end puts number(3,4) #実行結果は12になるnumberメソッドの引数として、aに3、bに4が呼び出されています。
結果、3×4が実行されて、12が出力されます。
- 投稿日:2020-09-08T00:10:31+09:00
Cを使ってRubyのメソッドを書く その1
目次
Cを使ってRubyのメソッドを書く その1 <- ここ
Cを使ってRubyのメソッドを書く その2 (Numo::NArray)はじめに
C++でRubyの拡張ライブラリを書く方法は、「C++を使ってRubyのメソッドを書く」にありますので参考にしてください。C++さえ書ければほとんど苦労せずにライブラリが作成できますので、自分で一から書かれるのでしたらそちらをお勧めします。
ここでは、Cで書かれた関数を拡張ライブラリにする方法を紹介します。C++でもCと同様の書き方ができますので、すでにCで書かれたライブラリがある場合にも使うことができます。
- 2. はdouble, float, intなどの単純な変数に受け渡し、3.で文字列に受け渡し、4.で既存のライブラリを拡張ライブラリにする方法を紹介します。 配列を受け渡す方法は(その2)を参考にしてください。
1. コンパイラが提供する関数を呼び出す
SWIGインターフェース定義ファイルを書きます。
上の%{..%}の中にはヘッダファイルを読み込むか、ヘッダファイルに相当することを書きます。test.i%module test // モジュール名 最初の文字は大文字に変換される %{ #include <math.h> %} %include "typemaps.i" extern double floor(double x); // double modf(double value, double *iptr); ポインタで値を受け取る時は*OUTPUTに変更 extern double modf(double value, double *OUTPUT);下の方にはRubyから呼び出す関数を書いています。math.hには多くの関数のヘッダが書かれていますが、その中からfloorとmodfをRubyから利用できるようにします。
modfに2番目の引数はポインタになっておりdouble型の値を返します。ポインタでは入力、出力、入出力が可能で、*INPUT, *OUTPUT, *INOUTと記述することでそれぞれの機能を持たせられます。extconf.rbrequire 'mkmf' create_makefile("test") # モジュール名と同じにMakefikeを作成するためのRubyプログラムです。
以上のファイルを同じフォルダの中に入れ、次のコマンドを実行します。
swig -ruby test.i ruby extconf.rb make以上で、test.bundle(拡張子はOSにより異なります)ができあがります。
テスト用プログラムです。test1.rbrequire "./test" p Test.floor(2.3) p Test. modf(2.3)2. 自作の関数を呼び出す
単純な変数を受け渡しする関数を書いてみました。ごく普通のCの関数です。2倍の値を返す関数です。ポインタは使っていません。
test2.cdouble twicefold_d(double x){ return(x*2.0); }test.i%module test %{ double twicefold_d(double x); %} double twicefold_d(double x);ヘッダファイルは作っていませんので、%{..%}の中にヘッダファイルに相当すること書きます。
extconf.rbファイルとコマンドは上と同じものを使ってください。
フォルダの中に.cや.cppなどのプログラムファイルがありましたら、全部コンパイルてリンクしようとしますので、不必要なファイルは入れておかないようにしましょう。テスト用プログラムです。
test2.rbrequire "./test" p Test.twicefold_d(3.4)3. 自作の関数を呼び出す 文字列を渡す
文字列も関数に簡単に渡すことができます。
test3.c#include "test3.h" int string_length(char* str){ return(strlen(str)); }test3.h#include <string.h> int string_length(char* str);ここではヘッダファイルを作っています。そう手間はかかりませんので、ヘッダファイルを作っておいた方が何かと便利なように思います。
test.i%module test %{ #include "test3.h" %} %include test3.h同じくextconf.rbファイルとコマンドは上と同じものを使ってください。
test1.rbrequire "./test" p Test.string_length("abcd")4. 既存ライブラリを利用できるようにする
GSLの関数gsl_hypotとgsl_hypot3を使えるようにします。GSLのヘッダファイルを読み込んで2つの関数のインターフェースを定義しています。2つの関数はヘッダファイルからそのままコピーしているだけで変更はしておりません。
test.i%module test %{ #include "gsl/gsl_math.h" %} extern double gsl_hypot(const double x, const double y); extern double gsl_hypot3(const double x, const double y, const double z);extconf.rbrequire 'mkmf' dir_config("gsl") have_header("gsl/gsl_math.h") have_library("gsl") # libgsl.soをリンクする create_makefile("test")GSLのヘッダファイル読み込みとlibgsl.soをリンクする必要がありますので、そのための3行を追加しています。コマンドは上と同じで大丈夫なことが多いのですが、ヘッダファイルとlibgsl.soの場所がわからわからない時には次のようにruby extconf.rbに後にパスを書きます。
ruby extconf.rb -- --with-gsl-dir=/path --with-gsl-include=/path/include --with-gsl-lib=/path/lib/path/include/gsl/gsl_math.hと/path/lib/libgsl.soのような場所にファイルがある時には
--with-gsl-dir=/pathで両方いっぺんに指定できます。下2つは片方ずつ指定できます。test4.rbrequire "./test" p Test.gsl_hypot(3, 4) p Test.gsl_hypot3(3, 4, 5)CentOS 8.2 Ruby 2.6.6
macOS 10.13.6 Ruby 2.7.1
SWIG 4.0.2
- 投稿日:2020-09-08T00:02:13+09:00
ゲッターについての備忘録
class Fruits def initialize(name, color) @name = name @color = color end def name #ゲッター @name #@nameの値を取得 end def color #ゲッター @color #@colorの値の取得。 end end class InfoFruits def initialize(fruits)#仮引数、実引数を受け取っています。 @fruits = fruits #実引数をインスタンス変数に代入することで定義を行います。 end def fruits @fruits #self.fruitsとは、インスタンス自身です。 end #下記において、インスタンスを利用するために、ここで一度インスタンスの値の取得を行なっています。 def info_fruits self.fruits.each do |fruit| puts "#{fruit.name}は#{fruit.color}です。" #配列fruitsには、インスタンスの値nameとcolorが含まれている。 end end end fruits = [] fruit_name = "りんご" fruit_color = "赤色" fruits << Fruits.new(fruit_name, fruit_color) #@nameの値と@colorの値を戻り値として配列に代入しています。 kind_fruit = InfoFruits.new(fruits)#その配列を実引数として渡しています。 kind_fruit.info_fruits #インスタンスメソッドinfo_fruitsの呼び出しです。class Fruits def initialize(name, color) @name = name @color = color end def name @name end def color @color end end class InfoFruits def initialize(fruits) @fruits = fruits end # def fruits # @fruits # end def info_fruits @fruits.each do |fruit| #ゲッターを用いない場合、配列が代入されたインスタンス変数を置くと、出力結果は同じになります。 puts "#{fruit.name}は#{fruit.color}です。" end end end fruits = [] fruit_name = "りんご" fruit_color = "赤色" fruits << Fruits.new(fruit_name, fruit_color) name_color_fruit = InfoFruits.new(fruits) name_color_fruit.info_fruits誤った認識をしている箇所、認識が不足している部分について、ご指摘頂けましたら、幸いに存じます。