20220112のRailsに関する記事は15件です。

RailsのViewの役割とRoutingについて

はじめに 基本は備忘録 MVCについて役割ごとにまとめる機会があったので整理します。 View htmlファイル 拡張子がsample.html.erb 新しいページを作成する (新たなコントローラとviewを作成 + routingの設定) # localhost:3000/home/topにアクセス可能 # 同じ名前のコントローラがすでにある場合コマンドが使えない rails generate controller コントローラ名 アクション名 rails g controller posts index link_to aタグに変換する。 # Prefixで設定 # rails routesでPrefixを確認 <%= link_to("文字列", post_path) %> # urlで指定 # /で始める routingに合わせる # postのroutingの時は{method: "post"} <%= link_to("文字列", "/posts") %> パーシャル 共通して使えるファイルを1つにまとめたもの パーシャルとして使うファイル名は_sample.erbのように_から始める # 呼び出し方 読み込ませる時は「_」がいらない # 第3引数に post: @postで変数も渡せる <%= render "dir_name/file_name"%> formを作成する # view側の設定 # form_tag(送り先のURL)でフォームの送信先を指定 # textareaのname属性をキーにして、ハッシュでアクションに送る <%= form_tag("/posts/create") do %> <textarea name="content"></textarea> <input type="submit" value="投稿"> <% end %> Routing resources :postsとすることで、基本となる7つのアクションへのルーティングを自動的に設定する get "URL" => "コントローラ名#アクション名" get "/" => "home#top" # railsデフォルトのページ無くす get "about" => "home#about" #home contのaboutを使う resources :posts # クラッドの7つのアクションを一括設定 # ルーティングは上から実行される 書く順番に気をつける # 以下の順番はよくない例だが、わかりやすくするためこの順番にしている get "posts/index" => "posts#index" get "posts/new" => "posts#new" post "posts/create" => "posts#create" get "posts/:id" => "posts#show" get "posts/:id/edit" => "posts#edit" post "posts/:id/update" => "posts#update" post "posts/:id/destroy" => "posts#destroy" URLにidを含ませる方法は下記 # view側のlinkのurlにidを混ぜる ## post.idの部分がparamsにハッシュで保存される <%= link_to(post.content, "/posts/#{post.id}") %> 設定済みrouting情報を確認 rails routes
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsのControllerの役割

はじめに 基本は備忘録 MVCについて役割ごとにまとめる機会があったので整理します。 Controller ModelやViewとdateのやりとりをする CRUD(クラッド)処理 システムに必要な4つの主機能 C Create # データの作成 R Read # データの読み込み U Update # データの更新 D Delete # データの削除 railsは7つを推奨している index # データの一覧を表示する new # データを新規作成するためのフォームを表示 create # データを新規作成し、データーベースへ保存 show # 指定したデータを表示 edit # データを更新するためのフォームを表示 update # データ更新 destroy # データ削除 一覧データの表示と作成 index # DBから全てのデータ(@posts)を取得しViewに返却 #.order(created_at: :desc)で並び替え @posts = Post.all new # インスタンス変数(@post)を作成し、それをViewへ返却 @post = Post.new create # Viewからの送信値(params)を元にデータを作成し、DBへ保存 # formの内容をparamsを使って取得している @post = Post.new(params[:xx]) @post.save Post.create(params[:xx]) データの更新と削除 show # 投稿の詳細を表示 # Viewからの送信値(params)を元にデータを探し、それをViewへ返す @post = Post.find(params[:id]) edit # Viewからの送信値(params)を元にデータを探し出し、Viewに返却 # View側でデータを更新するためのフォームを表示 @post = Post.find(params[:id]) update # Viewからの送信値(params)を元にデータを更新します @post = Post.find(prams[:id]) @post.update(params[:id]) destroy # Viewからの送信値(params)を元にデータを探し出し、削除 @post = Post.find(params[:id]) @post.destroy 応用機能4つ before_action アクションが実行される前に何らかの処理を行う # postsコントローラで共通させたい処理 # postsコントローラでbefore_actionを記述 # 全てのコントローラで共通させたい処理 # applicationコントローラに記述 before_action :set_current_user def set_current_user @current_user = User.find_by(id: session[:user_id]) end # 特定のアクションで利用 # Application..で定義したメソッドは # 継承元で定義したメソッドなので利用できる before_action :authenticate_user, {only: [:edit, :update]} strong Parameter form等からの不必要な情報を受け付けないように設定できる ハッキング対策 params.require(:モデル名).permit(:カラム名, :カラム名2) フラッシュメッセージ # 次のアクションまで表示 flash[:notice] = "表示したい文字列" ## 失敗した時 flash.now[:notice] = "表示したい文字列" # view側 application... <body>最上部 # flashメッセージがある時のみ表示する <% if flash[:notice] %> <div class="flash"> <%= flash[:notice] %> </div> <% end %> redirect_to / render controllerの経由回数が違うのでflashの使い方に気をつける redirect_to # レダイレクトする 引数はrouting redirect_to("/posts/index") render # 他のactionを経由せず、現在のactionの@変数を使える # renderはrender("フォルダ名/ファイル名") render("posts/edit")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsのModelの役割

