20210720のRubyに関する記事は14件です。

Ruby on Railsにおけるajax処理について

アプリケーションで取り扱いデータの処理内容が多くなってきたり、大容量データをデータベースとやり取りする時にAjaxを使用してデータ通信をすることでパフォーマンスの改善につながります。 ajaxを使用しないと更新の際データ通信時間が長すぎて503エラーが出たりするのに対して、ajax処理を導入することでエラーを回避したりできるメリットなどもあるようです。 環境情報 まず環境によってコードの書き方などが変わって来るらしいので私のrails環境を記入しときます。 ruby2.6.5 rails 6.0.4 基本的なajaxの使い方 railsに限らずajaxの一般的な使い方はこちらのような内容になります。 一般的なアプリケーションだとボタンなどをクリックするアクションをしてから読み込み処理をしてそれからサーバー再度でどのような返答をすればいいかの処理を決めてという風なやり取りをスレうするのに対してajaxだとユーザーからのアクションをしなくてもJavaScript側から取得できるすべてのイベントからリアルタイムにイベントを発火させることができる。非同期通信でページ遷移なしで スムーズにフロントエンド側に結果を反映できるのが特徴です。 データをすべて読み込んでから結果を返すやり方だとユーザー側もその間待たなくちゃいけないので、リアルタイムでやり取り出来て必要最低限のアプリケーションを動かすことになるのでユーザビリティーやアクセシビリティーの向上にもつながると思います。 Railsでのajax処理の書き方 RubyOnRailsではView側のヘルパーメソッドに(form_tag)などで:remote=>trueを指定してあげることでajax導入を導入することができます、特にGemを使用するなどのことはなく非常に簡単に導入できます。 inbdex.html.erb <%= form_tag({:controller => '<コントローラ名>', :action => 'index'}, :remote => true, :class => 'hoge') do -%> <%= hidden_field_tag :sample_name1, 'sample_name1' -%> <%= submit_tag('Start sample', :class => 'btn btn-primary btn-sm') -%> <% end %> Controller側でその アクションに対応する処理を行い、render でレスポンスを指定します。 デフォルトではレスポンスとしてフロントエンド側にJavaScriptの処理が戻ってきます。そのレスポンス用JavaScriptは View ファイルにJavaScriptテンプレートを記述して用意します。 とりあえずこれまでです、説明できるようになったら追記します
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】特定のroutesのみを表示する方法

My Profile プログラミング学習歴②ヶ月目のアカウントです! プログラミングスクールで学んだ内容や自分が躓いた箇所等のアウトプットの為に発信しています。 また、プログラミング初学者の方にわかりやすく、簡潔にまとめて情報共有できればと考えています。 もし、投稿した記事の中に誤り等ございましたら、コメント欄でご教授いただけると幸いです。  対象者 rails routesをよく使用する方 目的 grepを使って特定のroutesのみを表示して探す手間を省く 実際の手順と実例 1.特定のroutesのみ取得 terminal. rails routes | grep hoge チームで開発する際にroutesが多すぎて探すのに時間がかかっている方にかなりおすすめです! hoge部分にはroutes上に存在する文字列であれば表示できます! 活用してスムーズな開発につなげてください!! 参照 bundle exec rails routesで特定のroutesのみ表示する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails 投稿機能

