- 投稿日:2021-01-13T22:38:19+09:00
Railsでtext_areaに入力した文章を改行込で表示させる方法
はじめに
Ruby on Railsにて投稿機能のあるアプリを作成しました。
投稿画面にはRailsのヘルパーメソッドであるform_withメソッドを用いてフォームを実装。その際、text_areaで、複数行の入力が可能な入力欄を作成したので、改行を含めた文章を入力し、それを表示させようとしたところ、改行がされていない文章が表示されてしまいました。
今回はその問題を解決する方法を調べたので記事に残しておきます。環境
macOS Catalina バージョン 10.15.7
Ruby 2.6.5
Ruby on Rails 6.0.3.4前提として
フォームのコードは以下の通り。
app/views/shared/_form.html.erb<%= form_with(model: word, local: true) do |f| %> <%= f.text_area :remarks, placeholder: "備考", rows: "7" %> <%= f.submit "Register" %> <% end %>念の為、このフォームで送られてくるデータに改行が含まれているか、Railsのデバックツールであるpry-railsを用いて確認してみました。
まず、以下の改行を含めた文章をフォームで送信しました。おはよう こんにちはここで、コントローラーに記述したbinding.pryのところで一旦処理が止まるので、コンソールでparamsを実行し、送られてきたパラメーターを確認したところ、
このように、改行した部分に改行コードである「\r\n」が含まれており、ちゃんとデータとして送られてきていることが分かります。そして、送られてきたデータを表示するためのコードが以下なのですが、
app/views/show.html.erb<%= @word.remarks %>このままだと改行が含まれず、以下のような表示になってしまいます。
おはよう こんにちはこの問題を解決する方法を、以下2通りまとめました!
①simple_formatメソッド
以下のサイトを参考にしました。
- https://railsdoc.com/page/simple_format
- https://www.ryotaku.com/entry/2019/06/25/%E3%80%8Csimple_format%E3%80%8D%E3%82%84%E3%80%8Csafe_join%E3%80%8D%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%80%81%E6%AD%A3%E5%B8%B8%E3%81%AB%E6%94%B9%E8%A1%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B
- https://beryus.hatenablog.com/entry/2020/10/06/004936
simple_formatはRailsのヘルパーメソッドで、下記の機能を有します。
- 文字列を<p>で括る
- 改行は<br>を付与
- 連続した改行は</p><p>を付与
では、show.html.erbにsimple_formatを追記します。
app/views/show.html.erb<%= simple_format(@word.remarks) %>そして、ブラウザを更新し改めて確認してみると、
おはよう こんにちはこのように改行がされたまま表示がされました!
ChromeのデベロッパーツールのElementsパネルを確認すると、
たしかに、文字列がpタグで括られており、改行にはbrタグが付与されています。そこで、試しに以下のようにいくつか連続した改行の場合を調べてみました。
おはよう こんにちはしかし、表示を確かめると、
おはよう こんにちはこのように、連続した改行は実際に入力した通りには表示されませんでした。
ちなみに、Elementsパネルを確認すると、以下のようにpタグが付与されていました。
なので、この場合は改行ではなく、「おはよう」と「こんにちは」それぞれが1つの段落として表示されている事になります。②safe_joinメソッド
以下のサイトを参考にしました。
- https://www.ryotaku.com/entry/2019/06/25/%E3%80%8Csimple_format%E3%80%8D%E3%82%84%E3%80%8Csafe_join%E3%80%8D%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%80%81%E6%AD%A3%E5%B8%B8%E3%81%AB%E6%94%B9%E8%A1%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B
- https://qiita.com/kamotetu/items/1aa94994985c720668e4
safe_joinメソッドもRailsのヘルパーメソッドの一つです。
simple_formatと違い、pタグで括らず、また連続した改行を表示させることができます。まず、先ほどの記述を以下のように書き換え。
app/views/show.html.erb<%= safe_join(@word.remarks.split("\n"),tag(:br)) %>※ splitは文字列を分割するメソッド。引数に区切り文字を指定することで、その区切り文字のところで文字列を区切る。
あとは、同じように複数の連続した改行を含む文章を入力してみると、おはよう こんにちはきちんと入力した通りの表示がされました!!
Elementsパネルを確認すると、
brタグで改行されているのが分かります。最後に
色々調べる中で、HTMLやタグ、エスケープ処理などの記事を目にしました。これらの理解が深まったと同時に、知らない知識に触れる機会も多かった為、さらに派生させ知識をより深めていきたいと思います。
誤った箇所などありましたら、ご指摘いただけると幸いです。
- 投稿日:2021-01-13T22:38:19+09:00
text_areaに入力した文章を改行込で表示させる方法
はじめに
Ruby on Railsにて投稿機能のあるアプリを作成しました。
投稿画面にはRailsのヘルパーメソッドであるform_withメソッドを用いてフォームを実装。その際、text_areaタグで、複数行の入力が可能な入力欄を作成したので、改行を含めた文章を入力し、それを表示させようとしたところ、改行がされていない文章が表示されてしまいました。
今回はその問題を解決する方法を調べたので記事に残しておきます。環境
macOS Catalina バージョン 10.15.7
Ruby 2.6.5
Ruby on Rails 6.0.3.4前提として
フォームのコードは以下の通り。
app/views/shared/_form.html.erb<%= form_with(model: word, local: true) do |f| %> <%= f.text_area :remarks, placeholder: "備考", rows: "7" %> <%= f.submit "Register" %> <% end %>念の為、このフォームで送られてくるデータに改行が含まれているか、binding.pryを用いて確認してみました。
まず、以下の改行を含めた文章をフォームで送信しました。おはよう こんにちはここでbinding.pryを用いて、コンソールで「params」を実行し、パラメーターを確認したところ、
このように、改行した部分に改行コードである「\r\n」が含まれており、ちゃんとデータとして送られてきていることが分かります。そして、送られてきたデータを表示するためのコードが以下なのですが、
app/views/show.html.erb<%= @word.remarks %>このままだと改行が含まれず、以下のような表示になってしまいます。
おはよう こんにちはこの問題を解決する方法を、以下2通りまとめました!
①simple_formatメソッド
以下のサイトを参考にしました。
- https://railsdoc.com/page/simple_format
- https://www.ryotaku.com/entry/2019/06/25/%E3%80%8Csimple_format%E3%80%8D%E3%82%84%E3%80%8Csafe_join%E3%80%8D%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%80%81%E6%AD%A3%E5%B8%B8%E3%81%AB%E6%94%B9%E8%A1%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B
- https://beryus.hatenablog.com/entry/2020/10/06/004936
simple_formatはRailsのヘルパーメソッドで、下記の機能を有します。
- 文字列を<p>で括る
- 改行は<br>を付与
- 連続した改行は</p><p>を付与
では、show.html.erbにsimple_formatを追記します。
app/views/show.html.erb<%= simple_format(@word.remarks) %>そして、ブラウザで更新し改めて確認してみると、
おはよう こんにちはこのように改行がされたまま表示がされました!
ChromeのデベロッパーツールのElementsパネルを確認すると、
たしかに、文字列がpタグで括られており、改行にはbrタグが付与されています。そこで、試しに以下のようにいくつか連続した改行の場合を調べてみました。
おはよう こんにちはしかし、表示を確かめると、
おはよう こんにちはこのように、連続した改行は実際に入力した通りには表示されませんでした。
ちなみに、Elementsパネルを確認すると、以下のようにpタグが付与されていました。
なので、この場合は改行ではなく、「おはよう」と「こんにちは」それぞれが1つの段落として表示されている事になります。②safe_joinメソッド
以下のサイトを参考にしました。
- https://www.ryotaku.com/entry/2019/06/25/%E3%80%8Csimple_format%E3%80%8D%E3%82%84%E3%80%8Csafe_join%E3%80%8D%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%80%81%E6%AD%A3%E5%B8%B8%E3%81%AB%E6%94%B9%E8%A1%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B
- https://qiita.com/kamotetu/items/1aa94994985c720668e4
safe_joinメソッドもRailsのヘルパーメソッドの一つです。
simple_formatと違い、pタグで括らず、また連続した改行を表示させることができます。まず、先ほどの記述を以下のように書き換え。
app/views/show.html.erb<%= safe_join(@word.remarks.split("\n"),tag(:br)) %>※ splitは文字列を分割するメソッド。引数に区切り文字を指定することで、その区切り文字のところで文字列を区切る。
あとは、同じように複数の連続した改行を含む文章を入力してみると、おはよう こんにちはきちんと入力した通りの表示がされました!!
Elementsパネルを確認すると、
brタグで改行されているのが分かります。最後に
色々調べる中で、HTMLやタグ、エスケープ処理などの記事を目にしました。これらの理解が深まったと同時に、知らない知識に触れる機会も多かった為、さらに派生させ、知識をより深めていきたいと思います。
誤った箇所などありましたら、ご指摘いただけると幸いです。
- 投稿日:2021-01-13T21:39:58+09:00
Rails の Carrierwave を使用した画像複数アップロード機能
備忘録のため記述しています。
Carrierwave という gem の導入
carrierwaveuploader/carrierwave
Gemfile に以下を記述
gem "carrierwave", "~> 2.0"終わったらターミナルにて bi
bundle installUploader の作成
bundle exec rails g uploader Images下記が作成される。
images_uploader.rbアップロードされるファイルの設定を色々弄れるけど今回は見送り。
MVC 設定
Post モデルに対して Memory というモデルで画像登録をできるようにしている
Model
post.rb
post.rbclass Post < ApplicationRecord has_many :memories accepts_nested_attributes_for :memories, allow_destroy: true validates :title, presence: true endaccepts_nested_attributes_for :memories の設定で posts_controller 上で memories を登録できるようにしている。
memory.rb
class Memory < ApplicationRecord belongs_to :post mount_uploader :image, ImagesUploader endmount_uploader は carrierwave の設定。これで簡単にアップロードできるようになる。
Controller
posts_controller.rb
class PostsController < ApplicationController def new @post = Post.new # @post.memories.build とすることで post に紐づいた memories を保存する準備が整う @post_memory = @post.memories.build end def create post = Post.new(post_params) if post.save! # 以下は memories に保存する処理。 each 文で複数の画像を保存可能。 params[:memories][:image].each do |image| post.memories.create(image: image, post_id: post.id) end end redirect_to root_path end private def post_params params.require(:post).permit(:title, memories_attributes: [:image]).merge(user_id: current_user.id) end endView
new.html.erb
<%= form_for @post, local: true, html: {class: "form_area"} do |f| %> <div class="form_area__field"> <%= f.text_area :title, id: "post_text", placeholder: "投稿内容を入力", rows: 10%> <div class="form_area__image_field"> <%= f.fields_for :memories do |m| %> <%= m.label :image, "画像" %> <%= m.file_field :image, multiple: true, name: "memories[image][]" %> <%= hidden_field :memories, :post_id, value: @post.id %> <% end %> </div> <div class="form_area__hidden_field"> <%= hidden_field :post, :user_id, value: current_user.id %> </div> <div class="form_area__action"> <%= f.submit "投稿", class: "form_area__action__btn" %> </div> </div> <% end %>fields_for で1回の投稿で複数のクラスを保存できる。
multiple: true で複数の画像を投稿できるように設定している。
表示するには?
<% @post.memories.each do |m|%> <%= image_tag m.image.url %> <% end %>上記で表示できる。
- 投稿日:2021-01-13T20:39:01+09:00
パーシャルでインスタンス変数は使わない
初学者です。
コントローラの修正をしたときに、どのコントローラと結びついているのかわからなくなってしまったので、備忘録として残します。index.html.erb<%= render 'layout/header' %> #ダメな例_header.html.erb<%= @product.name %> #ダメな例
- モデルのデータと関連付けられるので、使いづらくなる。
- コントローラ側でインスタンス変数の名前や動き方を変更したときにパーシャル側の変更もしなければいけなくなる。
対処
index.html.erb<%= render 'layout/header', product_name: @product.name %>_header.html.erb<%= product_name %>これでできました!!!
参考
https://qiita.com/mom0tomo/items/e1e3fd29729b2d112a48
locals:
を使ったりもするみたいです。その場合はpartial:
もつける。
- 投稿日:2021-01-13T20:31:31+09:00
ポリモーフィック関連付けをしたModelでのfactoryの作り方
ほぼ自分用なので簡易的に記します。
userとprojectに対してコメントができる。
comment.rbbelongs_to :commentable, polymorphic: true belongs_to :commenter, class_name: 'User'user.rbhas_many :comments, as: :commentable, dependent: :destroypreject.rbhas_many :comments, as: :commentable, dependent: :destroy両方のfactoryを書いてあげれば良い
factories/comment.rbFactoryBot.define do factory :project_comment, class: 'Comment' do association :commenter, factory: :user association :commentable, factory: :project commentable_type { 'User' } comment { 'Sample Comment' } end factory :user_comment, class: 'Comment' do association :commenter, factory: :user association :commentable, factory: :user commentable_type { 'User } comment { 'Sample Comment' } end endlet(:user_comment) { FactoryBot.create(:user_comment) }で呼び出せる。
ポリモーフィック関連は関連するモデルの追加が簡単であるべき、
よってfactoryの追加も簡単であるべきだと思う。
このように書けば、今後関連モデルが増えてもcomment_typeを増やして対応できる。factories/comment.rbFactoryBot.define do comment_type = [:user, :project] comment_type.each do |type| factory :"#{type}_comment", class: 'Comment' do association :commenter, factory: :user association :commentable, factory: type commentable_type { type.to_s.camelize } comment { 'Sample Comment' } end end end逆にcomment_typeを増やしても対応できない場合は、ポリモーフィックにすべきではない。
関連モデルによってメソッドやfactoryの構成が変わるようでしたらポリモーフィックではなく,STIなどを検討してみればいかがでしょうか。
- 投稿日:2021-01-13T18:50:58+09:00
railsとDockerで(Basic認証)環境変数
Docker上でBasic認証
Docker上でBasic認証を実装したがサイトに入ることができなかったため理由を考えてみた。
結論
超簡単絶対に下まで読んでください。Docker上で環境変数を設定してあげる
docker-compose.ymlversion: '3' services: web: environment: BASIC_AUTH_USER: 'admin' #仮のuser BASIC_AUTH_PASSWORD: '0000' #仮のpassword理由として
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base before_action :basic_auth private def basic_auth authenticate_or_request_with_http_basic do |username, password| username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]# 環境変数を読み込む記述 end end end大体上のような記述でBASIC認証を実装していると思う。
ターミナル上で環境変数を設定してあげて呼び出しているかもしれないが、Docker上でも環境変数を設定してあげないといけない。
理由としてはDockerは今使っているpcとは別に仮想のマシンとしてコンテナを作りその上でアプリを動かしているから。
感想一安心かと思ったがちょっと待ってほしい。
Gitにあげれなくないか。。?
今の状態でマージしてしまうとGitのリポジトリからBasic認証のuseridとpasswordが丸見えになっていてセキュリティも何もない。
なので
結論
docker-compose.ymlversion: '3' services: web: environment: BASIC_AUTH_USER: ${BASIC_AUTH_USER:-default} BASIC_AUTH_PASSWORD: ${BASIC_AUTH_PASSWORD-default}上記のように書くことによってサーバーの環境変数を持ってきてセットすることができ、外部からは見えないようになる。
docker-compose.ymlファイルを触ったのでbuildも忘れずに。感想
初学者な為、知ってるわってあったらごめんなさい。。
やばい部分あったら教えていただけると幸いです!
マージする前に気づけてよかったのと、他のAPI使用する際にも活用できそう。
- 投稿日:2021-01-13T18:47:40+09:00
Rails must be exist系のエラー(@saveが実行されない)
- 投稿日:2021-01-13T18:14:04+09:00
Mysql2::Error: Incorrect string valueのエラーの対処
はじめに
データベースを作成してマイグレーションも実行し、「いざ、データ(日本語)を入れて動かそう!」としたところで、以下のようなエラーが。。。
Mysql2::Error: Incorrect string value: '\xE3\x82\xB2\xE3\x82\xB9...' for column 'name' at row 1どうやら文字コードが不適切らしい。。。
ということで、本記事では、このエラーについて、僕が試したことや解決策を書いていこうと思います!技術・環境
Docker/docker-compose
ruby 2.7.2
rails 6.0.2.3試したこと
①テーブルの文字コードを調べてみました。
まずは、MySQLに接続する。
$ docker-compose run web rails db次に、データベースの文字コードを調べてみる。
> show variables like '%char%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8mb4 | | character_set_connection | utf8mb4 | | character_set_database | latin1 | | character_set_filesystem | binary | | character_set_results | utf8mb4 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+やはり、データベースの文字コードが「latin1」だった。。。
※MySQLはdefaultで「latin1」が文字コードに設定されています。②データベースの文字コードをutf8mb4に修正
僕はDockerを使用していたので、以下のようにdocker-compose.ymlを修正。
※以下の公式ドキュメントを参考にしました。
https://hub.docker.com/_/mysqldocker-compose.ymlversion: "3" services: db: image: mysql:5.7 # この下の一行を追記しました command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci environment: MYSQL_ROOT_PASSWORD: password MYSQL_USER: root ports: - "3306:3306" volumes: - ./db/mysql/volumes:/var/lib/mysql web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/share-read ports: - "3000:3000" depends_on: - db volumes: mysql-data: driver: localデータベースの文字コードを再度調べてみる。
> show variables like '%char%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8mb4 | | character_set_connection | utf8mb4 | | character_set_database | utf8mb4 | | character_set_filesystem | binary | | character_set_results | utf8mb4 | | character_set_server | utf8mb4 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+「よし!修正完了!」と思ったが、まだエラーが出てしまう。
もしかしたらテーブル自体の文字コードが「latin1」のまま?と思い調べてみると。。。> SHOW CREATE TABLE users; | users | CREATE TABLE `users` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, # 中略 PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 |やはり、テーブルの文字コードが変わっていなかった。。。
③テーブルの文字コードをutf8mb4に修正
ということで、テーブルの文字コードを修正するのですが、10個くらいテーブルがあって一つ一つ修正するのは大変!
また、まだテーブルにデータを格納してなかったこともあり、今回はマイグレーションをやり直そうことにしました。$ docker-compose run web rails db:reset $ docker-compose run web rails db:migrateということで無事解決しました。
もし同じようなエラーが出てしまった方は、参考にしてみてください。
- 投稿日:2021-01-13T17:04:28+09:00
【備忘録】Rails Formオブジェクトパターン使用時のエラーメッセージ日本語化
概要
- RailsのFormオブジェクトパターン使用時の入力フォームについてのバリデーションで弾かれたエラー内容を日本語として表示させる事を行ったので備忘録としてまとめておきます。
前提
- RailsのアプリケーションにてFormオブジェクトパターンを用いている。
Formオブジェクトパターンについて簡単に
- Railsを利用する開発における実装パターンのひとつ。
- 主に1つのフォーム送信時に複数のモデルを操作したい場合やテーブルに情報を保存しない情報に対するバリデーションを行いたい場合に使用します。
Formオブジェクト使用時のバリデーションについて
- まず、1つのフォームから複数のテーブルにデータを保存する場合、Formオブジェクトを使用していないと、フォームから送られてきた値を処理(createやupdate)する際に複数テーブルに関連したモデル内記述のバリデーションで入力値が弾かれてしまうと処理を継続できなくなります。
- その点を補う為にFormオブジェクトパターンを用います。
- Formオブジェクトのインスタンス内にバリデーションの記述を行う事で、フォームからの入力値がバリデーションに引っかかった場合は、入力情報と共にエラーメッセージをフォームに返す事が出来ます。
エラーメッセージの日本語化について
1.作成中アプリケーションのconfigフォルダ内のapplication.rbに
config.i18n.default_locale = :ja ←この一文を追加します。
cnofig>application.rbmodule (作成アプリケーション名) class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 6.0 # 日本語の言語設定 config.i18n.default_locale = :ja #←この一文をconfig内のapplication.rbに追加。 # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. end end2.日本語に対応する"rails-i18n"というGemを導入します。
・このGemの導入によりrails-i18nで翻訳されている英文が日本語として使用出来るようになります。
※Gemについての詳細は下記のサイトで確認して下さい。
https://github.com/svenfuchs/rails-i18n
Gemfileにrails-i18nを記述しターミナルにて「bundle install」を行います。Gemfil~ 中略 ~ gem 'rails-i18n'
ターミナルbundle install
3.rails-i18nのGemで対応出来なかった単語に関して日本語翻訳する為のlocaleファイルを作成します。
・localeファイル・・・様々な言語に対応できる言語ファイルの事です。
・まずlocalesフォルダはをconfigフォルダ内に作成します。
・そしてconfig/localesディレクトリに「ja.yml」というファイルを作成します。
4.ja.ymlのファイルを作成したら、ファイル内に日本語化したい英文・英単語と日本語訳を記述していきます。
・ja.ymlファイル内の記述に関しては下記のコードを参照して頂ければと思います。
※この時に注意点です!
・Formオブジェクトパターンを使用していないモデルに関しては、ActiveRecordを継承していますが、Formオブジェクトパターンを用いて作成したモデルは、ActiveModelを継承して作成しています。
ですので、Formオブジェクトパターンを用いたモデルに対しての翻訳の部分の記述の際は気をつけて下さい。ja.ymlja: activerecord: #← ActiveRecordを継承しているモデルに対しての翻訳部分 attributes: user: #←モデルファイル名 nickname: ニックネーム #←rails-i18nにて翻訳されなかった単語名 gender: 性別 #←rails-i18nにて翻訳されなかった単語名 age: 年齢 #←rails-i18nにて翻訳されなかった単語名 activemodel: #← ActiveModelを継承して作成したFormオブジェクトパターンのモデルに対しての翻訳 attributes: book_data: #←Formオブジェクトパターン使用のモデルファイル名 title: タイトル #←rails-i18nにて翻訳されなかった単語名 publisher: 出版社 #←rails-i18nにて翻訳されなかった単語名 author: 著者 #←rails-i18nにて翻訳されなかった単語名 isbn: ISBN #←rails-i18nにて翻訳されなかった単語名5.サーバー再起動後にブラウザで確認して下さい。
・再起動後に、フォームのバリデーションのエラーメッセージが問題なく翻訳されているか確認して下さい。
- 投稿日:2021-01-13T14:20:05+09:00
カスタムデータ属性について
カスタムデータ属性とは?
HTML5で新しく導入された、html要素に、カスタムデータと呼ばれる、独自の属性を指定する属性。
オリジナルの属性も作成できる。
カスタムデータ属性の名前は常にdataから始まる。
各種スクリプトで動的に使用可能であり、主にJavaScriptやjQueryで値を取得するときに使用されることが多い。<div class="tweet" data-genre="movie"> 属性名:data-id 属性値:tweet.id本来的に、HTMLのclass属性の目的は、データを格納するためではなく、開発時にCSS等のスタイル情報を割り当てるため。
しかし、要素への情報が増えるたびに、その都度新しいクラスを追加する必要が出てきてしまう。
そうなると、JavaScriptで実際に必要な情報を取り出すことが難しくなる。
そのような背景のもと、HTML5で新たに導入された。カスタムデータ属性のルール
HTMLでカスタムデータ属性を設定するルールは次のようなものがあります。
- data以降に属性名を指定する
- 属性名に使用できるのは、文字、数字、-(ハイフン)、.(ドット)、_(アンダースコア)のみで、大文字は使用できない
- 属性値は数字も文字列も使用できるが、慣例的に小文字の使用が大半
- class名を属性名として格納することはできない(データ属性を扱うのは、他に適切なHTML要素や属性がない場合だけに限るべきだから)
JavaScriptでの使い方
データ属性の取得
<div id="tweet" data-genre="movie"></div> <script> var result = document.getElementById("tweet"); var dataset = result.dataset; console.log(result); </script>実行結果
movieデータ属性の変更
<div id="tweet" data-genre="movie"></div> <script> var result = document.getElementById("tweet"); result.dataset.genre = 'movie'; console.log(result); </script>実行結果
moviejQueryでの使い方
データ属性の取得
対象要素.data( 属性名 )
のように、引数へdata属性名を指定する。<div class="tweet" data-genre="movie"></div> <script> const result = $(".tweet").data('genre'); console.log(result); </script>実行結果
movieデータ属性の変更
<div class="tweet" data-genre="movie"></div> <script> const result = $(".tweet").data('genre', 'movie'); console.log(result); const result = $(".tweet").data('genre', 'music'); console.log(result); </script>実行結果
movie music
- 投稿日:2021-01-13T12:45:27+09:00
iso-2022-jpの文字列をutf-8に変換する
メールを受け取った際にiso-2022-jpで送られたために文字化けしてしまっていました。
rubyのencodeを使ってutf-8に変換します
検証するためにiso-2022-jpでエンコードされた文字列を生成します
puts "ほげ".encode('iso-2022-jp') # => $B$[$2(Bencodeを以下のように記述します
str.encode(変換先, 変換元, 変換オプション)今回はiso-2022-jpの文字列をutf-8に変換したいので次のようになります
str = "ほげ".encode('iso-2022-jp') puts str # => $B$[$2(B puts str.encode('utf-8', 'iso-2022-jp', invalid: :replace, undef: :replace, replace: '')今回は変換できない文字を空文字に置き換えるオプションを指定しています
変換元がわかっている場合でないとこの方法で変換することはできませんが、
今回のようにメールが文字化けしている場合などでは有効に使えそうです参考
https://docs.ruby-lang.org/ja/latest/method/String/i/encode.html
- 投稿日:2021-01-13T12:03:24+09:00
Formオブジェクトを用いて作成したデータを、特定のデータのみ削除する方法
要点
- メルカリクローンのアプリを作るときの参考に
- dependent: :destroy を用いて外部キーの削除制限を外す
- 下記のエラーを解消する方法
ActiveRecord::InvalidForeignKey (Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails (`-アプリ名-_development`.`-中間テーブル名-`, CONSTRAINT `fk_rails_~~~~~` FOREIGN KEY (`-商品のテーブル名-_id`) REFERENCES `-商品のテーブル名-` (`id`))):はじめに
メルカリのようなフリマアプリを作成中で、Formオブジェクトを用いて商品にタグ付けして出品できる機能を実装する所まで行いました
各モデルとコントローラーは以下のようになります
- Item/商品
- Tag/タグ
- TagItemRelation/商品とタグの中間テーブル
- TagsItem/ ItemとTagを同時に保存するためのFormオブジェクト
/app/model/item.rbclass Item < ApplicationRecord has_many :tag_item_relations has_many :tags, through: :tag_item_relations end/app/model/tag.rbclass Tag < ApplicationRecord has_many :tag_item_relations has_many :items, through: :tag_item_relations validates :tag_name, uniqueness: true end/app/model/tag_item_relation.rbclass TagItemRelation < ApplicationRecord belongs_to :item belongs_to :tag end/app/form/tags_item.rbclass TagsItem include ActiveModel::Model attr_accessor :item_name, :tag_name with_options presence: true do validates :item_name end def save item = Item.create(item_name: item_name) tag = Tag.where(tag_name: tag_name).first_or_initialize tag.save TagItemRelation.create(item_id: item.id, tag_id: tag.id) end endコントローラー
/app/controller/items_controller.rbclass ItemsController < ApplicationController def index @items = Item.all.order('created_at ASC') end def new @item = TagsItem.new end def create @item = TagsItem.new(items_params) if @item.valid? @item.save redirect_to root_path else render :new end end private def items_params params.require(:tags_item).permit( :item_name, :tag_name ) end endその後商品閲覧機能と
問題の商品削除機能を実装した/app/controller/items_controller.rbclass ItemsController < ApplicationController before_action :set_item, only: [:show, :destroy] ### 中略 def show @tags_item = TagItemRelation.find(params[:id]) end def destroy if current_user.id == @item.user_id @item.destroy redirect_to root_path else render :show end end private ### 中略 def set_item @item = Item.find(params[:id]) @tag = Tag.find(params[:id]) end endしかし実際に出品した商品を削除してみると、、、
ActiveRecord::InvalidForeignKey (Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails (`-アプリ名-_development`.`tag_item_relations`, CONSTRAINT `fk_rails_~~~~~~` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`))):のエラーが出てしまい、商品の削除ができませんでした
調べたこと
エラー内容をよく読んでみると、商品idは中間テーブルの外部キー(foreign key)に含まれて
デリートやアップデートができないよ!と書かれているのがわかりますそこで外部キーについて調べてみると、、、
外部キー(外部制約キーとも)は、よくマイグレーションファイルなどに書いてるデータベースのキーで
データベースの特定の項目に好き勝手な値を入れることを防ぎ、外部の項目から選んで入れる制約を持ち
主に外部キーのテーブルから主キーのテーブルのデータに対して、変更を制限するものだそうです
今回の場合外部キーのテーブルはtag_item_relations、主キーのテーブルはitemになることが分かりますね外部キーの設定変更
今回のエラーの原因はマイグレーションファイルに記載した外部キー(foreign_key: trueのやつ)でした
ですがマイグレーションファイルごと書き換えてしまうと別の不具合が起きてしまう恐れがあります
今回はdestoryで外部キーとして設定している項目を削除させるように、dependent: :destroyを設定しようと思います
この簡単な設定により不具合なく商品の削除ができるようになります/app/model/item.rbclass Item < ApplicationRecord has_many :tag_item_relations, foreign_key: :item_id, dependent: :destroy has_many :tags, through: :tag_item_relations end参考にしたサイト
関連記事
- 投稿日:2021-01-13T11:46:54+09:00
RSpec エラー undefined method `feature' for RSpec:Module
rspecコマンドを打った時に出たエラー。
結論
capybaraを読み込んでいなかった。
コード
エラーコード
require 'rails_helper' RSpec.feature "Users", type: :feature do describe "Signup page" do before do visit signup_path end it "display Signup contents, title properly" do expect(page).to have_css('h1', text: 'ユーザー登録') expect(page).to have_title 'Signup hoge' end end end解決したコード capybaraを読み込む
require 'rails_helper' + require 'capybara/rspec' RSpec.feature "Users", type: :feature do describe "Signup page" do before do visit signup_path end it "display Signup contents, title properly" do expect(page).to have_css('h1', text: 'ユーザー登録') expect(page).to have_title 'Signup hoge' end end end一応gemfile
#rspecのprogressbarを表示してくれる。実行のコマンド% bin/rspec spec/ --format Fuubar gem 'fuubar' group :test do #rspecには、以下の3つのgemが必要。 gem 'rspec-rails' gem 'factory_bot_rails' gem 'rails-controller-testing' #rspecのfeatureで必要。 gem 'capybara', '~> 2.13' #Capybaraでテスト中に、現在どのページを開いているのか確認するため gem 'launchy' #便利。validationが一行くらいでかける。 gem 'shoulda-matchers', git: 'https://github.com/thoughtbot/shoulda-matchers.git', branch: 'rails-5' end group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem 'spring-commands-rspec' end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 4.1.0' # Display performance information such as SQL time and flame graphs for each request in your browser. # Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md gem 'rack-mini-profiler', '~> 2.0' gem 'listen', '~> 3.3' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]参考:
https://stackoverflow.com/questions/26217184/rspec-3-1-undefined-method-feature-for-mainobject
- 投稿日:2021-01-13T11:46:54+09:00
RSpec エラー 解決 undefined method `feature' for RSpec:Module
rspecコマンドを打った時に出たエラー。
結論
capybaraを読み込んでいなかった。
コード
エラーコード
require 'rails_helper' RSpec.feature "Users", type: :feature do describe "Signup page" do before do visit signup_path end it "display Signup contents, title properly" do expect(page).to have_css('h1', text: 'ユーザー登録') expect(page).to have_title 'Signup hoge' end end end解決したコード capybaraを読み込む
require 'rails_helper' + require 'capybara/rspec' RSpec.feature "Users", type: :feature do describe "Signup page" do before do visit signup_path end it "display Signup contents, title properly" do expect(page).to have_css('h1', text: 'ユーザー登録') expect(page).to have_title 'Signup hoge' end end end一応gemfile
#rspecのprogressbarを表示してくれる。実行のコマンド% bin/rspec spec/ --format Fuubar gem 'fuubar' group :test do #rspecには、以下の3つのgemが必要。 gem 'rspec-rails' gem 'factory_bot_rails' gem 'rails-controller-testing' #rspecのfeatureで必要。 gem 'capybara', '~> 2.13' #Capybaraでテスト中に、現在どのページを開いているのか確認するため gem 'launchy' #便利。validationが一行くらいでかける。 gem 'shoulda-matchers', git: 'https://github.com/thoughtbot/shoulda-matchers.git', branch: 'rails-5' end group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem 'spring-commands-rspec' end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'web-console', '>= 4.1.0' # Display performance information such as SQL time and flame graphs for each request in your browser. # Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md gem 'rack-mini-profiler', '~> 2.0' gem 'listen', '~> 3.3' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]参考:
https://stackoverflow.com/questions/26217184/rspec-3-1-undefined-method-feature-for-mainobject
- 投稿日:2021-01-13T11:40:11+09:00
http://localhost:ポート番号を変更する方法
hello rails 画面を好きなポート番号で接続する
手順
ポート番号3000で接続してみる
docker-compose.ymlversion: "3" services: app: build: context: . dockerfile: Dockerfile ports: - "3000:3000" tty: true stdin_open: true command: bash -c "bundle exec rails s -p 3000 -b '0.0.0.0'" depends_on: - db db: image: mysql:8.0.16 command: --default-authentication-plugin=mysql_native_password restart: always environment: MYSQL_HOST: 127.0.0.1 MYSQL_DATABASE: app_development MYSQL_USERNAME: root MYSQL_ROOT_PASSWORD: root security_opt: - seccomp:unconfined ports: - "3306:3306"DockerfileFROM ruby:2.6.5-stretch ENV LANG C.UTF-8 ENV APP_ROOT /app WORKDIR $APP_ROOT RUN apt-get update && apt-get install -y --no-install-recommends \ curl apt-transport-https wget && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ curl -sL https://deb.nodesource.com/setup_8.x | bash - && \ apt-get update && apt-get install -y --no-install-recommends \ build-essential \ vim \ mysql-client \ yarn \ nodejs && \ gem install bundler && \ rm -rf /var/lib/apt/lists/* COPY Gemfile $APP_ROOT COPY Gemfile.lock $APP_ROOT COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] RUN bundle install COPY . $APP_ROOT EXPOSE 3000起動する
docker-compose up --build
コンテナに入る
docker-compose exec app bash
Gemfileの更新
bundle install
新規プロジェクト作成(sqliteでなく、mysqlを選択)
rails new . -d mysql
コンテナを落とす
docker-compose down
database.ymlにdocker-composeのdbコンテナのpasswordを設定
docker-compose up
=> railsが3000ポートが起動する
ポート番号3001で接続する
docker-compose.ymlversion: "3" services: app: build: context: . dockerfile: Dockerfile ports: - "3001:3001" tty: true stdin_open: true command: bash -c "bundle exec rails s -p 3001 -b '0.0.0.0'" depends_on: - db db: image: mysql:8.0.16 command: --default-authentication-plugin=mysql_native_password restart: always environment: MYSQL_HOST: 127.0.0.1 MYSQL_DATABASE: app_development MYSQL_USERNAME: root MYSQL_ROOT_PASSWORD: root security_opt: - seccomp:unconfined ports: - "3306:3306"DockerfileFROM ruby:2.6.5-stretch ENV LANG C.UTF-8 ENV APP_ROOT /app WORKDIR $APP_ROOT RUN apt-get update && apt-get install -y --no-install-recommends \ curl apt-transport-https wget && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ curl -sL https://deb.nodesource.com/setup_8.x | bash - && \ apt-get update && apt-get install -y --no-install-recommends \ build-essential \ vim \ mysql-client \ yarn \ nodejs && \ gem install bundler && \ rm -rf /var/lib/apt/lists/* COPY Gemfile $APP_ROOT COPY Gemfile.lock $APP_ROOT COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] RUN bundle install COPY . $APP_ROOT EXPOSE 3001手順
docker-compose.yml
- rails起動コンテナのapp内、portsを3001:3001を指定。
- 同じく、commandで解放済みの3001ポートをリッスンするよう指定。
Dockerfile
- EXPOSEにて、3001ポートを解放するよう指定
http://localhost:3001
でrailsが起動する。
- 投稿日:2021-01-13T11:10:37+09:00
Railsで配列をActive Record Relationに変換したい
変換できるのか
誤解を生む可能性がある為はじめに書いておきます。
「配列をActive Record Relationに変換したい」という理由でこの記事を見ていただいている方がいると思いますが、
厳密には配列をActive Record Relationに変換することは出来ません。
ただし、取得した配列を使って、Active Record Relationを取得することは出来ます。私自身「配列 Active Record Relation 変換」で検索したりしたので、あえてこのようなタイトルにしています。
配列とActive Record Relationについて
はじめに簡単に説明をしますが、分かる方はここまで飛ばしてください。
配列とActive Record Relation、それぞれの例を上げてみます。#Active Record Relationを作ります。 AdminUser.where(id: [2, 3]) => [#<AdminUser:0x00007fd2621de8e0 id: 2, name: "山田">, #<AdminUser:0x00007fd2621de4f8 id: 3, name: "佐藤">]#Arrayを作ります。 AdminUser.where(id: [2, 3]).select(&:name) => [#<AdminUser:0x00007fd26231ad80 id: 2, name: "山田">, #<AdminUser:0x00007fd26231aa88 id: 3, name: "佐藤">]結果は同じように見えますが、
.class
をつけてみると違いが分かります。AdminUser.where(id: [2, 3]).class => AdminUser::ActiveRecord_RelationAdminUser.where(id: [2, 3]).select(&:name).class => Arrayモデルからデータを取り出す際に、
where
やfind
、select
、map
など色々なメソッドを使うことがあると思いますが、Railsでは、使うメソッドによって返り値の型が決まっています。
上記の例の使い方で言うと、where
だとActive Record Relationが返り、select
だとArrayクラスが返ることになります。
※厳密にはselect
は使い方によってはActive Record Relationが返ります。例えばこんな時に困る
Viewに何らかのデータを表示したい。
where
を使ってActive Record Relationにしたはいいが、
そのあとselect
でデータの絞り込みなどを行った。
Viewに表示する前に並び替えをしたいので、order
メソッドを使ったら、エラーが発生した。Railsで開発をする際によく使う
order
と言うメソッド。並び替えが出来ます。#idが大きい順に並び替える AdminUser.where(id: [2, 3]).order(id: :desc) => [#<AdminUser:0x00007fd260347a30 id: 3, name: "佐藤", #以下省略この
order
メソッドをArrayクラスに対して使うとこのようなエラーになります。AdminUser.where(id: [2, 3]).select(&:name).order(id: :desc) => NoMethodError: undefined method `order' for #<Array:0x00007fd26027d578>このような場合に、
AdminUser.where(id: [2, 3]).select(&:name)
をActive Record Relationに変換したい、という欲望が生まれます。結論
ここからがタイトルのような欲望を叶える具体的な方法です。
admin_usersというArrayクラスから@admin_usersというActive Record Relationを作りたいなら、こうします。admin_users = AdminUser.where(id: [2, 3]).select(&:name) @admin_users = AdminUser.where(id: admin_users.map(&:id))要は
where(id: admin_users.map(&:id))
をしているだけですが、
何をしているかというと、既にある配列のidだけを取り出して配列を作って、それをwhere
の引数に使ってAdminUserから再度データを取得しています。注意点として、下記があるでしょうか。
- データの中身の順番が変わる可能性があること
- データを再取得する処理を行っていること(大量のデータの場合は余計な時間がかかる)
実装方法
この処理を使って実装するにあたって、同じ処理をたくさんするのであれば、スッキリとまとめてしまいたいです。
2つの方法を紹介します。1. コントローラーやモデルに再取得メソッドを作る
2. Arrayクラスを拡張して再取得メソッドを作る1.コントローラーやモデルに再取得メソッドを作る
コントローラーやモデルに下記のように書きます。
def self.get_activerecord_relation(arr) where(id: arr.map(&:id)) end使い方
admin_users = AdminUser.where(id: [2, 3]).select(&:name) => #Arrayクラス @admin_users = AdminUser.get_activerecord_relation(admin_users) => #Active Record Relationちょっと気持ち悪いかなと思います。
2.Arrayクラスを拡張して再取得メソッドを作る
array.rbというファイルを作ります。
lib/core_ext/array.rbclass Array def to_activerecord_relation return ApplicationRecord.none if self.empty? clazzes = self.map(&:class).uniq raise 'Array cannot be converted to ActiveRecord::Relation since it does not have same elements' if clazzes.size > 1 clazz = clazzes.first raise 'Element class is not ApplicationRecord and as such cannot be converted' unless clazz.ancestors.include? ApplicationRecord clazz.where(id: self.map(&:id)) end endcore_ext.rbというファイルを作ります。
config/initializers/core_ext.rbrequire 'core_ext/array'使い方
admin_users = AdminUser.where(id: [2, 3]).select(&:name) => #Arrayクラス @admin_users = admin_users.to_activerecord_relation => #Active Record Relation2の方法は、Rubyのオープンクラスという後からメソッドを追加したり出来る機能を使った方法で、
Arrayクラスに全体に対して、to_activerecord_relation
というメソッドが使えるようにしてしまおう、みたいな感じです。オープンクラスに関しては今回紹介したもの以外には例えば、
Stringクラスにto_bool
というメソッドを追加して、"true"
や"false"
という文字列が代入されたオブジェクトをboolean型に変換出来るようにする、なども出来ます。参考にさせていただいた記事
https://qiita.com/shibadai/items/ddbc76a8b980cd8354bc
https://stackoverflow.com/questions/17331862/converting-an-array-of-objects-to-activerecordrelation
- 投稿日:2021-01-13T10:34:18+09:00
scopeを使ったリファクタリング
リファクタリングって何がベストなのか? どこから行っていこうか?
初学者からすると難しい。まだ冗長な箇所や気付けていない箇所もありますが、今回
scope
を使ったので残しておこうと思います。数年後の自分が見たら、「もっとよくできる箇所はあるだろ..」と言われそうですが。(いや..言える自分になりたい ^^;)
そのために、コツコツと日々学んでいきます。リファクタリング前:
【画像のメタデータから緯度経度を取得して10進数に変換しているコード】
img = Magick::ImageList.new(Rails.root.to_s + "/public#{@post.image.url}") # 緯度取得 exif_lat = img.get_exif_by_entry('GPSLatitude')[0][1].split(',').map(&:strip) # 10進数に変換 @latitude = (Rational(exif_lat[0]) + Rational(exif_lat[1])/60 + Rational(exif_lat[2])/3600).to_f # 経度取得 exif_lng = img.get_exif_by_entry('GPSLongitude')[0][1].split(',').map(&:strip) # 10進数に変換 @longitude = (Rational(exif_lng[0]) + Rational(exif_lng[1])/60 + Rational(exif_lng[2])/3600).to_f...(恥)..めちゃくちゃ長ったらしくて読みたく無い程に見難い
showアクションと、confirmアクションに全く同じ記述があるので、更に格好悪い..どう切り分けるのか考える
・コントローラの役割とモデルの役割を意識
・10進数に変換する記述は供用する
・緯度経度の取得もscopeして、コントローラ側を短くするこんな感じでやってみる
10進数への変換を共通化させる
exif_lat
とexif_lng
で分けてある箇所は引数で与えてやればいいので、exif
とする
スコープの名前はget_exif_gps
app/controller/posts_controller: @latitude = Post.get_exif_gps(exif_lat) @longitude = Post.get_exif_gps(exif_lng)Postモデルに記述: scope :get_exif_gps, -> (exif){ (Rational(exif[0]) + Rational(exif[1])/60 + Rational(exif[2])/3600).to_f }緯度の取得もscopeさせる
ローカル変数
img
を引数で渡す
スコープの名前はget_exif_latitude
app/controller/posts_controller: exif_lat = Post.get_exif_latitude(img)Postモデルに記述: scope :get_exif_latitude, -> (img){ img.get_exif_by_entry('GPSLatitude')[0][1].split(',').map(&:strip) }※経度の取得も同様に行う
スコープの名前は
get_exif_longitude
app/controller/posts_controller: exif_lng = Post.get_exif_longitude(img)Postモデルに記述: scope :get_exif_longitude, -> (img){ img.get_exif_by_entry('GPSLongitude')[0][1].split(',').map(&:strip) }リファクタリング後
app/controller/posts_controller: img = Magick::ImageList.new(Rails.root.to_s + "/public#{@post.image.url}") exif_lat = Post.get_exif_latitude(img) @latitude = Post.get_exif_gps(exif_lat) exif_lng = Post.get_exif_longitude(img) @longitude = Post.get_exif_gps(exif_lng)Postモデル: # 緯度の取得 scope :get_exif_latitude, -> (img){ img.get_exif_by_entry('GPSLatitude')[0][1].split(',').map(&:strip) } # 経度の取得 scope :get_exif_longitude, -> (img){ img.get_exif_by_entry('GPSLongitude')[0][1].split(',').map(&:strip) } # 10進数に変換 scope :get_exif_gps, -> (exif){ (Rational(exif[0]) + Rational(exif[1])/60 + Rational(exif[2])/3600).to_f }コントローラを見た時に多少は目で追いやすくなったかな?..
メソッドに切り出したりしたら、もう少し見やすくできそうな気もしますが、今回はここまでを
scope
の備忘録がてら残しておきます。
今後も更に勉強して吸収していきたいと思います!!参考
https://pikawaka.com/rails/scope
最後に
もっとこうすれば良い!というアドバイスございましたら、是非ご指摘ください! ^^
- 投稿日:2021-01-13T09:37:31+09:00
TailwindUIのFormの見た目がサンプル通りにならない
困ったこと
同じスタイルクラスを当ててるはずなのに、見た目が違う。
理想の見た目
実際の見た目
対応内容
たぶん次のどっちかやればええんちゃうか
https://github.com/tailwindlabs/tailwindcss-forms
https://tailwindcss-custom-forms.netlify.app/1個目のほうをインストールしたけど怒られた
terminalERROR in ./node_modules/tippy.js/animations/perspective.css (./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src??ref--5-2!./node_modules/tippy.js/animations/perspective.css) Module build failed (from ./node_modules/postcss-loader/src/index.js): TypeError: Cannot read property 'none' of undefined at /Users/XXXXXXX/projects/XXXXX/node_modules/@tailwindcss/forms/src/index.js:38:26 at /Users/XXXXXXX/projects/XXXXX/node_modules/tailwindcss/lib/util/processPlugins.js:66:5 at Array.forEach (<anonymous>) at _default (/Users/XXXXXXX/projects/XXXXX/node_modules/tailwindcss/lib/util/processPlugins.js:60:11) at /Users/XXXXXXX/projects/XXXXX/node_modules/tailwindcss/lib/processTailwindFeatures.js:56:54 at LazyResult.run (/Users/XXXXXXX/projects/XXXXX/node_modules/postcss/lib/lazy-result.js:288:14) at LazyResult.asyncTick (/Users/XXXXXXX/projects/XXXXX/node_modules/postcss/lib/lazy-result.js:212:26) at LazyResult.asyncTick (/Users/XXXXXXX/projects/XXXXX/node_modules/postcss/lib/lazy-result.js:225:14) at /Users/XXXXXXX/projects/XXXXX/node_modules/postcss/lib/lazy-result.js:217:17 ERROR in ./app/javascript/css/tailwind.css (./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src??ref--5-2!./app/javascript/css/tailwind.css) Module build failed (from ./node_modules/postcss-loader/src/index.js): TypeError: getProcessedPlugins is not a function at /Users/XXXXXXX/projects/XXXXX/node_modules/tailwindcss/lib/processTailwindFeatures.js:67:83 at LazyResult.run (/Users/XXXXXXX/projects/XXXXX/node_modules/postcss/lib/lazy-result.js:288:14) at LazyResult.asyncTick (/Users/XXXXXXX/projects/XXXXX/node_modules/postcss/lib/lazy-result.js:212:26) at LazyResult.asyncTick (/Users/XXXXXXX/projects/XXXXX/node_modules/postcss/lib/lazy-result.js:225:14) at /Users/XXXXXXX/projects/XXXXX/node_modules/postcss/lib/lazy-result.js:217:17 ℹ 「wdm」: Failed to compile.Tailwind CSS v2.0. 用だからかな??
Tailwind CSS v2.0インストール
下記を元に2.0を入れる
https://tailwindcss.com/docs/installationTerminalnpm install tailwindcss@latest postcss@latest autoprefixer@latest
下記怒られる。
Terminal> % bin/webpack-dev-server ℹ 「wds」: Project is running at http://localhost:3035/ ℹ 「wds」: webpack output is served from /packs/ ℹ 「wds」: Content not from webpack is served from /Users/XXX/projects/XXX/public/packs ℹ 「wds」: 404s will fallback to /index.html ℹ 「wdm」: wait until bundle finished: /packs/js/application-83db7df6641884880765.js ✖ 「wdm」: Hash: f6dfc3f28099b484dcf6 Version: webpack 4.44.2 Time: 3149ms Built at: 2021-01-13 7:49:08 Asset Size Chunks Chunk Names js/application-83db7df6641884880765.js 1.88 MiB application [emitted] [immutable] application js/application-83db7df6641884880765.js.map 1.92 MiB application [emitted] [dev] application manifest.json 364 bytes [emitted] ERROR in ./app/javascript/css/tailwind.css (./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src??ref--5-2!./app/javascript/css/tailwind.css) Module build failed (from ./node_modules/postcss-loader/src/index.js): Error: PostCSS plugin tailwindcss requires PostCSS 8. Update PostCSS or downgrade this plugin. at Processor.normalize (/Users/XXX/projects/XXX/node_modules/postcss-loader/node_modules/postcss/lib/processor.js:153:15) at new Processor (/Users/XXX/projects/XXX/node_modules/postcss-loader/node_modules/postcss/lib/processor.js:56:25) at postcss (/Users/XXX/projects/XXX/node_modules/postcss-loader/node_modules/postcss/lib/postcss.js:55:10) at /Users/XXX/projects/XXX/node_modules/postcss-loader/src/index.js:140:12 ERROR in ./node_modules/tippy.js/animations/perspective.css (./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src??ref--5-2!./node_modules/tippy.js/animations/perspective.css) Module build failed (from ./node_modules/postcss-loader/src/index.js): Error: PostCSS plugin tailwindcss requires PostCSS 8. Update PostCSS or downgrade this plugin. at Processor.normalize (/Users/XXX/projects/XXX/node_modules/postcss-loader/node_modules/postcss/lib/processor.js:153:15) at new Processor (/Users/XXX/projects/XXX/node_modules/postcss-loader/node_modules/postcss/lib/processor.js:56:25) at postcss (/Users/XXX/projects/XXX/node_modules/postcss-loader/node_modules/postcss/lib/postcss.js:55:10) at /Users/XXX/projects/XXX/node_modules/postcss-loader/src/index.js:140:12インストール方法にも書いてるが、こちらを参考にする。
Terminalnpm uninstall tailwindcss postcss autoprefixer npm install tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
postcss.config.jsmodule.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, } }terminal-> % npx tailwindcss init @tailwindcss/postcss7-compat 2.0.2 ? tailwind.config.js already exists.tailwind.config.jsmodule.exports = { purge: [], darkMode: false, // or 'media' or 'class' theme: { extend: {}, }, variants: {}, plugins: [], }既に下記だった
app/javascript/css/tailwind.css@import "tailwindcss/base"; @import "tailwindcss/components"; @import "tailwindcss/utilities";一行目追加
app/javascript/src/js/application.jsimport 'tailwindcss/tailwind.css' import './dropdown.js'もう一度、tailwindcss-formsインストールする
今見直したら、2つとも叩いたが、片方でいいと思う。
Terminal-> % npm install @tailwindcss/forms + @tailwindcss/forms@0.2.1 added 2 packages from 1 contributor, removed 7 packages and audited 1824 packages in 8.861s found 0 vulnerabilities -> % yarn add @tailwindcss/forms yarn add v1.22.10 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] ? Resolving packages... [2/4] ? Fetching packages... [3/4] ? Linking dependencies... warning " > webpack-dev-server@3.11.1" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.2" has unmet peer dependency "webpack@^4.0.0". [4/4] ? Building fresh packages... success Saved lockfile. success Saved 4 new dependencies. info Direct dependencies ├─ @tailwindcss/forms@0.2.1 ├─ @tailwindcss/postcss7-compat@2.0.2 └─ tailwindcss@2.0.2 info All dependencies ├─ @tailwindcss/forms@0.2.1 ├─ @tailwindcss/postcss7-compat@2.0.2 ├─ mini-svg-data-uri@1.2.3 └─ tailwindcss@2.0.2 ✨ Done in 19.76s.tailwind.config.jsmodule.exports = { purge: [], darkMode: false, // or 'media' or 'class' theme: { extend: {}, }, variants: {}, plugins: [ require('@tailwindcss/forms'), ], }結果
いい感じになった。
- 投稿日:2021-01-13T07:51:48+09:00
rails _6.0.3_ new hello_myappコマンドでwarningのメッセージが出た
rails 6.0.3 new hello_myappコマンドでwarningのメッセージが出ました。
そのメッセージは以下のようなもの
warning " > webpack-dev-server@3.10.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
解決策
hello_myappのフォルダの階層で以下のコマンドを実行したことで解決した。yarn upgrade webpack@^4.0.0
このサイトを参考にさせてもらいました。
https://stackoverflow.com/questions/61565543/rails-webpack-dev-server-has-unmet-peer-dependency
- 投稿日:2021-01-13T00:46:52+09:00
【Rails】RSpec キホンのキ
はじめに
RSpecはRailsで定番のテストフレームワーク。
minitestと比べると必要なGemが多い。
とはいえ一度に全てのGemを入れると、どのGemがどこでどういう働きをするのかが曖昧になってしまう。
そこで、RSpecの学習に至っては、テストの内容に応じてGemを逐次追加していく手法を取ることにした。RSpecとFactoryBot
Gemの導入と設定
RSpec
と、テスト用データの生成用となるFactoryBot
を導入する。
FactoryBotはminitestにおけるfixture的な役割を担う。
ここでspring-commands-rspec
を入れておくと、RSpecをbinstub
から実行し、spring
を使ってテスト開始にかかる時間を短縮できるとのこと。Gemfile.rbgroup :development, :test do gem "rspec-rails" gem 'spring-commands-rspec' gem "factory_bot_rails" end
bundle install
したら以下のコマンドでRSpec用のデータを生成する。$ bundle exec rails generate rspec:installRSpecの設定を追加する。
設定はconfig/application.rb
に書く。
ここではgenerate
コマンド実行時にRSpec用のファイルを生成するかを設定している。
true
かfalse
かはプロジェクトによって適宜変更する。config/application.rbmodule SampleApp class Application < Rails::Application . . . config.generators do |g| g.test_framework :rspec, controller_specs: true, fixtures: true, helper_specs: true, model_specs: true, request_spec: true, routing_specs: false, view_specs: false end end end次にFactoryBotの設定。
以下のように記述することで、FactoryBotクラスの呼び出しを簡略化できる。spec/rails_helper.rbRSpec.configure do |config| config.include FactoryBot::Syntax::Methods end# FactoryBotクラスの呼び出し user = FactoryBot.create(:user) #省略版 user = create(:user)テスト用データの設定をもう一つ。
以下の一行のコメントアウトを外しておく。
spec/support/
配下のファイルを読み込めるようになる。
ここにはテスト用のヘルパーを記述するファイルなどが置かれる。spec/rails_helper.rb# The following line is provided for convenience purposes. It has the downside # of increasing the boot-up time by auto-requiring all files in the support # directory. Alternatively, in the individual `*_spec.rb` files, manually # require only the support files necessary. # Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }最後に、RSpecのbinstubを導入する。
これで$ bundle exec rspec spec/
に加えて$ bin/rspec spec/
でテストを実行できるようになる。$ bundle exec spring binstub rspec # 実行コマンド $ bin/rspec spec/specファイルの生成
RSpecで使用されるファイルは全て
*_spec.rb
というファイル名になっている。
これをコントローラやモデルに合わせて各種用意していく。
例えばusers_controller用のspecファイルは以下のように生成する。$ rails g rspec:controller users create spec/controllers/users_controller_spec.rbテスト用データの用意
FactoryBotを使って、各種クラスのテスト用データ(インスタンス)を定義する。
例えばUserクラスなら、/spec/factories/users.rb
に定義していく。/spec/factories/users.rbFactoryBot.define do # Userモデルのテストデータmichaelを定義 factory :michael, class: User do name 'michael' email 'michael@example.com' end # 汎用データをたくさん用意する factory :user do sequence(:name) { |n| "name-#{n}"} sequence(:email) { |n| "test-#{n}@example.com"} end end定義したテストデータを呼び出してインスタンス変数に格納し、テストで使用する。
/spec/models/users_spec.rbRSpec.describe User, type: :model do before do # モデルのみの作成 @michael = build(:michael) # DBへレコード生成 @michael = create(:michael) # 汎用データの活用 @user1 = build(:user) @user2 = build(:user) @user3 = build(:user) end . . . end続く!!!