はじめに 基本は備忘録 MVCについて役割ごとにまとめる機会があったので整理します。 Model modelの役割はDB関連の処理 date取得などの処理や、date自体の作成・削除 新しいテーブルを作成 モデル・マイグレーションファイルが作成される db/migrate/配下にmigrationファイル app/models/配下にモデル # DBに変更を指示するmygration fileを作成 # カラムが複数個ある場合は,は不要 name:string mal:string rails generate model Post content:text # DBに変更を反映 id, created_at, updated_at, は自動生成 rails db:migrate # データ型 integer 整数 float 少数 string 文字列 text 長い文字列 boolean 真偽値 既存のtableにカラムを追加する db/migrate配下 # migrationファイルのみを作成 # 中身を記述 # rails db:migrate rails g migration ファイル名 # 関連ある名前にする migrationファイルの内容を記述 def change # ここに処理 # 既存のテーブルにカラムを追加する add_column :table名, :column名, :データ型 end バリデーションを設定 不正なデータがDBに保存されないようにする仕組み モデルで設定する app/models/配下 # validates :検証するカラム, {検証内容} カラム別に設定 # 空なら弾く, 文字数制限140字 validates :content, {presence: true, length: {maximum: 140}} # 重複した登録を防げる validates :email, {uniqueness: true} presence: true #=> 値が存在しているかを確認 uniqueness: true #=> 値が重複していないか length: {minimum:4} length: {maximum:16} format: {widh: 正規表現} #=>値のフォーマットを指定 inclusion: {in: [draft]} # 値の候補を指定 エラーメッセージを表示 form_tagのtextareaの上に配置。 エラーがない場合は何も表示されない # saveメソッドでvalidationに失敗すると、error messageが自動で生成される # @post.errors.full_messagesの中に配列で入る # view側でeach文を使ってエラー文を表示する <% @post.errors.full_messages.each do | message | %> <%= message %> <% end %> データを操作 # rails consoleや action内で取得する post = Post.new(name: '田中', age: 18) post.save # 変数 = モデル名.条件 post = Post.first post1 = Post.all post2 = Post.all[0].content post3 = Post.find_by(id: 1) post4 = Post.find(1) post.destroy
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby on Rails]いいね、お気に入り機能の実装

はじめに お気に入り機能を実装する際に迷うことがあったため、アウトプットもかねて自分なりにまとめてみました。 前提 下のようなER図にて、お気に入り機能を実装する。 すでに、userの新規登録及びgadjetの投稿、一覧画面、詳細画面の実装は済んでいる。 ・Userはgadjetに対して、一つのお気に入りをすることができる ・Userとfavoriteは"1対多"の関係 ・gadjetとfavoriteは"1対多"の関係 開発環境 ruby '3.0.0' Rails 6.0.3.4 実装手順 favoriteモデルの作成 上記ER図のように、モデルを作成する。 ターミナル rails g model favorite user_id:integer gadjet_id:integer マイグレーションファイルが正しく作成されているか、確認してから ターミナル rails db:migrate DBに反映させる。 モデル同士の紐付け belongs_toとhas_many - belongs_toとhas_manyは共にモデルファイルに記述をする - 「1対多」の関係に置いて「1」である方にhas_manyを記述する - 「1対多」の関係に置いて「多」である方にbelongs_toを記述する app/models/favorite.rb class Favorite < ApplicationRecord belongs_to :user belongs_to :gadjet validates_uniqueness_of :gadjet_id, scope: :user_id end 「1対多」の関係に置いて「多」である方にbelongs_toを記述する。その際、単数系にすることに注意する。 「1ユーザが1つのガジェットにお気に入りをできるのは1回まで。」というバリデーションを、下記記述でかけている。 (gadjet_idとuser_idのセットをユニークにすることで) validates_uniqueness_of :gadjet_id, scope: :user_id app/models/gadjet.rb class Gadjet < ApplicationRecord belongs_to :category, dependent: :destroy belongs_to :user has_many :favorites, dependent: :destroy has_one_attached :image end has_many :favorites, dependent: :destroy 「1対多」の関係に置いて「1」である方にhas_manyを記述する。その際、複数形にすることに注意する。 紐づいた"gadjet"が削除された際に、お気に入りも削除されるように、「dependent: :destroy」を記述する。 app/models/user.rb class User < ApplicationRecord belongs_to :category, dependent: :destroy belongs_to :user has_many :favorites, dependent: :destroy has_one_attached :image end ユーザモデルにも同様に記述する。 favorites controller の作成 ターミナル rails g controller favorites コントローラでは、以下のアクションを記述する。 ・create:お気に入りをする ・destroy:お気に入りを取り消す app/controllers/favorites_controller.rb class FavoritesController < ApplicationController def create @favorite = current_user.favorites.create(gadjet_id: params[:gadjet_id]) redirect_back(fallback_location: root_path) end def destroy @gadjet = Gadjet.find(params[:gadjet_id]) @favorite = current_user.favorites.find_by(gadjet_id: @gadjet.id) @favorite.destroy redirect_back(fallback_location: root_path) end end 「current_user.favorites.create」→ current_userに紐づいた"favorite"を作成している。 (favoriteテーブルのuser_idにカレントユーザidが入っている事になる) "gadjet_id"には、paramsで指定したgadjet_idが入る。 「redirect_back(fallback_location: root_path)」→直前のページにリダイレクトする。 お気に入りした際に、一覧画面、詳細画面のそれぞれにリダイレクトするようにするため。 destroyについても同じ容量で記述する。 ルーティングの作成 以下のように、ルーティングを設定する。 config/routes.rb resources :gadjets do resource :favorites, only: [:create, :destroy] end お気に入りをする一覧画面、詳細画面のアクションがあるコントローラのルーティングで記述。 (私の場合は、boardsコントローラがそれに当たる) view画面の作成にて、create,destroyのパスは使用するため、確認しておく。 お気に入り済みか判定するメソッドを作成 app/models/user.rb class User < ApplicationRecord belongs_to :category, dependent: :destroy belongs_to :user has_many :favorites, dependent: :destroy has_one_attached :image def already_favorite?(gadjet) self.favorites.exists?(gadjet_id: gadjet.id) end end 「self.favorite.exists?(gadjet_id: gadjet.id)」 →カレントユーザに紐位づいている"gadjet"の中で、favoriteテーブルの"gajet_id"の中に、お気に入りしようとしているガジェットのID"gajet.id"が存在しているか を判定している。(selfには、current_user.idが入ると考える) viewファイルにお気に入りボタンの実装 お気に入りを実装するviewファイル.html.erb <% if current_user.already_favorite?(@gadjet) %> #上で作成したメソッドを使用 <%= button_to gadjet_favorites_path(@gadjet), method: :delete do %> #すでにお気に入りだったらdestroy <i class="fas fa-thumbs-up good"></i>  <% end %> <%= @gadjet.favorites.count %> #お気に入りの数をカウント <% else %> <%= button_to gadjet_favorites_path(@gadjet.id), method: :post do %> #お気に入りでなかったらcreate <i class="far fa-thumbs-up good"></i> <% end %> <%= @gadjet.favorites.count %> <% end %> 自分は、font awesomeを使用してgoodボタンにしていますが、ハートでいいねやその他アイコンで様々な表現ができると思います。 (例) 終わりに 少しでも参考になれば幸いです。 また、間違い等がありましたら、コメントにてご指摘をお願いいたします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