投稿機能(newアクション) railsを利用した基本的な投稿機能について、学習内容をメモ的に記載しています。 ルーティング Rails.application.routes.draw do get "posts/new", to: "posts#new" end まずは、newアクションに対応するルーティングを記載し、新規投稿画面に遷移させます。 HTTPメソッドは、新規投稿画面を表示させたいので、サーバに対して「新規投稿画面を下さいよ」という意味でgetを使用します。 投稿フォームの作り方 <form action="/posts" method="post"> <type="text" name="content"> <type="submit" value="投稿する"> </form> ヘルパーメソッド(form_with) 前述のhtmlを使用した投稿フォールの作成方法とは別に、ヘルパーメソッドという便利なメソッドが存在します。 ヘルパーメソッドを使用した投稿フォームの記載 html.erb <%=form_with url: "/posts", method: :post local: true do |form|%> <%=form.text_field :content%> <%=form.submit "投稿する"%> <%end%> ヘルパーメソッドを使用するメリット コードの記述を簡略的・分かりやすく記述できる セキュリティ面が向上する パラメーター formからリクエストでサーバに対して値を送る時に外部から渡されるデータのこと。 railsのコントローラーに渡されるパラメーターはparamsというはハッシュ形式に格納されています。 <%=form.text_field :content%> の:の後に記載したキー名で、値を送信することで、リクエストのparams内に{"キー名"=>"投稿内容"}と言った形式で値をコントローラーに渡すことができます。 コントローラーにおいて、params[:キー名]で値を取得することができます。 投稿機能(createアクション) ルーティング Rails.application.routes.draw do get "posts/new", to: "posts#new" post "posts", to: "posts#create" end createアクションの場合は、URIパターンは、postsのみの記載、HTTPメソッドがpostになっている点に注意が必要です。 サーバに対して、何か値を送信するので、postメソッドが必要になります。 投稿完了とともに、投稿完了画面を返してやると、わかりやすいです。 createメソッド ActiveRecordメソッドの一つで、値をテーブルに保存するには、new→情報入力→saveの流れが必要でしたが、このメソッドを使えば一発でテーブルに保存することができます。 def create Post.create(params[:content]) end #Postテーブルにformから送られてきたキー名contentの値を保存する記載
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActiveHashの特定の数字を表示させない(条件分岐)

はじめに hotel_type.rb class HotelType < 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: 'その他' } ] include ActiveHash::Associations has_many :model end このように宿泊施設ではないを選んだ時-が出るようにしたいなと思い、条件分岐を使って表示させました。 最初から{ id: 2, name: '-' }こうしろよと意見があると思いますが意味があってこのようにしたのでご了承下さい・・・ やった事 宿泊施設ではないを選んだ時、-が表示される それ以外は通常通り表示される この事から条件分岐が必要とする事が分かりました。 <% if 条件式%> <p>-</p> <%else%> <%= @model.hotel_type.name %> <% end %> こんな感じになると思います。 結論 ActiveHashは数字がDBに保存されます。なので数字で条件式を作ります。 if @model.hotel_type_id == 2 この条件式ではhotel_type_idのidが2だった場合という形になります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】created_at、日本時間する

Ruby on RailsでWebサービスを作っていて、日本時間への設定変更をしたいケースの解決方です。 2021-07-18 10:00 + 0900みたいな表示になってしまう。 年、月、日、時を使って、わかりやすくしていく。 日本時間に設定する方法 config/application.rbを開く このファイルに、以下のコードを記述 config/application.rb config.time_zone = 'Tokyo' サーバーを再起動させる config/initializers/time_formats.rbというファイルを作り以下を記述 config/initializers/time_formats.rb Time::DATE_FORMATS[:datetime_jp] = '%Y年 %m月 %d日 %H時 %M分' viewの修正をする <%= xxx.created_at.to_s(:datetime_jp) %> <%= xxx.updated_at.to_s(:datetime_jp) %> まとめ 日本時間の表示は、設定としてフォーマットを定義しておくと便利.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】mapメソッドを使ったリファクタリング

