20210516のRubyに関する記事は16件です。

【rails】gemを使って簡易的なハッシュタグ機能を実装する

はじめに act_as_taggrable_onというgemを使って簡易的なハッシュタグ機能を実装しようと思います。 エラーがでたりして複数の記事をみながら実装し時間がかかったので、1つにまとめて見やすいように備忘録としてこの記事を執筆します。 用意するもの シンプルな投稿機能は用意しておいてください。 環境 windows10 ruby 2.6.6 rails 6.0 実装 1.gemをインストールする Gemfile. gem 'acts-as-taggable-on', '~> 7.0' $ bundle install 2.テーブルを作成する $ rails acts_as_taggable_on_engine:install:migrations 次にrails db:migrateをする前に、作成された6つのマイグレーションファイルのうち○○○○_add_missing_unique_indices.acts_as_taggable_on_engine.rbの以下の行をコメントアウトします。 db/migrate/○○○○_add_missing_unique_indices.acts_as_taggable_on_engine.rb AddMissingUniqueIndices.class_eval do def self.up add_index ActsAsTaggableOn.tags_table, :name, unique: true #remove_index ActsAsTaggableOn.taggings_table, :tag_id if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id) # ↑上記をコメントアウト remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_taggable_context_idx' add_index ActsAsTaggableOn.taggings_table, [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type], unique: true, name: 'taggings_idx' end def self.down remove_index ActsAsTaggableOn.tags_table, :name remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_idx' add_index ActsAsTaggableOn.taggings_table, :tag_id unless index_exists?(ActsAsTaggableOn.taggings_table, :tag_id) add_index ActsAsTaggableOn.taggings_table, [:taggable_id, :taggable_type, :context], name: 'taggings_taggable_context_idx' end end そして、マイグレーションを行います。 $ rails db:migrate ※マイグレーションファイルを編集する前にrails db:migrateを行うと、エラーがでてきます。 3.モデルとコントローラーに追加 post.rb class Post < ApplicationRecord acts_as_taggable #追加 end posts_controller.rb class PostsController < ApplicationController def index @posts = Post.all #ここから追加 if params[:tag_name] @posts = Post.tagged_with("#{params[:tag_name]}") end #ここまで end #省略 private def post_params params.require(:post).permit(:body, :tag_list) #tag_list を追加 end end 4.ビューの編集 投稿ページ new.html.erb <%= form_for @post do |f| %> <div class="field"> <%= f.label :投稿内容 %> <br> <%= f.text_area :body %> </div> #ここから追加  <div class="field"> <%= f.label :タグ %> <%= f.text_field :tag_list, value: @post.tag_list %>   </div>   #ここまで <%= f.submit "投稿する" %> <% end %> 投稿一覧ページ index.html.erb <% @posts.each do |p| %> #省略 <%= render 'posts/tag_list', tag_list: p.tag_list %> #追加 <% end %> _tag_list.html.erbファイルを作成 _tag_list.html.erb <% tag_list.each do |tag| %> <%= link_to tag, posts_path(tag_name: tag) %> <% end %> これで完成です! 複数のタグを作成するためにはタグとタグをカンマで区切ります。 区切り方をカンマから半角スペースにする方法 半角スペースなどで区切りたい場合は、config/initializers に acts_as_taggable_on.rb を作成して、以下のように記述します。 acts_as_taggable_on.rb ActsAsTaggableOn.delimiter = ' ' その後、一度サーバー再起動すると半角スペースでタグを区切れるようになります。 参考記事 Rails | acts-as-taggable-on を使ったタグ機能の実装 | 備忘録 Railsにタグ機能をつける。acts-as-taggable-on使用 【Rails】acts-as-taggable-onの区切り文字の変更 acts-as-taggable-on導入時のエラー
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【rails】gemを使って簡易的なタグ機能を実装する

はじめに act_as_taggrable_onというgemを使って簡易的なタグ機能を実装しようと思います。 エラーがでたりして複数の記事をみながら実装し時間がかかったので、1つにまとめて見やすいように備忘録としてこの記事を執筆します。 用意するもの シンプルな投稿機能は用意しておいてください。 環境 windows10 ruby 2.6.6 rails 6.0 実装 1.gemをインストールする Gemfile. gem 'acts-as-taggable-on', '~> 7.0' $ bundle install 2.テーブルを作成する $ rails acts_as_taggable_on_engine:install:migrations 次にrails db:migrateをする前に、作成された6つのマイグレーションファイルのうち○○○○_add_missing_unique_indices.acts_as_taggable_on_engine.rbの以下の行をコメントアウトします。 db/migrate/○○○○_add_missing_unique_indices.acts_as_taggable_on_engine.rb AddMissingUniqueIndices.class_eval do def self.up add_index ActsAsTaggableOn.tags_table, :name, unique: true #remove_index ActsAsTaggableOn.taggings_table, :tag_id if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id) # ↑上記をコメントアウト remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_taggable_context_idx' add_index ActsAsTaggableOn.taggings_table, [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type], unique: true, name: 'taggings_idx' end def self.down remove_index ActsAsTaggableOn.tags_table, :name remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_idx' add_index ActsAsTaggableOn.taggings_table, :tag_id unless index_exists?(ActsAsTaggableOn.taggings_table, :tag_id) add_index ActsAsTaggableOn.taggings_table, [:taggable_id, :taggable_type, :context], name: 'taggings_taggable_context_idx' end end そして、マイグレーションを行います。 $ rails db:migrate ※マイグレーションファイルを編集する前にrails db:migrateを行うと、エラーがでてきます。 3.モデルとコントローラーに追加 post.rb class Post < ApplicationRecord acts_as_taggable #追加 end posts_controller.rb class PostsController < ApplicationController def index @posts = Post.all #ここから追加 if params[:tag_name] @posts = Post.tagged_with("#{params[:tag_name]}") end #ここまで end #省略 private def post_params params.require(:post).permit(:body, :tag_list) #tag_list を追加 end end 4.ビューの編集 投稿ページ new.html.erb <%= form_for @post do |f| %> <div class="field"> <%= f.label :投稿内容 %> <br> <%= f.text_area :body %> </div> #ここから追加  <div class="field"> <%= f.label :タグ %> <%= f.text_field :tag_list, value: @post.tag_list %>   </div>   #ここまで <%= f.submit "投稿する" %> <% end %> 投稿一覧ページ index.html.erb <% @posts.each do |p| %> #省略 <%= render 'posts/tag_list', tag_list: p.tag_list %> #追加 <% end %> _tag_list.html.erbファイルを作成 _tag_list.html.erb <% tag_list.each do |tag| %> <%= link_to tag, posts_path(tag_name: tag) %> <% end %> これで完成です! 複数のタグを作成するためにはタグとタグをカンマで区切ります。 区切り方をカンマから半角スペースにする方法 半角スペースなどで区切りたい場合は、config/initializers に acts_as_taggable_on.rb を作成して、以下のように記述します。 acts_as_taggable_on.rb ActsAsTaggableOn.delimiter = ' ' その後、一度サーバー再起動すると半角スペースでタグを区切れるようになります。 参考記事 Rails | acts-as-taggable-on を使ったタグ機能の実装 | 備忘録 Railsにタグ機能をつける。acts-as-taggable-on使用 【Rails】acts-as-taggable-onの区切り文字の変更 acts-as-taggable-on導入時のエラー
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby]クラスメソッドの定義には2種類ある!