form_withについて

form_withについて form_withは今まで場合によって使い分けをしていたform_forとform_tagを統合したもの モデルに紐づくフォームを作成=form_for モデルに紐付かないフォームを作成=form_tag HTTPメソッドとアクションを判別してくれる form_withでurlとmodelを渡す場合の違い 1. urlを渡す場合 <%= form_with url: users_path do |form| %> <%= form.text_field :email %> <%= form.submit %> <% end %> この場合には、user_pathに対して、POST(送信)を行い,text_field :emailに入力されたメールアドレスの値を取得できる。 2.modelを渡す場合 新規で作成されたものが渡されたとき(コントローラーのnewアクションが渡された場合) <%= form_with model: @user do |form| %> <%= form.text_field :email %> <%= form.submit %> <% end %> この場合モデルの中身が空なのでcreateメソッドを呼び出す すでにあるものが渡された場合(コントローラーのeditアクションが渡された場合) <%= form_with model: @user do |form| %> <%= form.text_field :email %> <%= form.submit %> <% end %> この場合、モデルの中身が存在するのでupdateメソッドを呼び出す。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails 7のHotwireがどんなことをしてくれるものかを知りたいです

はじめに 先月12月15日に Ruby on Rails 7.0 がリリースされたということで、自分でもその機能を試してみます。 リリースを伝えるブログ記事の日本語訳はこちらを読みました。 ここでは Hotwire について試してみます。 Hotwireは、こちらの記事 では「It's a complete alternative to heavy JavaScript client-side apps that speak JSON to a backend.」と説明されています。早速使ってみましょう。 デモアプリケーション こちら にソースコードを置きました。 プロジェクトの新規作成 プロジェクトは rails new コマンドで作成しますが、これを実行するためにはあらかじめ以下の gem がインストールされている必要があります。 bundle init echo "gem 'rails', '~>7.0.1'" >> Gemfile echo "gem 'bootsnap'" >> Gemfile echo "gem 'importmap-rails'" >> Gemfile echo "gem 'turbo-rails'" >> Gemfile echo "gem 'stimulus-rails'" >> Gemfile echo "gem 'sprockets-rails'" >> Gemfile bundle config set --local path vendor/bundle bundle install bundle exec rails new ../bustime -d postgresql --skip-jbuilder ※Rails 7.0.1 で、Ruby 3.1 対応になりました。 Turbo Turbo Drive モデルとコントローラを作成してみます。 bundle exec rails generate scaffold BusLine name:text bundle exec rails generate scaffold BusSchedule departure_hour:bigint departure_minute:bigint bus_line_id:bigint bundle exec rails db:migrate bundle exec rails server -b 0.0.0.0 Webブラウザでアクセスします。 http://localhost:3000/bus_lines 一覧画面が表示されました。続けて新規作成画面を表示し、1件登録して、再び一覧画面に戻ります。 ここで、Webブラウザの開発ツール、「ネットワーク」で確認すると、新規作成画面以降のアクセスが XHR になっています。なんと、POST メソッドのアクセスも XHR です。 従来通りにプロジェクトを作成しただけなのに、シングルページアプリケーションができあがりました。 不思議ですね。 Turbo Frame シングルページアプリケーション(SPA)といえば、例えば一覧画面で、画面の表示直後はスピナー(ローディングインジケータ)がくるくる回って、データの取得が終わったら結果が表示される、というような動作になっていたりします。 これはつまり、フロントエンドで以下の処理を行っている、ということになります。 ローディングインジケータを表示する データ取得APIに対してリクエストを送信する 取得した JSON 文字列を分解し、テンプレートに流し込む テンプレートから生成された HTML を DOM ツリーに差し込む(画面に表示する) ローディングインジケータを非表示にする 使用するフロントエンドのフレームワークによって書き方はさまざまかと思いますが、必要な処理は同じです。 Rails 7.0 でやってみます。 app/views/bus_schedules/_schedule_table.html.erb <%= turbo_frame_tag 'bus_schedules', src: bus_schedules.nil? ? list_bus_schedules_path : nil do %> <table class="bus-schedule-table"> <thead> <tr> <th class="departure-hour">時</td> <th class="departure-minute">分</td> <th class="line">路線</td> <th class="operation">操作</td> </tr> </thead> <tbody> <% if bus_schedules.nil? %> <tr> <td colspan="4" class="loading"><%= image_tag 'loading.gif' %></td> </tr> <% else %> <% bus_schedules.each do |bus_schedule| %> <tr> <td class="departure-hour"><%= bus_schedule.departure_hour %></td> <td class="departure-minute"><%= bus_schedule.departure_minute %></td> <td class="line"><%= bus_schedule.bus_line.name %></td> <td class="operation"><%= link_to "Show this bus schedule", bus_schedule, data: { turbo_frame: '_top' } %></td> </tr> <% end %> <% end %> </tbody> </table> <% end %> app/views/bus_schedules/index.html.erb <p style="color: green"><%= notice %></p> <h1>Bus schedules</h1> <%= render partial: 'schedule_table', locals: { bus_schedules: nil } %> <%= link_to "New bus schedule", new_bus_schedule_path %> app/views/list_bus_schedules/index.html.erb <%= render partial: 'bus_schedules/schedule_table', locals: { bus_schedules: @bus_schedules } %> app/controllers/list_bus_schedules_controller.rb class ListBusSchedulesController < ApplicationController def index sleep 2 @bus_schedules = BusSchedule.all end end エラー処理などが一切ありませんが、期待通りの動作ができました。 あれ、一覧のデータ取得はどこで行っているのでしょうか?ローディングインジケータはどうやって切り替えたのでしょうか?むむ。 データ取得は、turbo_frame_tag において、src 属性にパスを指定することで行っています。src が指定されていると、ページの読み込み完了時に、自動的にそのパスにリクエストが送信されます。 turbo_frame_tag は、<turbo-frame> というタグを生成します。リクエストから応答が返却されると、その内容で、<turbo-frame> の中身が置き換わります。これにより、最初に表示していたローディングインジケータが消え、一覧に切り替わる、という動作になります。 ところで、ここに至るまで、このプロジェクトでは、まだ1行も JavaScript を書いていません。 不思議ですね。 Turbo Stream フロントエンドといえば、サーバプッシュの仕組みもよく利用されています。たとえばチャットの画面で、誰かが送信したメッセージが自動的に自分の Web ブラウザの画面に反映される、というような状況です。 WebSocket を用いる場合、フロントエンド側では以下の処理を行う必要があります。 コネクションを確立する。 サーバ側からのイベントを受け取る。 イベントからデータを取り出し、テンプレートに流し込む テンプレートから生成された HTML を DOM ツリーに差し込む(画面に表示する) チャットではありませんが、Webブラウザのタブを2つ開き、片方は一覧画面、もう片方は新規作成画面として、新規作成を行うと自動的に一覧画面に反映される、ということをやってみます。 app/models/bus_line.rb class BusLine < ApplicationRecord has_many :bus_schedules after_create_commit -> { broadcast_append_to 'bus_lines', partial: 'bus_lines/list_item' } after_update_commit -> { broadcast_update_to 'bus_lines', partial: 'bus_lines/list_item' } after_destroy_commit -> { broadcast_remove_to 'bus_lines' } end app/views/bus_lines/_list_item.html.erb <tr id="<%= dom_id bus_line %>"> <td class="name"><%= bus_line.name %></td> <td class="operation"><%= link_to "Show this bus line", bus_line, data: { turbo_frame: '_top' } %></td> </tr> app/views/bus_lines/index.html.erb <p style="color: green"><%= notice %></p> <h1>Bus lines</h1> <table class="bus-line-table"> <thead> <tr> <th class="name">Name</th> <th class="operation">操作</th> </tr> </thead> <tbody id="bus_lines"> </tbody> </table> <%= link_to "New bus line", new_bus_line_path %> <%= turbo_stream_from 'bus_lines' %> <% @bus_lines.each do |bus_line| %> <%= turbo_stream.append(:bus_lines, partial: "list_item", locals: { bus_line: bus_line }) %> <% end %> おや、どこでコネクションを確立したのでしょうか?どうやって画面上の一覧に新しい行を追加しているのでしょうか? ERB のテンプレート内、turbo_stream_from 'bus_lines' が、コネクションを表しています。 モデルの broadcast_append_to が、コネクションに対してデータを追加するイベントを送信します。DBテーブルにレコードが追加された時に、この処理を実行しているので、新規作成の処理に合わせて一覧が更新される、というどうさになりました。 なんと、ここに至るまで、JavaScript を1行も書いていません。 不思議ですね。 Stimulus 別にフロントエンドを毛嫌いしているわけでもなく、フロントエンドなしで何でもできるわけでもありません。 例えば、特に意味はありませんが、一覧画面において、いずれかの行がクリックされたら、その行の背景色が変わるようにしてみます。 必要な処理は以下のようになります。 行がクリックされたことを検知できるようにする 他の行の選択状態を解除する (選択状態であることを示すクラスを取り除く) クリックされた行を選択状態にする (選択状態であることを示すクラスをセットする) Rails 7.0 で書いてみます。 前述、Turbo Frame の部分で作成した _schedule_table.html.erb を編集し、かつ、JavaScript のファイルを追加します。 apps/views/bus_schedules/_schedule_table.html.erb <%= turbo_frame_tag 'bus_schedules', src: bus_schedules.nil? ? list_bus_schedules_path : nil do %> <table class="bus-schedule-table" data-controller="schedule" data-schedule-selected-class="selected"> : (中略) <% bus_schedules.each do |bus_schedule| %> <tr data-schedule-target="row" data-action="click->schedule#selectRow"> : (中略) </tr> <% end %> : (中略) </table> <% end %> app/javascript/controllers/schedule_controller.js import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = [ 'row' ]; static classes = [ 'selected' ]; // コントローラがDOMと接続された時に実行されるハンドラー connect() { this.clearState(); } // すべての行を未選択状態にする(selectedクラスを取り除く) clearState() { this.rowTargets.forEach((tableRow) => { tableRow.classList.remove(this.selectedClass); }); } // クリックされた行を選択状態にする selectRow(event) { this.clearState(); const tableRow = event.target.closest('tr'); tableRow.classList.add(this.selectedClass); } } JavaScript は、おおよそ普通に見えますね。すべての行の選択状態を解除して、クリックされた行を選択状態にする、ということをしているだけです。 普通に見えますが、よくわからない部分があります。どうして schedule_controller.js で定義したクラスが、この <table> タグに対して動作するのでしょうか。もう一つ、クリックイベントのハンドラーを設定していないように見えますが、どうやってクリックを検知しているのでしょうか。 <table> タグに、以下の記述を追加しました。 data-controller="schedule" これにより、schedule_controller.js という名前のファイルが自動的に参照されるようになります。 さらに、<tr> タグに、以下の記述を追加しました。 data-schedule-target="row" data-action="click->schedule#selectRow" これにより(targets の宣言も必要ですが)、tr タグを JavaScript のクラス内、this.rowTargets で参照できるようになります。また、data-action で、クリック時のイベントハンドラーを設定しています。 フロントエンドのフレームワークは独自にテンプレート機能を持っていますが、Rails 7.0 では、ERB がそのままフロントエンドのテンプレートになっています。 おわりに Rails 7.0 で導入された、Hotwire と呼ばれる機能について、どんな機能なのか、どうやって使うのか、について確認しました。 既存のプロジェクトを Rails 7.0 にして何も考えずに Turbo を有効にするといろいろ動かなくなりそうですが、新しいプロジェクトであれば、手軽に WebSocket が使えたりするので、よいかもしれません。 参考 Rails 7.0正式リリース、Node.js不要のフロントエンド開発環境がデフォルトに Rails 7.0: Fulfilling a vision Hotwire Rails 7 will have three great answers to JavaScript in 2021+ Rails 7.0.1 has been released Rails cashes with Ruby 3.1.0 release #43998 Ruby on Rails
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