ポイント 空の配列を用意して、他の配列をループ処理した結果を空の配列に詰め込んでくような処理の大半は、mapメソッドに置き換えることができる。 例 def to_ints(hex) r, g, b = hex[1..2], hex[3..4], hex[5..6] ints = [] [r, g, b].each do |s| ints << s.hex end ints end # to_ints('#000000') # => [0, 0, 0] # to_ints('#ffffff') # => [255, 255, 255] 上のコードの処理は、 ・引数の文字列から3つの16進数を抜き出し、 ・3つの16進数を配列に入れ、ループを回しながら10進数の整数に変換した値を別の配列に詰め込み、 ・10進数の整数が入った配列を返す。 という処理を行っています。 ここで冒頭のポイントの通り、 「空の配列を用意して、他の配列をループ処理した結果を空の配列に詰め込んでくような処理の大半は、mapメソッドに置き換えることができる。」 ので、以下のようにmapメソッドに置き換えられます。 def to_ints(hex) r, g, b = hex[1..2], hex[3..4], hex[5..6] [r, g, b].map do |s| s.hex end end mapメソッドはブロックの戻り値を配列の要素にして新しい配列を返すメソッドなので、 リファクタリング前のコードのように、変数を用意しなくとも、 mapメソッドとブロックだけで処理を完結できます。 参考文献 伊藤 淳一 「プロを目指す人のためのRuby入門」, 技術評論社, 2017
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

formオブジェクト(ActiveModel)を用いたタグ機能(タグ検索)

説明 自分はformオブジェクトを用いてタグ機能は実装したのですが、投稿はともかく編集、削除、検索などは記事が少なく、あっても複雑で苦労したのでいくつかに分けて投稿したいと思います。今回はタグをクリックするとそのタグのついた投稿の一覧に飛ぶ機能を解説します。 前提条件 この記事は複数投稿編、編集、削除編を閲覧していただいている前提の解説となります。 完成コード routes.rb resources :tweets do collection do get 'search' get 'search_tag' get 'search_incre_tag' get 'search_tags' get 'search_status' get 'search_job' end resources :comments, only: [:create] resources :likes, only: [:create, :destroy] end _tweet.html.erb(タグのビュー) <div class="search-subTtl">タグ検索</div> <div class="search-tagContainer"> <%= link_to search_tags_tweets_path, class: "search-form tag-searchBtn" do %> <i class="fas fa-tags"></i>タグで検索する <% end %> </div> tweets_controller.rb def search_tag relations = TweetTagRelation.where(tag_id: params[:tag]) @tag_tweets = [] relations.each do |relation| @tag_tweets << Tweet.find_by(id: relation.tweet_id) end end search_tag.html.erb(タグ関連の投稿一覧のビュー) <% if @tag_tweets != [] %> <% @tag_tweets.each do |tweet| %> <li class='tweet-list'> <%= link_to tweet_path(tweet.id), remote: true, class: "show-link" do %> <%= render partial: "shared/tweet", locals: { tweet: tweet } %> <% end %> </li> <% end %> <% end %> コード解説 routes.rb resources :tweets do collection do get 'search' get 'search_tag' get 'search_incre_tag' get 'search_tags' get 'search_status' get 'search_job' end resources :comments, only: [:create] resources :likes, only: [:create, :destroy] end _tweet.html.erb(タグのビュー) <% if tweet.tags != [] %> <div class="tweet-tags"> <ul class="tweet-tagList"> <% tweet.tags.each do |tag| %> <%= link_to search_tag_tweets_path(tag: tag), method: :get, class: "tag-link" do %> <div class="tag-name">#<%= tag.name %></div> <% end %> <% end %> </ul> </div> <% end %> まずget 'search_tag'をルーティングに記述します。この時idが必要なのでcollectionで囲みます。そしてビューには繰り返し文でタグを表示し、リンクに先ほど作ったルーティングのsearch_tag_tweets_path(tag: tag)を記入し、引数には投稿に関連したtagの情報を入れるため(tag: tag)を記入します。 tweets_controller.rb def search_tag relations = TweetTagRelation.where(tag_id: params[:tag]) @tag_tweets = [] relations.each do |relation| @tag_tweets << Tweet.find_by(id: relation.tweet_id) end end コントローラーではまず引数でもらったタグの情報を元にrelations = TweetTagRelation.where(tag_id: params[:tag])を記述してrelationsに中間テーブルの情報を入れます。そして@tag_tweetsという空の配列を作り、そこに中間テーブルに関連した投稿を配列として入れていきます。 search_tag.html.erb(タグ関連の投稿一覧のビュー) <% if @tag_tweets != [] %> <% @tag_tweets.each do |tweet| %> <li class='tweet-list'> <%= link_to tweet_path(tweet.id), remote: true, class: "show-link" do %> <%= render partial: "shared/tweet", locals: { tweet: tweet } %> <% end %> </li> <% end %> <% end %> タグに関連した投稿一覧のビューを作ります。そこでコントローラーで作った@tag_tweetの中身の投稿を繰り返し文で取り出していき、完成です。 まとめ 以上がfromオブジェクトでのタグに関連した投稿一覧の解説となります。閲覧ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Sidekiqが死んだままサービス運用をしてしまった際の復旧手順について