はじめに まずは、特異クラスや特異メソッドとは何か分かるでしょうか?? タイトルにある通り、クラスメソッドの定義方法には2種類あり、特異メソッド方式と特異クラス方式があります。 名前はなんとなく分かるけど、使い方が分からないとか、その逆もあることかと思います。 習得すれば、強力な武器になると思うので、ぜひ覚えていってください! 特異メソッドとは 特異メソッドとは1つのインスタンス固有のメソッドのことを指します。 特定のインスタンスに特別な性質を持たせたい場面に活躍します。 特異メソッドの定義方法 # helloオブジェクトを作成 hello = 'hello' # helloオブジェクトにsayメソッドを作成(特異メソッド) def hello.say(count = 1) count.times { print self } # ここでのselfは「hello」となる end hello.say(2) #=> hellohello 特異クラスとは あるオブジェクトに特異メソッドを定義した際に、そのメソッドが定義されるクラスが特異クラスです。 通常のクラスとは違い、特異クラスはあるオブジェクトだけが使用するクラスです。(主にselfオブジェクトであることが多いです) そのため、特異クラスからオブジェクトを作成したり、サブクラスを作成することは禁止されています。 特異クラスの定義方法 # helloオブジェクトを作成 hello = 'hello' # この中で定義されたメソッドはすべて「hello.メソッド名」の特異メソッドとなる class << hello def say(count = 1) count.times { print self } # ここでのselfは「hello」となる end end hello.say(2) #=> hello, world class << selfの解説 class 〜 endの間に定義することで、インスタンスがアクセス可能なインスタンスメソッドが定義されますが、class << self 〜 endの間に書くことで、クラス自体にメソッドが定義されます。 class Foo def hello puts 'hello' end class << self def sample puts 'sample' end end end # Fooクラスのインスタンスを作成 foo = Foo.new # fooインスタンスにはhelloが定義されているので実行される foo.hello #=> hello # fooインスタンスではsampleメソッドにアクセス出来ない foo.sample #=> NoMethodError # Fooクラスのクラスメソッドなので正しく実行される Foo.sample #=> "sample" # Fooクラスのインスタンスメソッドなので、クラスではアクセス出来ない Foo.hello #=> NoMethodError 終わりに 特異クラスや特異メソッドについての理解が深まりましたでしょうか? 理想は使いこなすことですが、足掛かりになればと思います。 共に頑張って習得しましょう!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby]特異メソッドの定義方法には2種類ある!

はじめに まずは、特異クラスや特異メソッドとは何か分かるでしょうか?? タイトルにある通り、特異メソッドの定義方法には2種類あり、特異クラス定義式による方法と特異メソッド定義式による方法があります。 名前はなんとなく分かるけど、使い方が分からないとか、その逆もあることかと思います。 習得すれば、強力な武器になると思うので、ぜひ覚えていってください! 特異メソッドとは 特異メソッドとは1つのインスタンス固有のメソッドのことを指します。 特定のインスタンスに特別な性質を持たせたい場面に活躍します。 特異メソッドの定義方法 # helloオブジェクトを作成 hello = 'hello' # helloオブジェクトにsayメソッドを作成(特異メソッド) def hello.say(count = 1) count.times { print self } # ここでのselfは「hello」となる end hello.say(2) #=> hellohello Object#define_singleton_methodメソッドを使用して、特異メソッド作成することも可能です。 class Foo class << self def class_name to_s end end end # helloという特異メソッドを定義 Foo.define_singleton_method(:hello) do "Hello! #{class_name}" end # helloメソッドを呼び出し Foo.hello #=> "Hello! Foo" 特異クラスとは あるオブジェクトに特異メソッドを定義した際に、そのメソッドが定義されるクラスが特異クラスです。 通常のクラスとは違い、特異クラスはあるオブジェクトだけが使用するクラスです。(主にselfオブジェクトであることが多いです) そのため、特異クラスからオブジェクトを作成したり、サブクラスを作成することは禁止されています。 特異クラスの定義方法 # helloオブジェクトを作成 hello = 'hello' # この中で定義されたメソッドはすべて「hello.メソッド名」の特異メソッドとなる class << hello def say(count = 1) count.times { print self } # ここでのselfは「hello」となる end end hello.say(2) #=> hello, world class << selfの解説 class 〜 endの間に定義することで、インスタンスがアクセス可能なインスタンスメソッドが定義されますが、class << self 〜 endの間に書くことで、クラス自体にメソッドが定義されます。 class Foo def hello puts 'hello' end class << self def sample puts 'sample' end end end # Fooクラスのインスタンスを作成 foo = Foo.new # fooインスタンスにはhelloが定義されているので実行される foo.hello #=> hello # fooインスタンスではsampleメソッドにアクセス出来ない foo.sample #=> NoMethodError # Fooクラスのクラスメソッドなので正しく実行される Foo.sample #=> "sample" # Fooクラスのインスタンスメソッドなので、クラスではアクセス出来ない Foo.hello #=> NoMethodError 終わりに 特異クラスや特異メソッドについての理解が深まりましたでしょうか? 理想は使いこなすことですが、足掛かりになればと思います。 共に頑張って習得しましょう!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

erb でコメントアウトする方法

.erb のファイルを編集するとき<%= %>で囲まれた行が、ctrl + / でコメントアウトされないので調べてみた。 "#"を "<%" と "=" のあいだに入れるだけでした。 application.html.erb <%#= debug(params) if Rails.env.development? %> ほかにも方法があるみたいです。 ・Ruby の複数行コメント =begin ... =end を使う方法 <% =begin %> ... <% =end %> ・if false で囲う方法 <% if false %> ... <% end %> 参考 https://ja.stackoverflow.com/questions/43321/html-erb%E3%81%A7%E3%81%AE%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E3%82%A2%E3%82%A6%E3%83%88%E3%81%AE%E6%96%B9%E6%B3%95
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

redirect_back(fallback_location: root_url)で常にエラーが発生していた話