わかりやすいrailsの中間テーブルの命名方法

結論 railsの中間テーブルは多対多の関係にある2つのテーブルを結合した命名が多いが、関係性を表現する命名にするべき。 例: usersテーブルとpoliciesテーブルの中間テーブルならagreementsテーブル(同意) (観測範囲で言うと、policies_users, users_policies、user_policiesのような命名がされるケースが多い。) 詳しくは以下の記事に詳しく書かれています。 背景 リレーショナルデータベースは「多対多」の関係をうまく扱うことができないため、 中間テーブルという第3のテーブルを使って関係性を表現します。 これまでrailsの中間テーブルの命名は一般的には多対多の関係の2つのテーブルの名前を結合したものが多かったです。(例: policies_users) これは、おそらくrails1,2時代にhas_and_belongs_to_manyメソッドでモデル間のリレーションを宣言するケースが多かったためです。 class User < ApplicationRecord has_and_belongs_to_many :policies end class Policy < ApplicationRecord has_and_belongs_to_many :users end has_and_belongs_to_manyを使用する場合、中間テーブルの命名にはルールがありました。 それは単語同士(今回の場合 users と policies)をアルファベット順に_で結合するというものです。(例: policies_users) (なおhas_and_belongs_to_manyを使用する場合、中間テーブルのモデルクラスは作成せず、migrationファイルを作成してテーブルだけ作成します。) その慣習から今でも中間テーブルの命名として、2つのテーブルを結合したものが多くなっています。 ですが、今は御存知の通りhas_many :throughで多対多のリレーションシップを宣言するケースが大半です。 class User < ApplicationRecord has_many :agreements has_many :policies, through: :agreements end class Agreement < ApplicationRecord belongs_to :user belongs_to :policy end class Policy < ApplicationRecord has_many :agreements has_many :uses, through: :agreements end has_many :throughの場合は中間テーブルに独自の名前を命名できるので、無思考に2つのテーブル名を結合するのではなく、よりわかりやすいテーブル名にするべきです。 ただし、books_authors、articles_tagsのようにそのまま結合したほうがわかりやすい場合もあるので、ケースバイケースです。 あとプロジェクトごとの命名規則もあると思うので、状況に応じて柔軟に決定してください。 なお、has_and_belongs_to_manyと、has_many :throughの違いは蛇足なので割愛しますが、以下の記事がわかりやすかったです。 お気づきの点がありましたら、ご気軽にご指摘ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsの中間テーブルのわかりやすい命名