1. 現状蓄えられているQueueを確認 > stats = Sidekiq::Stats.new > stats.queues → { "default" => 100, "mailers" => 400 } keyはQueueの名前、valueはQueue内のJob数です。 2. すべてのJobを削除 stats.queues.keys.each do |queue_name| queue = Sidekiq::Queue.new(queue_name) queue.each do |job| # 特定のjobだけを消したい場合はなんかしらのガード文を書く # next unless job.klass == "SampleWorker" job.delete end end 3. Queueが消えているかを確認 > stats.queues → { "default" => 0, "mailers" => 0 } 4. 再起動 5. チームメンバーへ謝罪 参考 https://qiita.com/dany1468/items/20cf0dfc40d589993bda https://www.it-swarm-ja.com/ja/ruby-on-rails/%E3%82%AD%E3%83%A5%E3%83%BC%E5%86%85%E3%81%AE%E5%86%85%E5%AE%B9%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%97%E3%80%81sidekiq%E3%81%A7%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%92%E3%82%AF%E3%83%AA%E3%82%A2%E3%81%99%E3%82%8B%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8B%EF%BC%9F/1069431510/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]バリデーションのエラーメッセージを3ステップで日本語化

過去の記事 [Rails]よく使うバリデーションまとめ [Rails]フラッシュメッセージとエラーメッセージ違いと実装方法 で、 バリデーションによるエラーメッセージの表示を解説して、実装しましたが、デフォルトではエラーメッセージが英語のままなので、日本語化していきます。 開発環境 ruby 2.6.3 Rails 5.2.6 3ステップ エラーメッセージを日本語化するには3ステップです! ①rails-i18nをインストール ②デフォルトの言語を日本語にする ③カラム名も日本語化する ①rails-i18nをインストール エラーメッセージを日本語化するには、rails-i18nというgemを使います。 Gemfileに追加します。 gem 'rails-i18n' 追加したら、インストールします。 $bundle install これで、rails-i18nをインストールできました。 ②デフォルトの言語を日本語にする 次に、デフォルトの言語を日本語に設定します。 config/application.rbに設定を追加していきます。 config/application.rb : module SampleApp class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.2 # 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. # 以下一文を追加 config.i18n.default_locale = :ja end end これで、デフォルトの言語を日本語に設定できました。 サーバーを再起動して試してみてください。 これだけでカラム名以外は、日本語で表示ができています。 ③カラム名も日本語化する カラム名は各Webサービスによって、表示したい名前も変わってくると思うので、開発者側で設定する必要があります。 config/locales配下にja.ymlファイルを作成してその中に、モデル、カラム名の設定を記述していきます。 基本形 ja: activerecord: models: モデル名: 表記したい名称 attributes: モデル名: カラム名: 表記したい名称 カラム名: 表記したい名称 基本はこのような形で記述していきます。 表記したい名称には、imageカラムなら「画像」が入ります。 これだけだとわかりにくいと思うので、実際に記述したコードを載せておきます。 モデルは、以下です。 User Post Comment Like Contact config/locales/ja.yml # エラーメッセージのカラム名日本語化 ja: activerecord: # 全てのモデル記載 models: user: ユーザー post: 投稿 comment: コメント like: いいね contact: お問い合わせ attributes: # 各モデルのカラム名を記載 user: name: 名前 email: メールアドレス password: パスワード post: content: 説明 image: 画像 comment: comment: コメント内容 contact: name: 名前 email: メールアドレス content: お問い合わせ内容 これで、カラム名も任意の名前に変更できました。 確認してみてください。 まとめ エラーメッセージを日本語化するには3ステップです! ①rails-i18nをインストール ②デフォルトの言語を日本語にする ③カラム名も日本語化する エラーメッセージをかんたんに実装することができました。 あらためてgemの偉大さを痛感しました!(かんたんすぎ) 最後まで見ていただきありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