前提 rspecでmod操作をチェックすることができるようになったので、確認ダイアログが表示される操作の統合テストを追加した。(data: { confirm: "削除してよろしいですか?" }の部分) しかしその際に、エラーが発生したので、その修正に軌跡をここに記しておくこととする。 ちなみに、RSpecで確認ダイアログを操作するコードは以下を参考にしました。ありがとうございました!! 結論 遷移の前のページが削除される操作の場合、redirect_backという指示は適切ではない。 エラーの原因とその修正 テストした箇所と、エラーが発生していた部分、その修正。 app/views/works/show.html.erb : <% if current_user?(@work.user) %> <div class="work--settings"> <span class="delete_btn field__negative"> <%= link_to "削除する", work_path(@work), method: :delete, data: { confirm: "削除してよろしいですか?" } %> </span> </div> <% end %> : app/controllers/works_controller.rb class WorksController < ApplicationController : def destroy @work.destroy flash[:success] = "削除しました。" - redirect_back(fallback_location: root_url) + redirect_to root_url end : spec/system/works/create_work_spec.rb require "rails_helper" RSpec.describe "Create or delete work", type: :system, js: true do let(:user) { create(:user) } let(:work) { create(:work, user_id: user.id) } it "delete work" do sign_in user visit work_path work within(".work--settings") do expect(page).to have_selector "span.delete_btn" page.accept_confirm do click_link "削除する" end end end end エラーコード Create or delete work delete work (FAILED - 1) Failures: 1) Create or delete work delete work Failure/Error: @work = Work.includes( [ :user, comments: :user, image_attachment: :blob, illustrations: [photo_attachment: :blob], ] ).find(params[:id]) ActiveRecord::RecordNotFound: Couldn't find Work with 'id'=3313 # ./app/controllers/works_controller.rb:15:in `show' : # ------------------ # --- Caused by: --- # Capybara::CapybaraError: # Your application server raised an error - It has been raised in your test code because Capybara.raise_server_errors == true # /usr/local/bundle/gems/capybara-3.35.3/lib/capybara/session.rb:160:in `raise_server_error!' Finished in 5.17 seconds (files took 3.93 seconds to load) 1 example, 1 failure 原因 原因は削除操作にて、redirect_back(fallback_location: root_url)という、redirect_backの操作を行っていた事に由来します。 app/controllers/works_controller.rb class WorksController < ApplicationController : def destroy @work.destroy flash[:success] = "削除しました。" - redirect_back(fallback_location: root_url) + redirect_to root_url end : fallback_locationというオプションは遷移前のページのURL取得する操作でした。しかし、遷移の前のページ(今回でいうworks/show.html.erb)が削除される操作の場合は、そもそもredirect_backという指示は適切なはずがなく、エラーが発生していました。 ちなみにこの修正は、以下の記事を参考にしました。ありがとうございました! つまり、自分のアプリケーションにはエラーが発生するコードが、常に内在していた、と言うことになります。情けない、、 改めてテストの重要性に気付かされました。 今回の記事は以上です、最後まで読んでいただきありがとうございました!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby で解く AtCoder ABC 201 D

はじめに AtCoder Problems の Recommendation を利用して、過去の問題を解いています。 AtCoder さん、AtCoder Problems さん、ありがとうございます。 今回のお題 AtCoder Beginner Contest D - Game in Momotetsu World Difficulty: 1317 今回のテーマ、ミニマックス法 本番中に分からなかったのですが、座標の和の奇遇(x + y) % 2で先手後手が定まることを利用して解いていきます。 ユーザ解説 user.rb def dp(x, y) return @memo[y][x] if @memo[y][x] if (x + y) % 2 == 0 @memo[y][x] = -10000 if y < @h - 1 if @memo[y][x] < dp(x, y + 1) + @a[y + 1][x] @memo[y][x] = dp(x, y + 1) + @a[y + 1][x] end end if x < @w - 1 if @memo[y][x] < dp(x + 1, y) + @a[y][x + 1] @memo[y][x] = dp(x + 1, y) + @a[y][x + 1] end end else @memo[y][x] = 10000 if y < @h - 1 if @memo[y][x] > dp(x, y + 1) - @a[y + 1][x] @memo[y][x] = dp(x, y + 1) - @a[y + 1][x] end end if x < @w - 1 if @memo[y][x] > dp(x + 1, y) - @a[y][x + 1] @memo[y][x] = dp(x + 1, y) - @a[y][x + 1] end end end @memo[y][x] end @h, @w = gets.split.map(&:to_i) @a = Array.new(@h){ gets.chomp.bytes.map{ _1 == 43 ? 1 : -1 } } @memo = Array.new(@h){ [nil] * @w } @memo[@h - 1][@w - 1] = 0 opt = dp(0, 0) if 0 < opt puts 'Takahashi' elsif opt == 0 puts 'Draw' else puts 'Aoki' end ユーザ解説 を参考にしたコードです。 memo.rb if (x + y) % 2 == 0 @memo[y][x] = -10000 if y < @h - 1 if @memo[y][x] < dp(x, y + 1) + @a[y + 1][x] @memo[y][x] = dp(x, y + 1) + @a[y + 1][x] end end (x + y) % 2が0なので先手の手番になります。 dp(x, y + 1)のy + 1は下方向の移動を意味しています。 bytes.rb @a = Array.new(@h){ gets.chomp.bytes.map{ _1 == 43 ? 1 : -1 } } 43は+の文字コードを表す整数です。 文字同士の比較より高速に動作します、といいますかこの問題はRubyにとって実行時間が厳しい問題ですね。 ord.rb p "+".ord # => 43 Qiitaユーザ解説 user.rb h, w = gets.split.map(&:to_i) grid = Array.new(h){ gets.chomp.chars.map{ _1 == '+' ? 1 : -1 } } dp = Array.new(h){ [0] * w } dp[-1][-1] = 0 (h - 1).downto(0) do |row| (w - 1).downto(0) do |col| next if row == h - 1 && col == w - 1 if (row + col) % 2 == 0 s1 = -10000 s2 = -10000 s1 = dp[row + 1][col] + grid[row + 1][col] if row < h - 1 s2 = dp[row][col + 1] + grid[row][col + 1] if col < w - 1 dp[row][col] = [s1, s2].max else s1 = 10000 s2 = 10000 s1 = dp[row + 1][col] - grid[row + 1][col] if row < h - 1 s2 = dp[row][col + 1] - grid[row][col + 1] if col < w - 1 dp[row][col] = [s1, s2].min end end end x = dp[0][0] if x == 0 puts 'Draw' elsif x > 0 puts 'Takahashi' else puts 'Aoki' end @u2dayo さんの【AtCoder解説】PythonでABC201のA,B,C,D問題を制する! を参考にしたコードです。 ユーザ解説は再帰でしたが、こちらはループで解きます。 RubyU RubyQ コード長 (Byte) 999 805 実行時間 (ms) 1750 1510 メモリ (KB) 84476 77924 まとめ ABC 201 D を解いた hamayanhamayan さんありがとう u2dayo さんありがとう
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails初学者によるRailsチュートリアル学習記録⑨ 第8章