結論 railsの中間テーブルは多対多の関係にある2つのテーブルを結合した命名が多いが、関係性を表現する命名にするべき。 例: usersテーブルとpoliciesテーブルの中間テーブルならagreementsテーブル(同意) (観測範囲で言うと、policies_users, users_policies、user_policiesのような命名がされるケースが多い。) 詳しくは以下の記事に書かれています。 背景 リレーショナルデータベースは「多対多」の関係をうまく扱うことができないため、 中間テーブルという第3のテーブルを使って関係性を表現します。 これまでrailsの中間テーブルの命名は一般的には多対多の関係の2つのテーブルの名前を結合したものが多かったです。(例: policies_users) これは、おそらくrails1,2時代にhas_and_belongs_to_manyメソッドでモデル間のリレーションを宣言するケースが多かったためです。 class User < ApplicationRecord has_and_belongs_to_many :policies end class Policy < ApplicationRecord has_and_belongs_to_many :users end has_and_belongs_to_manyを使用する場合、中間テーブルの命名にはルールがありました。 それは単語同士(今回の場合 users と policies)をアルファベット順に_で結合するというものです。(例: policies_users) (なお余談ですが、has_and_belongs_to_manyを使用する場合、中間テーブルのモデルクラスは作成せず、migrationファイルを作成してテーブルだけ作成します。) その慣習から今でも中間テーブルの命名として、2つのテーブルを結合したものが多くなっています。 ですが、今は御存知の通りhas_many :throughで多対多のリレーションシップを宣言するケースが大半です。 class User < ApplicationRecord has_many :agreements has_many :policies, through: :agreements end class Agreement < ApplicationRecord belongs_to :user belongs_to :policy end class Policy < ApplicationRecord has_many :agreements has_many :users, through: :agreements end has_many :throughの場合は中間テーブルに独自の名前を命名できるので、無思考に2つのテーブル名を結合するのではなく、よりわかりやすいテーブル名にするべきです。 ただし、books_authors、articles_tagsのようにそのまま結合したほうがわかりやすい場合もあるので、ケースバイケースです。 あとプロジェクトごとの命名規則もあると思うので、状況に応じて柔軟に決定してください。 なお、has_and_belongs_to_manyと、has_many :throughの違いは蛇足なので割愛しますが、以下の記事がわかりやすかったです。 お気づきの点がありましたら、ご気軽にご指摘ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerでソースコードが反映されない時の対処法(Rails使用)