if,else問題

21時から翌朝6時までにオウムに喋られると問題があるのでその場合は「NG」、それ以外は「OK」と出力するメソッドを作成します。オウムが喋る時をtrue、喋らない時をfalseと入力することにし、時刻も同時に入力します。 答えと解釈 def parrot_trouble(talking, hour) if talking && (hour < 6 || hour >= 21) puts "NG" else puts "OK" end end これは呼び出し方です parrot_trouble(talking, hour) 日本語訳するとしたらこんな感じ オウムがtalkingするのはNGです。(6時-21時の間は) それ以外の場合はOK &&と||の使い方 「A && B」で「AかつB」 「A || B」で「AまたはB」
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カート機能①カート内商品の合計金額を出す inject 税込価格の表示 / ECサイト

はじめに カート機能を作成中です。今回はカート内商品の合計金額を出すやり方を学習しました。 前提条件 ここで登場するテーブル・モデルは、 Customer Item Cart_item です。←(CustomerとItemの中間テーブルになる。) (Cartモデルを作成している記事が多いですが、Cartモデルは作成していません。) *ログインしなくても商品の閲覧はできるが、カートには入れられない。 マイグレーションファイル customer_id,item_idは外部キーで、個数はnull:falseにしています。 マイグレーションファイル class CreateCartItems < ActiveRecord::Migration[5.2] def change create_table :cart_items do |t| t.integer :item_id t.integer :customer_id t.integer :quantity,null: false t.timestamps end end end モデルファイル class CartItem < ApplicationRecord belongs_to :item belongs_to :customer validates :item_id, :quantity, presence: true validates :quantity, numericality:{ only_integer: true } def sum_of_price item.taxin_price * quantity end end カート内しょうひんの合計金額を出すところで重要なのは、 def sum_of_price item.taxin_price * quantity endです。 sum_of_priceで、ある商品の税込価格❌数量が出るようにしました。 taxin_priceというのは、item.rbで定義しています。 item.rb def taxin_price price*1.1 end itemのテーブルには税抜価格であるpriceというカラムを作成しており、 taxin_priceというカラムはありませんが、ここで定義することにより、item.taxin_priceで税込価格が取り出せるようになりました。 以下の記事を参考にしました。 最難関 コントローラー cart_items_controller.rb def index @cart_items= current_customer.cart_items.all # カートに入ってる商品の合計金額 @total = @cart_items.inject(0) { |sum, item| sum + item.sum_of_price } end カート内商品の一覧画面で、カート内商品の合計金額を算出します。 モデルファイルの記述や、 @total = @cart_items.inject(0) { |sum, item| sum + item.sum_of_price }は、以下の記事を参考に記述し、実装しましたが、初心者にはコードの意味が理解できなかったので、、 読み解いていきたいと思います。 コードの解読 @total = @cart_items.inject(0) { |sum, item| sum + item.sum_of_price } inject(0)って何?? 配列の合計を算出するらしい。 配列オブジェクト.inject {|初期値, 要素| ブロック処理 }が基本の形 inject(0)の(0)は、初期値は0ですよ〜ということのよう。 { |sum, item| sum + item.sum_of_price }で行ってることは? 1回目の動作 @cart_itemsから、カートに入ってる1つ目のitem取り出して、 sumにitem.sum_of_priceを足す。(sumの初期値は inject(0)で0) 2回目以降の動作 次のitem取り出して、sumにitem.sum_of_priceを足す。 これで、最終的にカート内商品の合計金額が出る!!! injectは”注入” sumにモデルで定義してるitem.sum_of_priceがどんどん注入されてくイメージ! 以下の記事で理解できました! viewファイル cart_item.html.erb ¥<%= @total.round.to_s(:delimited)%> これで合計金額出せました!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】関連付けメソッドのキャッシュ制御