目次 1. はじめに 2. 第8章の概要 3. 学習内容 4. 終わりに 1. はじめに この記事は、Rails初学者の工業大学三年生がRailsチュートリアルの学習記録をつけるための記事です。 筆者自体がRailsやWebについて知識が少ないので、内容の解釈などに間違いがある可能性があります。(その時はコメントで指摘してくださると助かります!) Railsチュートリアル内ではRailsの内容以外にも、gitでのバージョン管理やHerokuを使ったデプロイも学習しますが、gitに関しては既に私が学習済みのため学習記録には記述しません。 演習の記録も省略します。 2. 第7章の概要 前回の章でユーザー登録が可能になったので、この章ではユーザーがログイン・ログアウトを行えるようにします。 ここで実装するログインの仕組みは、ユーザーがログインしているという状態をブラウザが保持し、 ブラウザが閉じられたときにその状態を破棄するという認証システムです。 他にも、ログインしているかしていないかによって、ヘッダーの内容を変えるという認可モデルの一部を実装していきます。 セッションについて セッションとは セッションによってログイン機能を実現する ログインフォームの作成 フォームの処理 ログイン機能の実装 フラッシュによるエラーの表示 ログアウト機能の実装 ログインしている時としていない時でヘッダーの内容を変える 3. 学習内容 1. セッションについて 1-1. セッションとは セッションとはブラウザ上でユーザーが入力した情報などを、他のページに移動したときに保持しておける通信のことです。 普段利用しているHTTPプロトコルは「ステートレス」なプロトコルであり、 リクエスト1つ1つがそれ以前のリクエストの情報を全く利用しないという性質があります。 実装するログイン機能は、ユーザーのIDをブラウザが保持する必要があります。 よって、ログイン機能にはセッションを利用した通信が必要です。 Railsでセッションを実装する一般的な方法はcookiesを使う方法です。 この章ではsessionメソッドで一時セッションを作成します。 この一時セッションは、ブラウザが閉じられたときに自動的に終了するものです。 半永続的に続くセッションは9章でcookiesメソッドを使用して作成します。 1-2. セッションによってログイン機能を実現する ログイン機能を実装するために、コマンドを使用してSessionsコントローラーを作成します。 ログイン・ログアウトの処理はこのコントローラーのRESTアクションに対応付けます。 具体的には以下の表のようにアクションと処理の対応付けを行います。 実装する処理 対応するアクション ログインフォーム new ログイン create ログアウト delete この時点で、この3つのアクションのルーティングを行います。 2. ログインフォームの作成 2-1. フォームの処理 ルーティングが設定できたらログインフォームから作成していくのですが、 前回(第7章)で作成した、ユーザー登録用のフォームとほとんど同じなので、 ここでは前回作成したフォームとの違いを記述します。 ①入力フィールドの数 ユーザー登録時には名前、メールアドレス、パスワード、パスワードの確認の4つの入力フィールドが あったのに対して、ログインにはメールアドレスとパスワードの2つに減っています。 ②エラーメッセージの表示方法 ユーザー登録時に入力した情報が、文字数などの条件を満たしていなかったときは、エラーメッセージを表示しました。 今回は入力した情報に誤りがあった場合にエラーメッセージを表示させたいのですが、その時に使用する方法が前回と異なります。 前回はユーザー登録時にUserモデルを使用して@userというオブジェクトを生成しており、 そのオブジェクトに値を渡していました。 この場合、モデルの属性に文字数などの条件が設定されており、それを満たしていない場合はActive Recordによって エラーメッセージが生成されていました。 今回はSessionモデルというものを使用していないため、Active Recordによるエラーメッセージの生成が行われません。 よって、フラッシュメッセージによってエラーを表示します。 ③form_withヘルパーに渡す情報 先述したSessionモデルを使用していないという違いは、form_withヘルパーを使用する場面でも影響してきます。 ユーザー登録フォームでは以下のようにform_withヘルパーを使用していました。 <%= form_with(model: @user, local: true) do |f| %> Railsでは上記のように書くとフォームは「/usersというURLへのPOSTリクエスト」と自動で判定します。 しかし、モデルを使用してない場合はこのように書くことができないので、 ログインフォームでは以下のようにフォームの送信先のURLを指定する必要があります。 <%= form_with(url: login_path, scope: :session, local: true) do |f| %> また、socpeに指定されている:sessionというシンボルは、 フォームの値を渡す際に使用されるハッシュの名前になります。 2-2. ログイン機能の実装 ログイン機能の処理は以下のように行われます。 ①ユーザーがメールアドレスとパスワードを入力する ↓ ②メールアドレスを受け取って該当するユーザーを検索する ↓ ③検索で取り出されたユーザーのパスワードと入力されたパスワードが一致するかを判断する ↓ ④パスワードが正しければユーザーを使用してセッションを作成する パスワードが間違っていた場合、ログインフォームを再表示する ①を行うためのログインフォームはこれまでで実装できたので、②以降の処理を実装していきます。 ②の処理は、メールアドレスを使用したユーザーの検索なので、find_byメソッドで実装できます。 入力されたメールアドレスはユーザー登録フォームの時のように、入れ子になったハッシュとして渡されます。 form_withヘルパーで指定したscope: :sessionから入力された情報はsessionというハッシュに入ることが分かります。 このハッシュは以下のように表すことができます。 session: { passsword: "入力されたパスワード" email: "入力されたメールアドレス" } そしてこのハッシュはparamsというハッシュの中に入っているので下のように表します。 params[:session] よってデータには以下のように書いてアクセスします。 params[:session][:email] 以上のことから検索の処理は user = User.find_by(email: params[:session][:email].downcase)のように書きます。 ③は検索したユーザーのパスワードと入力されたパスワードが一致しているかを調べるため、 authenticateメソッドを使用します。 このメソッドでは引数に渡した値がユーザーのパスワードと一致したらtrueを返し、一致しなければfalseを返すので if user && user.authenticate(params[:session][:password])という条件式を作れます。 この条件式でなぜuserを使用しているかというと、その前のユーザーの検索でユーザーが存在したかどうかを確かめるためです。 ようやく④でログイン処理が登場します。 とはいってもコード自体は短く、session[:user_id] = user.idという一行で済んでしまいます。 このログイン処理はSessionヘルパーにlog_inという名前のメソッドとして定義しておくと便利です。 パスワードが誤っていた時のページの再表示はrenderメソッドで実装できます。 ここまでの②から④までをまとめるとcreateアクションは以下のようになります app/controlles/sessions_controller.rb def create user = User.find_by(email: params[:session][:email].downcase) if user && user.authenticate(params[:session][:password]) log_in user redirect_to user else render 'new' end end 2-3. フラッシュによるエラーの表示 フラッシュは、前回ウェルカムメッセージを表示するために使用しました。 その時のコードが↓です app/controlles/users_controller.rb def create @user = User.new(user_params) if @user.save # 保存に成功したときの処理 log_in @user flash[:success] = "Welcome to the Sample App!" # フラッシュを使用したウェルカムメッセージ redirect_to @user else # 保存が失敗したときの処理 render 'new' end end 今回もこのようにflashハッシュにメッセージを代入するのですが、前回のコードに倣って先ほどのログイン機能のコードに flash[:danger] = "メールアドレスとパスワードの組み合わせに誤りがあります" と記述すると正しく動作しません。 具体的にどのような不具合が発生するかというと、フラッシュメッセージが表示されたまま消えなくなってしまいます。 フラッシュメッセージは別のページに遷移したり、リロードするはずなのですがそうならないのです。 原因を探すためにユーザー登録機能のコードとログイン機能のコードを比較しましょう。 ユーザー登録機能のcreateアクションの一部 if @user.save # 保存に成功したときの処理 log_in @user flash[:success] = "Welcome to the Sample App!" # フラッシュを使用したウェルカムメッセージ redirect_to @user ログイン機能のcreateアクションの一部 if user && user.authenticate(params[:session][:password]) log_in user redirect_to user else flash[:danger] = "メールアドレスとパスワードの組み合わせに誤りがあります" render 'new' end 上記の2つのコードを比較するとflashハッシュに値を代入した後のビューの表示方法が違うことが分かります。 ユーザー登録機能はredirect_toメソッドを使用しているのに対して、ログイン機能ではrenderメソッドを使用しています。 これが先ほどの不具合の原因でrenderメソッドはリクエストとみなされないため、リクエスト時のメッセージがきえないのです。 この不具合を解消するにはflash.now[:danger:]と書いて値を代入します。 flash.nowによってその後のリクエストが発生したときにメッセージが消えるようになります。 2-4. ログアウト機能の実装 ログアウト機能はSessionsコントローラのdestroyアクションで実装します。 ログアウト処理はセッションからユーザーIDを削除します。 そのためにsession.delete(:user_id)と記述します。 この処理もログインと同じように使いまわすためにlog_outメソッドとしてsessions_helper.rbに定義しておきます。 2. ログインしている時としていない時でヘッダーの内容を変える ここからはユーザーがログインしている時としていない時でヘッダーの内容を変えていきます。 この機能を実現するには、現在ユーザーがログイン中かどうかを判別するメソッドが必要です。 そのメソッドの前に、現在ログイン中のユーザーの情報を扱えるようにするメソッドを説明します。 そのメソッド名はcurrent_userとして、以下のように書きます。 app/helpers/sessions_helper.rb # 現在ログイン中のユーザーを返す(いる場合) def current_user if session[:user_id] @current_user ||= User.find_by(id: session[:user_id]) end end このメソッドでは 「||=」 というRuby特有の演算子を使用しています。 上記のコードの条件式を書き直すと、 @current_user = @current_user || User.find_by(id: session[:user_id])となります。 意味としては@current_userが存在するときはそのままの値、存在しないときはユーザーを検索して代入するという意味です。 このメソッドにより、現在ログイン中のユーザーを@current_userというインスタンス変数で扱うことができます。 上記のメソッドが定義できたら、本題のユーザーがログイン中かどうかを判別するメソッドを定義します。 そのメソッドはlogged_in?メソッドという名前で以下のように書きます。 app/helpers/sessions_helper.rb # ユーザーがログインしていれば true、その他なら false を返す def logged_in? !current_user.nil? end このメソッドは単純で、current_userがnilの時はfalse、それ以外はtrueを返します。 このメソッドによってユーザーがログインしているかを判別できるようになったので、 ヘッダーの内容をログイン状態に応じて変更できるようになりました。 以下に変更後のヘッダーの変更部分を示しておきます。 app/views/layouts/_header.html.erb <li><%= link_to "Home", root_path %></li> <li><%= link_to "Help", help_path %></li> <% if logged_in? %> <li><%= link_to "Users", '#' %></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> Account <b class="caret"></b> </a> <ul class="dropdown-menu"> <li><%= link_to "Profile", current_user %></li> <li><%= link_to "Settings", '#' %></li> <li class="divider"></li> <li> <%= link_to "Log out", logout_path, method: :delete %> </li> </ul> </li> <% else %> <li><%= link_to "Log in", login_path %></li> <% end %> 4. 終わりに この章はログイン機能を作成してユーザー登録したユーザーがアプリケーションを使えるようになりました。 Railsでは今回実装したような認証機能を簡単に実装できるgemがありますが、 Railsチュートリアルではそのようなgemを使えば簡単に実装できる機能を1から自分で実装するので、 その分機能の仕組みがよく理解できていると思います。 内容が徐々に難しくなってきていますが、今のところ1週間に2章分というペースを維持できているので、 できる限りこのペースのまますすめていこうと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Notion APIライブラリまとめ