1,development.rbの記述を変えます config.file_watcher = ActiveSupport::EventedFileUpdateChecker config.file_watcher = ActiveSupport::FileUpdateChecker Eventedを削除 2,コンテナ再起動 docker-compose down -v docker-compose up -d docker-compose run web rails db:create docker-compose exec web bundle exec rails db:migrate これで無事反映されました! ※再起動などは不要かもしれませんが自分の場合書き換えだけだと変わりませんでした
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]deviseの導入

ユーザー管理機能を簡単に実装できるdeviseというGem 初めて学んだ時は理解できず難しいと感じてたけど、使ってるうちにめちゃくちゃ便利やん!と思ったので忘備録として記事にしときます。 deviseの導入 ①Gemfileを下記のように編集 Gemfile #最後の行に追記 gem 'devise' ②下記のコマンドを実行してdeviseをインストール ターミナル % bundle install インストールしたGemの反映するタイミングはサーバー起動時なので、ローカルサーバーを起動しているのであれば再起動 ③以下のコマンドを実行して設定ファイルを作成 追加したdeviseの「設定関連に使用するファイル」を自動で生成するコマンド deviseを追加したらとりあえず1度実行しておく、くらいの認識で ターミナル % rails g devise:install このようなログが流れれば成功!             create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Depending on your application's configuration some manual setup may be required: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. * Required for all applications. * 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" * Not required for API-only Applications * 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> * Not required for API-only Applications * 4. You can copy Devise views (for customization) to your app by running: rails g devise:views * Not required * =============================================================================== ④deviseのUserモデル作成 作成には通常のモデルの作成方法(rils g model ○○)ではなく、deviseのモデル作成用コマンドでUserモデルを作成 以下のコマンドで実行 ターミナル % rails g devise user このようなログが流れれば成功! invoke active_record create db/migrate/20200309082300_devise_create_users.rb create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml insert app/models/user.rb route devise_for :users ログを見てみるとユーザーに関する、モデルやマイグレーションも自動生成されていることがわかる また、routes.rbに以下のルーティングが自動的に追記される config/routes.rb Rails.application.routes.draw do devise_for :users #追記されている end マイグーションファイルを確認してみると以下のようになっている db/migrate/20XXXXXXXXX_devise_create_users.rb class DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at # 省略 t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end デフォルトでメールアドレスやパスワードのカラムを作成する記述があることがわかる 他のカラムを追加したい場合は自身で追記する必要があり(ユーザー名など)、 自身で追加したカラムには別にストロングパラーメーターを使えるようにする記述が必要   テーブルの設計が確認できたら、rails db:migrateコマンドでマイグレーションを実行してuserテーブルを作成する。   以上がRailsにおけるdevise導入方法です これだけでユーザー管理機能が実装できるとかほんと便利すぎる!   ※補足等ありましたらコメントいただけると幸いです
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]deviseの導入手順