はじめに Rails には、関連先のメソッドを呼び出す時に、キャッシュを使用することで高速化する仕組みがあります。 しかし、キャッシュではなく、データーベースから直接読み込みしたい場合があると思います。 今回はそのような場合のキャッシュ制御方法についてご紹介したいと思います。 関連性 以下のようなAnimalモデル、Pandaモデルの構成を作成します。 animal.rb class Animal < ApplicationRecord has_many :pandas end panda.rb class Panda < ApplicationRecord belongs_to :animal end キャッシュ制御 reloadメソッド を使用することで、キャッシュを破棄してくれます。 animal = Animal.first animal.pandas # データベースから pandas を取得する animal.pandas.size # pandas のキャッシュコピーが使われる animal.pandas.reload.empty? # pandas のキャッシュコピーが破棄される # その後データベースから再度読み込まれる まとめ まだまだ知らないことが多いので、引き続き勉強ですね〜 参考 Railsガイド - キャッシュ制御 https://railsguides.jp/association_basics.html#%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5%E5%88%B6%E5%BE%A1
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

モジュール [Rubyチェリー本 8章まとめ]

モジュールの概要 モジュールの主な用途 継承を使わずにクラスにインスタンスメソッドを追加する、もしくは上書きする(ミックスイン)。 複数のクラスに対して共通の特異メソッド(クラスメソッド)を追加する(ミックスイン)。 クラス名や定数名の衝突を防ぐために名前空間を作る。 関数的メソッドを定義する。 シングルトンオブジェクトのように扱って設定値などを保持する。 モジュールの定義 module モジュール名 # モジュールの定義 end クラスとは異なる点 インスタンスを作成することはできない 他のモジュールやクラスを継承することはできない ミックスイン - include Rubyは単一継承を利用している コードが重複しているからといって安易に継承を使ったりしてはいけません。「製品はユーザである」または「ユーザは製品である」という関係(isaの関係)が成り立たないのであれば、継承の使用は避けるべきです。 共通の機能は持たせたいが、継承は使うべきでない、そんな時に最適なのがモジュール モジュールで定義したメソッドが、インスタンスメソッドとして呼び出せるようになります。以下のようにこの機能を扱い、この機能の名前をミックスイン、と言う。 module Loggable def log(text) puts "[LOG]#{text}" end end class Product include Loggable def title # logメソッドはLoggableモジュールで定義したメソッド log 'title is called.' 'A great movie' end end class Use include Loggable def name # Loggableモジュールのメソッドが使える log 'nameiscalled.' 'Alice' end end product=Product.new product.title # =>[LOG]titleiscalled. # "A great movie" user=User.new user.name # =>[LOG]name is called. # "Alice" インスタンスメソッドをprivateにしたい場合は、module内でprivateしておく。 extend extendを使うと、モジュール内のメソッドをそのクラスの特異メソッド(つまりクラスメソッド)にすることができます。 ミックスインに関してもっと詳しく includeされているモジュールを確認する include?(モジュール名) Product.include?(Loggable)#=>true include_modules Product.included_modules#=>[Loggable,Kernel] ancestors モジュールだけではなく、スーパークラスの情報も含まれる Product.ancestors#=>[Product,Loggable,Object,Kernel,BasicObject] include先に特定のメソッドが定義されている前提のモジュール これはRubyがダックタイピングという考え方で構成されている為に適用される話。 Productクラスのpriceメソッドと連携して目的の処理を実行する module Taggable def price_tag "#{price}円" # priceメソッドはinclude先で定義されているはず、という前提 end end class Product include Taggable def price 1000 end end product=Product.new product.price_tag # =>"1000円" # 呼び出しているのはmodule内のメソッド、ただそのメソッド内でクラスのメソッドを活用している 上記の利用方法を採用したRubyの具体的なモジュール Enumerableモジュール Enumerableモジュールは配列やハッシュ、範囲(Range)など、何かしらの繰り返し処理ができるクラスにincludeされているモジュールです。 map, select, find, countなど Enumerableモジュールをincludeして、モジュールに定義されたメソッドを使えるようにする条件はたった1つだけです。それはinclude先のクラスでeachメソッドが実装されていることです。Enumerableモジュールのメソッドはいずれもinclude先のクラスに実装されたeachメソッドを使います。 Comparableモジュール Comparableモジュールのメソッドを使えるようにするための条件は、include先のクラスで<=>演算子を実装しておくことです。 <, ≤, ==, >, ≥など Kernelモジュール puts, p , print, require, loopなどについて これらの当たり前に利用していたメソッドが何故これまで利用できていたか? それはKernelモジュールをObjectクラスがincludeしているから。 トップレベルでは、mainという名前のオブジェクト Rubyのirbを起動した直後、 またclassやmoduleの定義の外側、これらの場所はどういう扱い? $ irb irb(main):001:0>ここはどこ?私は誰? ================================================================================ # ここはどこ?誰? class User # Userクラス内 end これらの一番外側の部分をトップレベルという。 トップレベルにはmainという名前のObjectクラスのインスタンスがselfとして存在しています。つまり、「私は誰?」の答えは「Objectクラスのインスタンス」になります。 モジュール内での、インスタンス変数の扱い モジュール内で定義したメソッドの中でインスタンス変数を読み書きすると、include先のクラスのインスタンス変数を読み書きしたことと同じになります。 ただし、モジュールとミックスイン先のクラスでインスタンス変数を共有するのはあまり良い設計ではありません。なぜなら、インスタンス変数は未定義の状態でも自由に代入したり参照したりできるからです。 一方、メソッドであれば未定義のメソッドを呼び出したときにエラーが発生します。 なので、ミックスイン先のクラスと連携する場合は特定のインスタンス変数の存在を前提とするより、特定のメソッドの存在を前提とするほうが安全です。 モジュールを利用した名前空間の作成 名前空間の衝突を防ぐ モジュール構文の中にクラス定義を書くと「そのモジュールに属するクラス」という意味になる module Baseball class Second def initialize(player, uniform_number) @player = player @uniform_number = uniform_number end end end クラス名の衝突を防止する名前空間として使われています。モジュールに属するクラスを参照する際は“モジュール名::クラス名”のように、::でモジュール名とクラス名を区切ります Baseball::Second.new('Alice', 13) 名前空間でグループやカテゴリを分ける クラスが何十、何百もあるような大きなプログラムになってくると、カテゴリ別にモジュール(名前空間)を作って整理しないと、どれが何のクラスなのかぱっと把握しにくくなるためです。 ネストなしで名前空間付きクラスを定義する 名前空間として利用するモジュールを定義する クラスの定義の際の構文を変更する # moduleを定意義しておく module Baseball end # 名前空間を定義 class Baseall::Second end モジュールを単体で使う 特異メソッドを定義する わざわざ他のメソッドに組み込むことなく、直接モジュール名.メソッド名とする事で、メソッドを呼び出す事ができる。 ただし、モジュールではインスタンスが作成できない為、「単なる関数の集まり」を作りたいケースに向いている。 また、クラスと同様に定数を定義することもできる。 module_function 単体の特異メソッドとしての利用、かつモジュールをミックスインとしても利用できるようにするメソッド。 module Loggable def text # 処理 end module_function :log # どちらでも利用可能に end 状態を保持する為に、モジュール自身に設定値を持たせる クラスインスタンス変数を使って、クラス自身にデータを保持する方法を説明しました。この方法はモジュールでも使うことができます。外部ライブラリ(gem)では、そのライブラリを実行するための設定値(config値)をモジュール自身に保持させたりすることがよくあります。 # AwesomeApiという外部ライブラリ AwesomeApi.base_url # => "http://example.com" AwesomeApi.debug_mode # => false インスタンスを作って何か操作する必要がないのであれば、モジュールにしておいたほうがほかの開発者に変な勘違いをさせる心配がありません。 ところで、ライブラリの実行に必要な設定値などはアプリケーション全体で共通の値になることが多いです。 そのため、アプリケーション内ではいつでもどこでも同じ設定値を設定したり、取得したりする必要があります。 そのためには設定値の情報はアプリケーション内で「唯一、1つだけ」の状態になっていることが望ましく、「唯一、1つだけ」のオブジェクトを作る手法のことを、シングルトンパターンと呼びます。 その他モジュールについて 1.メソッド探索のルール 同名のメソッドを扱う際に、どのモジュールやクラス内のメソッドを参照しているか調べる方法が記載されている 2.moduleにmoduleをinclude 3.prepend prependの特徴は同名のメソッドがあったときに、ミックスインしたクラスよりも先にモジュールのメソッドが呼ばれるところです。 この活用方法は、既存のメソッドを置き換える際に活用することができる。具体例を見た方が早い・再読必要 4.refinements - 有効範囲を限定 moduleとclassに跨る形で、それぞれrefinements, usingを利用することで、module内のメソッドの利用可能範囲を限定する事ができる。具体例を見た方が早い・再読必要 例題 - deep_freezeメソッドの作成 ここでは基本的なモジュールの理解として、複数のclass内における共通のメソッドの利用、について学んだ。 test/deep_freezable_test.rb require 'minitest/autorun' require '../lib/team.rb' require '../lib/bank.rb' class DeepFreezableTest < Minitest::Test def test_deep_freeze_to_array assert_equal ['Japan', 'US', 'India'], Team::COUNTRIES assert Team::COUNTRIES.frozen? assert Team::COUNTRIES.all? { |country| country.frozen? } end def test_deep_freeze_to_hash assert_equal( {'Japan' => 'yen', 'US' => 'doller', 'India' => 'rupee'}, Bank::CURRENCIES, ) assert Bank::CURRENCIES.frozen? assert Bank::CURRENCIES.all? { |key, value| key.frozen? && value.frozen? } end end lib/deep_freezable.rb module DeepFreezable def deep_freeze(array_or_hash) case array_or_hash when Array array_or_hash.each do |element| element.freeze end when Hash array_or_hash.each do |key, value| key.freeze value.freeze end end array_or_hash.freeze end end lib/team.rb require '../lib/deep_freezable.rb' class Team extend DeepFreezable COUNTRIES = deep_freeze(['Japan', 'US', 'India']) end lib/bank.rb require '../lib/deep_freezable.rb' class Bank extend DeepFreezable CURRENCIES = deep_freeze({'Japan' => 'yen', 'US' => 'doller', 'India' => 'rupee'}) end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

authenticate_user! メソッドが効かない

行いたい事  「出品」ボタンを押したときに、ユーザーがログインをしていなければログイン画面に飛ぶようにしたい。 item_controller.rb class ItemController < ApplicationController before_action :move_to_index, except: :index before_action :authenticate_user!, except: :index def index end def new end def create end private end 上記の様に $ authenticate_user! メソッドをbefore_actionで書いてみたが、ログイン画面に遷移しない・・・・なぜ?? before_actionの順番を変える事で解決しました。 item_controller.rb class ItemController < ApplicationController before_action :authenticate_user!, except: :index before_action :move_to_index, except: :index def index end def new end def create end private end コードは上から順番に読み込まれるので、 ログインページに飛ばしてくれるメソッド  よりも index以外のアクションをしようものなら問答無用にトップページに飛ばしてしまう   メソッドが先に働いてしまっていた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む