Ruby Laravel Swift JS go python vue PHP React
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クラスの定義

クラスを使用して以下の表示結果を出力するコードを記述します。 表示結果 ワンワン わたしは犬です わたしの名前はポチで種類はトイプードルです 仕様 クラス変数 値 type 犬 インスタンス変数 値 name ポチ dog_type トイプードル クラスメソッド メソッド名 処理 say ワンワン インスタンスメソッド メソッド名 処理 say_type "私は{クラス変数type}です" self_introduction わたしの名前は{インスタンス変数name}で種類は{インスタンス変数dog_type}です 雛形 class Dog @@type = "犬" def initialize @name = "マロン" @dog_type = "トイプードル" end def self.say puts "ワンワン" end def say_type puts "わたしは#{@@type}です" end def self_introduction puts "わたしの名前は#{@name}で種類は#{@dog_type}です" end end dog = Dog.new Dog.say dog.say_type dog.self_introduction 1)クラスの定義はclass クラス名 〜 endでした。まずはクラス変数であるtypeを定義します。 2)クラス変数は変数名の始めに@@(アットマーク2つ)をつけます。 3)インスタンス変数です。インスタンス変数は変数名の始めに@(アットマーク1つ)をつけます。 4)インスタンスごとに定義する必要があるのでインスタンスメソッド内で定義します。 5)クラスメソッドsayの定義をします。クラスメソッドはメソッドの前に自身のメソッドであることを示すself.をつけます。 6)インスタンスメソッドであるsay_typeとself_introductionを定義します。インスタンスメソッドの中ではクラス変数とインスタンス変数の両方が使えます。インスタンスメソッドの書き方は通常のメソッドと同じです。 7)定義したメソッドをクラスの外から呼び出します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsポートフォリオ #15 READMEの作成