ユーザー管理機能を簡単に実装できるdeviseというGem 初めて学んだ時は理解できず難しいと感じてたけど、使ってるうちに理解できてきて便利さに感動! なので忘備録として記事にしときます。 deviseの導入手順 ①Gemfileを下記のように編集 Gemfile #最後の行に追記 gem 'devise' ②下記のコマンドを実行してdeviseをインストール ターミナル % bundle install インストールしたGemの反映するタイミングはサーバー起動時なので、ローカルサーバーを起動しているのであれば再起動 ③以下のコマンドを実行して設定ファイルを作成 追加したdeviseの「設定関連に使用するファイル」を自動で生成するコマンド deviseを追加したらとりあえず1度実行しておく、くらいの認識で ターミナル % rails g devise:install このようなログが流れれば成功!             create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Depending on your application's configuration some manual setup may be required: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. * Required for all applications. * 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" * Not required for API-only Applications * 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> * Not required for API-only Applications * 4. You can copy Devise views (for customization) to your app by running: rails g devise:views * Not required * =============================================================================== ④deviseのUserモデル作成 作成には通常のモデルの作成方法(rils g model ○○)ではなく、deviseのモデル作成用コマンドでUserモデルを作成 以下のコマンドで実行 ターミナル % rails g devise user このようなログが流れれば成功! invoke active_record create db/migrate/20200309082300_devise_create_users.rb create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml insert app/models/user.rb route devise_for :users ログを見てみるとユーザーに関する、モデルやマイグレーションも自動生成されていることがわかる また、routes.rbに以下のルーティングが自動的に追記される config/routes.rb Rails.application.routes.draw do devise_for :users #追記されている end マイグーションファイルを確認してみると以下のようになっている db/migrate/20XXXXXXXXX_devise_create_users.rb class DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at # 省略 t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end デフォルトでメールアドレスやパスワードのカラムを作成する記述があることがわかる 他のカラムを追加したい場合は自身で追記する必要があり(ユーザー名など)、 自身で追加したカラムには別にストロングパラーメーターを使えるようにする記述が必要   テーブルの設計が確認できたら、rails db:migrateコマンドでマイグレーションを実行してuserテーブルを作成する。   以上がRailsにおけるdevise導入方法です これだけでユーザー管理機能が実装できるとか便利すぎ!   ※補足等ありましたらコメントいただけると幸いです
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Railsの環境構築【初心者用】

動機 シンプルに手順を示した記事が無かったため作成。 できる限りシンプルにまとめました! とりあえず手元のPCでRailsを動かせるようになることを目的としていますので細かい説明は省略しています。 環境構築が終わってから、コマンドで具体的に何を行っているのか、一つずつ調べていきましょう。 環境 macOS Monterey 12.1 ひたすらインストールしていく ターミナルを開いてコマンドを入力していってください。 Command Line Tools コマンドラインツール xcode-select --install Homebrew macのパッケージ管理ツール /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" rbenv Rubyのバージョン管理ツール brew update brew install rbenv echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.zshrc echo 'eval "$(rbenv init -)"' >> ~/.zshrc source ~/.zshrc Ruby プログラミング言語のRuby 3.0.3はバージョンを示しています。 3.0.3がインストールできない場合はrbenv install -lで表示されるバージョンを指定してください。 rbenv install -l rbenv install 3.0.3 rbenv global 3.0.3 bundler Gem(ライブラリ)のバージョン管理ツール gem install bundler yarn Rails内におけるJavaScriptのバージョン管理ツール brew install yarn Ruby on Rails Webアプリケーションフレームワーク gem install rails --no-document 動作確認して完了! 以下のコマンドを実行します(数分程かかります) rails new sample_app cd sample_app rails server # Ctrl+Cで停止 ブラウザ(chromeでもsafariでもOK)のURL欄に http://localhost:3000 と入力して、以下のような画面が表示されれば環境構築成功です!お疲れさまでした! 最後のコマンドはサーバーを起動するコマンドです。 Ctrl + C で停止しておきましょう。 動作確認用アプリの削除は以下のコマンド。 cd .. rm -rf sample
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】デプロイ後の修正を反映させる方法

はじめに 「AWSでデプロイしたはいいけど、デザインを修正したくなったよー」という人に向けた記事です。 デプロイ後の修正を反映させるには masterにpushする まずはローカル環境で修正したファイルをGitHubのmasterブランチにpushします。 $ git push origin master git cloneしたディレクトリにpullする EC2インスタンスが開始されていることを確認してから、sshコマンドで接続します。 $ ssh -i 秘密鍵.pem ユーザー名@ipアドレス デプロイ時にgit cloneしたディレクトリに移動してpullします。 $ git pull origin master アセットをプリコンパイルする 修正がCSSなどの場合、アセットファイルをプリコンパイルする必要があります。 簡単にいうと、JavaScriptやCSSのアセットを通信量削減のためにギュッとまとめる仕組みです。 開発環境ではこの仕組みが自動で働いてましたが、 本番環境では行われないため手動で行います。 $ rails assets:precompile RAILS_ENV=production インスタンスを再起動して確認 EC2インスタンスを再起動し、きちんと反映されていればオッケーです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

active_hashを使って都道府県モデルを作る方法

はじめに    今回は都道府県を選択する時に使う「active_hash」について新たに学んだので備忘録としてまとめます。active_hash住所などを選択する時に都道府県を選択するプルダウンを作るために必要です。ユーザー登録をする時にはよく使いますが、47個の都道府県を毎回実装するのは大変です。そんな時に、active_hashを使うと簡単に効率よく実装する事ができます。 active_hashの実装方法 active_hashの実装方法は以下の手順です。 1gemfile 2疑似モデルを作る 3対応するカラムを作る 4アソシエーションを定義する です。 今回はuserモデルに都道府県を保持させたい場合を想定します それでは順番に説明していきます。 gemfileの導入  まずはgemfileを導入します。 ## Gemfileに以下を記述 gem 'active_hash' その後bundle installを忘れずします。 都道府県の擬似モデルを作る  次に都道府県を入れた擬似モデルを作ります まずは実施のコードをご覧ください prefecture.rb class Prefecture < ActiveHash::Base self.data = [ { id: 1, name: '--' }, { id: 2, name: '北海道' }, { id: 3, name: '青森県' }, { id: 4, name: '岩手県' }, { id: 5, name: '宮城県' }, { id: 6, name: '秋田県' }, { id: 7, name: '山形県' }, { id: 8, name: '福島県' }, { id: 9, name: '茨城県' }, { id: 10, name: '栃木県' }, { id: 11, name: '群馬県' }, { id: 12, name: '埼玉県' }, { id: 13, name: '千葉県' }, { id: 14, name: '東京都' }, { id: 15, name: '神奈川県' }, { id: 16, name: '新潟県' }, { id: 17, name: '富山県' }, { id: 18, name: '石川県' }, { id: 19, name: '福井県' }, { id: 20, name: '山梨県' }, { id: 21, name: '長野県' }, { id: 22, name: '岐阜県' }, { id: 23, name: '静岡県' }, { id: 24, name: '愛知県' }, { id: 25, name: '三重県' }, { id: 26, name: '滋賀県' }, { id: 27, name: '京都府' }, { id: 28, name: '大阪府' }, { id: 29, name: '兵庫県' }, { id: 30, name: '奈良県' }, { id: 31, name: '和歌山県' }, { id: 32, name: '鳥取県' }, { id: 33, name: '島根県' }, { id: 34, name: '岡山県' }, { id: 35, name: '広島県' }, { id: 36, name: '山口県' }, { id: 37, name: '徳島県' }, { id: 38, name: '香川県' }, { id: 39, name: '愛媛県' }, { id: 40, name: '高知県' }, { id: 41, name: '福岡県' }, { id: 42, name: '佐賀県' }, { id: 43, name: '長崎県' }, { id: 44, name: '熊本県' }, { id: 45, name: '大分県' }, { id: 46, name: '宮崎県' }, { id: 47, name: '鹿児島県' }, { id: 48, name: '沖縄県' } ] end このようにして都道府県の擬似モデルを作ります。 ここで注意してもらいたいのが、 「class Prefecture < ActiveHash::Base」の部分です。 ActiveHash::Baseという記述は、あるモデルの中でActiveHashを使うために必要となるクラスです。 ActiveHash::Baseを継承することで、ActiveRecordと同じようなメソッドを使用できるようになります。 従って今回の例で言うと、user.prefecture.nameであるuserの出身地をとってくる事ができます。 適用したいモデルに、prefecture_idカラムを作る  次に都道府県を使用したいモデルにprefecture_idカラムを追加します。 今回はuserのマイグレーションファイルに記述します。 t.integer :prefecture_id, null: false 注意点としては、 ・id値が数値なのでintegerを指定する事 ・カラム名に_idをつける事です このようにする事で、userに紐づく都道府県をとってくる事ができます。 アソシエーションの設定  次にuserモデルとprefectureモデル間でのアソシエーションを設定します まずはuserモデルです。 user.rb class User < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions belongs_to :prefecture end userは必ず一つの都道府県に紐づいているので、prefectureに対してbelongs_toの関係です。 ここで注意点はextend ActiveHash::Associations::ActiveRecordExtensionsと記述してモジュールを取り込んでいる事です。 次にprefectureモデルです。 prefecture.rb class Prefecture < ActiveHash::Base self.data = [ { id: 1, name: '--' }, { id: 2, name: '北海道' }, { id: 3, name: '青森県' }, { id: 4, name: '岩手県' }, { id: 5, name: '宮城県' }, { id: 6, name: '秋田県' }, { id: 7, name: '山形県' }, { id: 8, name: '福島県' }, { id: 9, name: '茨城県' }, 〜〜中略〜〜 ] include ActiveHash::Associations has_many :items end 都道府県は複数のuserに紐づくので、userに対してhas_manyの関係です。 注意点としてはinclude ActiveHash::Associationsと記述してモジュールを取り込んでいる事です。   以上ここまでで都道府県モデルを作る事ができした。 まとめ  今回はactive_hashを使って都道府県モデルを作る方法についてまとめました。  active_hashを使う利点としては固定値の使い回しができる事です。都道府県はuser以外にもいろいろな場面で使われます。そのような時に都道府県モデルがあると、効率的に実装を進める事ができます。 以上今回の記事が少しでも誰かのお役に立てれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【CircleCI】bundle installされない場合の対処方法

railsでポートフォリオ作成時にCircleCIを導入したところ、 bundle exec rails db:migrate実行時にエラーが発生しました。 ログ上ではbundle installしてたがbundle installしろとのこと。。。 ググっても解決策が見つからず、かなりハマってしまったので記録しておきます。 エラー内容 エラーメッセージ Could not find rake-13.0.6 in any of the sources Run `bundle install` to install missing gems. 解決策 プレフィックスが「 circleci / 」のレガシーイメージは、 2021 年 12 月 31 日に廃止されます。 ビルドを高速化するには、次世代の CircleCI イメージを使ってプロジェクトをアップグレードしてください。 引用元 とのことだったので、config.yml で指定しているDockerイメージを下記のように修正したら解決しました。 .circleci/config.yml version: 2.1 orbs: ruby: circleci/ruby@1.1.2 jobs: build: docker: + - image: cimg/ruby:2.7.5 - - image: circleci/ruby:2.7.5 working_directory: ~/app/src steps: - checkout: path: ~/app - ruby/install-deps test: docker: + - image: cimg/ruby:2.7.5 - - image: circleci/ruby:2.7.5 - image: circleci/postgres:13.5 environment: POSTGRES_USER: postgres POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_DB: app_test environment: BUNDLE_JOBS: "3" BUNDLE_RETRY: "3" APP_DATABASE_HOST: "127.0.0.1" RAILS_ENV: test working_directory: ~/app/src steps: - checkout: path: ~/app - ruby/install-deps - run: name: Database setup command: bundle exec rails db:migrate - run: name: test command: bundle exec rake test workflows: version: 2 build_and_test: jobs: - build - test: requires: - build
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む