こんにちは 今回はReadmeの作成を行いました。 (前回記事 #14 カテゴリーソート機能) ポートフォリオの顔とも言える超重要なReadme 今回はポートフォリオにおいて最も重要なものの一つであるReadmeの作成に取り組みました。 Readmeとアプリの最初の画面がポートフォリオにおいて最も大切、もはやそこだけで判断される、なんていう話は皆さんもご存知だと思います。 私が作っているアプリが業務改善系ということもあり、多くの方が作られるSNS系のアプリに比べると使い方がなかなか伝わりにくいので、Readmeでの説明には特に力を入れようと考えていました。 まずは先人たちのものを見せてもらい、何を書けばいいのかを把握するところから始めました。 作成時意識したこと 最初にわかりやすい概要を書くことで、そこだけしかみてもらえない場合にも雰囲気を掴んでもらえるようにすること 画像も上の方に一枚貼ることで、少しのスクロールでも目に入るようにし、視覚的にも伝えられるようにすること アプリ内にも簡単な説明書きがあるので、Readmeは丁寧な説明を記述すること 読んでもらえるかはわからないけど、各機能の説明をしっかり書きました。 書く順番 概要 URL 技術一覧 ER図 インフラ構成図 開発背景 意識したこと 機能一覧 機能の詳細 今後の改良計画 どの順番がベストなのかはわかりませんが、レビューをしてもらった際にもらったご指摘も踏まえ、最終的にこの順番で書きました。 ポートフォリオ作りもいよいよゴールが近づいてきているなという感じがします。 この調子で頑張るぞー!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyで解くAtCoder ABC 201 (C問題 Rubyでは最短実行時間)

C - Secret Number 問題内容 0000~9999までの4桁の暗証番号について,どの文字が使われていたかを10文字の文字列で与えられるので,ありえるパターンの数を答える問題 例えばo?xx?oxoxxでが与えられれば,左から順に 0,1,2..9 と見ていって, o : 確実に1回以上使われる( 0,5,7 は 1~4 個) ? : 使われたかもしれない( 1,4 は 0~4 個) x : 使われない( 2,3,6,8,9 は 0 個) この条件でありえる暗証番号のパターン数は84通りなので,84を出力すればよいです。 本番で提出したコード ABC201_C.rb str = gets.chomp.split('') o = 0 q = 0 10.times do |i| o += 1 if str[i] == 'o' q += 1 if str[i] == '?' end if o >= 5 puts 0 elsif o == 4 puts 24 elsif o == 3 puts 24 * q + 36 elsif o == 2 puts 12 * q * q + 24 * q + 14 elsif o == 1 puts 4 * q * q * q + 6 * q * q + 4 * q + 1 else puts q * q * q * q end 最初のtimes文のところまでで,oと?の個数を数えて,変数o,qに入れています。あとから見直すと,結構直したくなってくる... 配列にしてるのに変数名strなのは違和感 文字列のままcountで数えたほうがスマート if文で,変数oの値によって,条件分岐させながら,計算しました。 (高校数学でこんなのやったなあと思い出しながら...) o が 5 個以上 4桁の暗証番号なので,これはありえない! $0$ 通り o が 4 個 4個全てをパターンしかないので $4! = 24$ 通り o が 3 個 oの3種類のみで考えられるパターン $4!$に対し,同じ数字が2個あるので$2$で割って,どの数字を2個使うかで3パターンあるので$3$をかけます。 $ \frac{4!}{2}×3 = 36 $ 通り oの3種類に?から1個使うパターン どこに?を使うかで$4$通り,oの並べ方で$3!$通り,さらに?の個数分だけ$q$通りあるので $ 4 × 3! × q = 24q $ 通り 合計は $ 24q + 36 $ 通り o が 2 個 oの2種類を2個ずつ使うパターン $4!$ に対し,同じ数字が2個ずつあるので $2×2$ で割ります。 $ \frac{4!}{2×2} = 6 $ 通り oの2種類を1個,3個で使うパターン どちらを1個にするかで $2$ 通りに,1個のほうがどこに来るかで $4$ をかけます。 $ 2 × 4 = 8 $ 通り oの2種類を1個,2個で使い,?から1個使うパターン どこに?を使うかで $4$ 通り,oの並べ方(どこに1個のほうがくるかで3通り,どっちを1個にするかで2通り)で $ 3 × 2 $ 通り,さらに?の個数分だけ$q$通りあるので $ 4 × 3 × 2 × q = 24q $ 通り oの2種類を1個ずつ使い,?から2個使うパターン どこに?を使うかで $_4 C _2 = 6$ 通り,oの並べ方(どこに1個のほうがくるかで3通り,どっちを1個にするかで2通り)で $ 3 × 2 = 6 $ 通り,さらに?の個数分だけ $q^2$ 通りあるので $ 6 × 6 × q^2 = 36q^2 $ 合計は $ 36q^2 + 24q + 14 $ 通り o が 1 個 oを4回使うパターン $1$ 通りしかないです。 oを3回,?を1回使うパターン どこに?を使うかで $4$ 通り,さらに?の個数分だけ $q$ 通りあるので $4q$ 通り oを2回,?を2回使うパターン どこに?を使うかで $_4 C _2 = 6$ 通り,さらに?の個数分だけ $q^2$ 通りあるので $6q^2$ 通り oを1回,?を3回使うパターン どこにoを使うかで $ 4 $ 通り,さらに?の個数分だけ $q^3$ 通りあるので $4q^3$ 通り 合計は $ 4q^3 + 6q^2 + 4q + 1 $ 通り o が 0 個 ?の個数を4回かければよいので $ q^4 $ 通り 解説記事 公式解説 $10^4$ 通りなので,全部数えるようにしてもできそうですね。 ユーザー解説 こちらは場合分けしていますね。 感想 今回はC問題までを45分で解くことができました。 D問題は解けなかったので,次回こそチャレンジ!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby初心者(私)がやった構文ミス

はじめに はじめまして、Rubyにてプログラミング学習をはじめたkat_logと申します。 学習の中でやった間違いをご紹介いたします? 一覧 数値指定が必要なのに文字列で指定した ミス print_info("USBメモリ", "1200") 正解 print_info("USBメモリ", 1200) 初心者にありがちなミスですかね… if文のelseに条件式を記載した 別の条件で分岐させる時はelsifが正しいのですがelseとしていたため意図しない結果が出てきました。 ミス total.rb total = 50 if total >= 200 #25円引き total -= 25 else total >= 100 #10円引き total -= 10 end puts total # => 40 100円以上の時に10円引きしたいのに、100円より小さい値でも10円引きされてしまいました。 正解 total.rb total = 50 if total >= 200 #25円引き total -= 25 elsif total >= 100 #10円引き total -= 10 end puts total # => 50 2つ目の条件の時はelsifですね! elseに条件を書いていても実行時にエラーは出ず、実行後に気づきました!? メソッド作成時にreturn付け忘れ ミス friday.rb def sale_day? # 金曜日判定 today = Date.today today.friday? end 正解 friday.rb def sale_day? # 金曜日判定 today = Date.today return today.friday? end 処理が書けて満足してたら忘れてました! おわりに ここまで読んでいただきありがとうございました。 ミスは他にもあるのですが今回は3つだけご紹介しました。 慣れていないこともありこれだけの記事でも大変だと思いました…! ランキングに載るような記事をまとめられている方々は知識はもちろん集中力や構成力も持たれているのだと思い尊敬します。 学習の過程ではたくさん間違えますが、間違えたときほど記憶には残っているとポジティブに捉えて今後も学習進めていきたいと思います? 最後に、記事の投稿が初めてでして技術の面でも、「こうすると見る側に親切だよ」といった記事の面でもアドバイス等ありましたらフィードバックいただけたらと思います。 ありがとうございました! 参考 Progate Let'sプログラミング
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Capistrano取扱説明書

Capistranoとは Rubyで記述されたDSLを用いて複数のリモート環境を操作するためのツールで、主にデプロイツールとして利用します。 コマンドを実行して、リモートのサーバーに最新のアプリケーションをデプロイし、サーバーを再起動する、といったことが可能です。 インストール gemパッケージとして提供されているので、gem installコマンドでインストールすることが出来ます。 $ gem install capistrano . . . 1 gem installed 必要ファイルの生成 capifyコマンドを実行することで、デプロイに必要なファイルを生成することが出来ます。 $ capify . #=> 「Capfile」と「config/deploy.rb」が生成される <Capfile> Capistrano本体であるcapコマンド実行時に、タスクが記述されたファイルを読み込むために利用される。 <config/deploy.rb> どういったサーバーにどうやってデプロイするか、といった実際のデプロイの流れを記述していきます。 一般的には、デプロイ処理をまとめたものをレシピと言います。 設定 set Capistrano内部でオプションとなる項目の設定にはsetメソッドを使用します。 # 第1引数にオプションのキーのシンボル、第2引数のキーに対する値 set :myname, 'sample123' puts myname #=> "sample123" デプロイをするには、「application」,「repository」,「scm」を設定する必要があります。 # デプロイ対象となるアプリケーション名 set :application, 'sample_project' # デプロイ対象のプロジェクトを管理しているリポジトリパスを指定 set :repository, 'https://github.com/sample/sample.git' # 使用するバージョン管理システム set :scm, :git role デプロイするサーバーを用途別に分けてグルーピングする設定項目のこと。 role :web, 'sample-web-server' role :app, 'sample-app-server' role :db, 'sample-db-primary-server', primary: true role :db, 'sample-db-slave-server' # set :applicationで指定したアプリケーション名を指定 set :deproy_to, "/var/www/#{application}" タスクとネームスペース タスクとは、実際に行うデプロイ処理をまとめたもの。 ネームスペースとは、タスクの集まりに名前をつけたもの。 Capistranoはタスク単位でデプロイ処理を実行していき、cap タスク名で実行可能です。 ※deskはタスクの説明文のことです。 # cap :hello_capistrano desc 'echo at remote server' task :hello_capistrano do run 'echo "Hello, Capistrano!"' end # rolesオプションを指定することで、対象サーバーを指定 desc 'echo at remote server' task :hello_capistrano, roles: [:web, :app] do run 'echo "Hello, Capistrano!"' end namespace :list do # cap list:ls desc 'execute ls' task :ls do run 'ls' end # cap list:ls_detail desc 'execute ls -l' task :ls_detail do run 'ls -l' end end デプロイの流れ Ruby on Railsのデプロイタスクをデフォルトで用意しています。タスク名はdeployで定義されています。 大まかな処理の流れとしては、、 ①ソースコードの取得 ②bundle install ③共有ファイルのシンボリックリンクの差し替え ④最新版ディレクトリのシンボリックリンク差し替え ⑤サーバー再起動 Capistranoが利用するディレクトリ ディレクトリ 意味 releases デプロイされるプログラム一式が格納、デプロイごとに作成される current 現在稼働しているプログラム一式が格納 shared アプリケーションが出力するログ・tmpディレクトリ・pidファイルが格納 タスク実行時の出力内容の制御方法 capコマンドを実行すると、各種ログが出力されます。このログは「重要度」に応じて出力されているので、-vオプションで表示内容を制御出来ます。 ※段階的に出力レベルを引き上げるために-vvと-vvvが利用出来ます。 desc 'echo at remote server' task :hello_capistrano do run 'echo "Hello, Capistrano!"' end # -vオプションで表示内容を制御 $ cap -v hello_capistrano TransactionとRollback Capistranoはトランザクション処理とロールバック処理の仕組みが備えられています。 複数ステップのデプロイ処理の中で問題が発生した際に、切り戻し処理を行うためのものです。 desc 'transaction rollback test' task :has_error, roles: :app do # 問題が起きる可能性のある箇所をトランザクション処理で囲む transaction do    # ロールバック処理を記述 on_rollback { run 'echo "has error"' } run 'command_does_not_exists "error?"' end end フック処理 フックの種類 タスク実行の前後などに、フック処理を指定することが可能です。 主に、beforeやafterを使用します。 desc 'before task' task :before_task, roles: :app do run 'echo "this is before task"' end desc 'after task' task :after_task, roles: :app do run 'echo "this is after task"' end desc 'main task' task :main_task, roles: :app do run 'echo "this is main task"' end before 'main_task', 'before_task' after 'main_task', 'after_task' 種類 説明 before 指定したタスクの実行前 after 指定したタスクの実行後 start コマンドラインから指定されたタスクの実行前 finish コマンドラインから指定されたタスクの実行後 load レシピファイルの読み込み終了後 exit 全てのタスク終了後 パスワードの取り扱い デプロイレシピに直接パスワードを記載するとセキュリティ的に問題なので、Capistranoではパスワード入力を求めるコマンドラインインターフェースを提供しています。 利用者からの入力を受けて、設定変数として利用します。 set(:db_password) { Capistrano::CLI.password_prompt("DB password: ") } desc 'connect to db client' task :db_connect, roles: :db do run "db_connect --user='pruby' --password=#{db_password}" end cap db_connect -vv * executing 'db_connect' DB password: # ここでパスワード入力が求められる * executing "db_connect --user='pruby' --password=password" sudoメソッド Capistranoは通常SSHのログインユーザ権限でコマンドを実行します。時にroot権限が必要になる場合があります。その時にsudoメソッドを使用することで、root権限で実行可能になります。 set desc 'need sudo' task :use_sudo_command, roles: :app do run "touch /tmp/cap_tmp" # root権限で実行している sudo 'rm /tmp/cap_tmp', as: 'tanaka.taro' # asオプションでどのユーザーで実行するか指定 CaptureとStream Capistranoには、サーバーで実行させたいコマンドの中には実行させた結果を取得してCapistrano側で処理したい場合や、サーバーの状態を観測するための処理も存在します。 captureメソッド captureメソッドとは、タスクの実行対象になるroleの最初に指定されたサーバーに対してコマンドを実行してその結果を返します。 desc 'log size watch' task :log_size_watcher do log_file = "#{deproy_to}/shared/log/development.log" ls_result = capture("ls -l #{log_file}") file_size = ls_result.squeeze.split(/ /)[4].to_i p "file size alert" if file_size > 100 end streamメソッド streamメソッドは、複数サーバーに対して継続的なアウトプットを得たい時に利用します。 アプリケーションのログ観測などに利用します。 desc 'log stream' task :tail_log do stream("tail -f #{deproy_to}/shared/log/development.log") end ストラテジー アプリケーションをどのように本番環境に配信するかを、ストラテジーという仕組みで選択できるようになっています。 ストラテジーの種類 種類 意味 remote_cache 各サーバ側でアプリケーションのリポジトリを取得、フル取得→差分取得 checkout デプロイごとにサーバーでリポジトリを丸ごと取得 copy マシン上でファイルを取得し圧縮したものをサーバーに転送 export デポロイごとにリポジトリを丸ごと取得 unshared_remote_cache サーバー側でリポジトリを保持するディレクトリを指定し、remote_cache実行 デプロイ環境の切り替え デプロイする環境は、本番環境だけでなくステージング環境など異なる環境にデプロイする場合があります。 config/deploy.rbで、capistrano/ext/multistageをrequireすると利用可能になります。 ※環境ごとに設定ファイルをそれぞれ設定しておく。 set :stages, %w(production staging) set :default_stage, :production require 'capistrano/ext/multistage' config/deploy/production.rb role :web, 'sample-web-server' role :app, 'sample-app-server' role :db, 'sample-db-primary-server', primary: true set :deproy_to, "/var/www/#{application}" config/deploy/staging.rb role :web, 'sample-staging-web-server' role :app, 'sample-staging-app-server' role :db, 'sample-staging-db-primary-server', primary: true set :deproy_to, "/var/www_staging/#{application}"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RSpec(model)の読みやすい書き方

Rubyでテストを書くにあたって コメントにてご指摘をいただき、 Rspecをrailsなしで、ruby上で使うための設定方法を調べてみました。 https://stackoverflow.com/questions/12307097/how-to-use-rspec-without-rails userモデル 今回はこちらのメソッドへのテストの書き方について! user.rb class User def fullname [name, surname].join(' ') if middle_name.nil? [name, middle_name, surname].join(' ') if middle_name.nil? end end userモデルRspec userの名前が定義されている状況に応じて異なるフルネームを返す。 user_spec.rb describe 'fullname' do context 'with surname and name' do let(:user) { build(:user, surname: 'delicious', name: 'banana') } it 'shows full name without middle name' do expect(user.fullname).to eq('banana delicious') end end context 'with surname, name and middle name' do let(:user) { build(:user, surname: 'delicious', name: 'banana', middle_name: 'super') } it 'shows full name with middle name' do expect(user.fullname).to eq('banana super delicious') end end end どこに何を書けば良い? describe: メソッド名 context: 状況設定 it: returnされる結果 describe後にメソッド名のみを記載する事で、 後にテストを探す際、"describe 'メソッド名'"で探すと瞬時に見つけることができ、便利になります。 改善のアドバイス等ある方はコメントいただけると嬉しいです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

草野球の出欠確認Webアプリを作ろう! part.7

これから作っていく簡単なWebアプリの作成メモ(自分の備忘)です。 自分用なのであまり凝りすぎないように書いていきたい。 <<前回の記事 今回やったこと 前回作ったスケジュールの編集機能の修正点について 前回記事にて、一覧画面からテーブルの一行をクリックすることで、そのスケジュールの編集画面に遷移できるようにする変更をした。しかし、この時は眠くて画面遷移の動作確認を「一覧画面」⇒「編集画面」(⇒既設linkにて「一覧画面」)と、一度しか実施しなかった。 今日、改めて触ってみると、ページリロード後の「一覧画面」⇒「編集画面」⇒「一覧画面」は移動できるが、その後もう一度同じ動きで(或いはテーブルにある別のスケジュール行で)編集画面に遷移しようとしても、何も起こらなかった(!?)。 上記一覧画面からスケジュールをクリックして... 赤枠のリンクをクリックすることで一覧画面に戻って... 戻ってきた一覧画面からもう一度同じ遷移をしようとしても、何も起きない!? なぜうまくいかないのか、だいぶ考えてしまいました。。。 そして出した結論が、 「もしかして、JQuery側でレンダリングしてる処理が最初(一覧画面の一番はじめの表示時)しか動いてない??」 です。 ではなぜ、そのような現象が起こってしまうのか。 いろいろとWeb記事を見回って、やっとこれだというものを発見(以下記事です)。 【Rails】turbolinksやAjaxの影響でjQueryが正常に動作しないとき turbolinksがページ遷移時の動作を軽くしてくれていますが、これによってJQueryのイベント発火のタイミングが少し考慮しなければいけなくなり、その部分にまるで気が付いていなかったので、今回のようなダメな実装例が出来上がってしまったということです。 反省しつつ、前回書いたJQueryの処理を上記記事の通りに修正。 app/javascript/packs/schedules.js jQuery(document).on('turbolinks:load', function() { $(".clickable-row").css("cursor","pointer").on('click', function() { location.href = $(this).data("href"); }); }); turbolinksを使う際には、このあたりの考慮をしないといけなかったんですね。 無知故致し方なし...。 スケジュールの編集に対する画面遷移の変更 修正をしていて思ったこと。 「一覧からクリックしていきなり編集画面になるの、なんか変では?」 最初に作った時にはまるで気が付かなかったけど、一般的には以下のようになっていることが多い。 一覧画面⇔詳細表示画面⇔編集画面 ようやくそのことに気が付いたので、これも修正する。 まずは一覧画面からテーブルの行をクリックしたときの遷移先を詳細表示画面にする。 app/views/schedules/index.html.erb (略) <tbody> <% @schedules.each do |lst| %> <tr class="clickable-row" data-href="<%= schedule_path lst.id %>"> (略) さらに、詳細表示画面から編集画面へのリンクを用意する。 app/views/schedules/show.html.erb (略) <div class="row_line"> <%= link_to '編集', edit_schedule_path(@schedules.id), class: 'btn primary-btn' %> </div> 動作も確認できた。 スケジュールの削除 スケジュールを編集できても、削除できないと不便(というか最低限出来ないと困る)。 なので、スケジュールを削除できるようにします。 以下の記事は参考に読んだ。 [Rails]deleteメソッドとdestroyメソッドの違いについて!![初心者] まずはコントローラーの手入れから。 app/controllers/schedules_controller.rb (略) def destroy @schedules = Schedule.find(params[:id]) destroyed_title = @schedules.title @schedules.destroy redirect_to schedules_url, notice: "予定『#{destroyed_title}』を削除しました。" end (略) ※これまで、しれっとdestroyアクションのことをdeleteって書いてしまっていたことに気が付いて、これも修正(Userコントローラーのほうもアクション名を修正した)。 次に、詳細表示画面に削除ボタンを配置する。 app/views/schedules/show.html.erb (略) <div class="row_line"> <%= link_to '編集', edit_schedule_path(@schedules.id), class: 'btn primary-btn' %> <%= link_to '削除', schedule_path(@schedules.id), method: :delete, class: 'btn btn-danger' %> </div> できた。 動作も確認できたのでOK。 今後やるべきこと まだまだ最低限使えるものへの道のりは長い...。 ユーザーでのログインの仕組みづくり ユーザーの新規登録 ユーザーの編集 ユーザーの詳細表示 ユーザーの削除 見た目の改善 Bootstrapの有効化 レスポンシブデザインへの対応 データ削除時に「本当に削除しますか」の確認の実装 各種バリデーションの実装 今回はここまで。 記述ミスもまだまだあるので、見つけ次第修正したい。 あと、最低限必要なものが揃ったら、リファクタリングも時間を割いておきたい(願望)。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む