Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby:作成したRubyプログラムを指定したコマンドで実行する

最近Rubyでコンソールアプリケーションを作成したので、指定したコマンドで作成したRubyプログラムを実行する方法をメモφ(..)

github.com

Rubyプログラムを任意のコマンドで実行方法

手順

やりかたとしては、作成したRubyプログラムへの絶対パスへのエイリアス~/.bash_profileに追記します。

# cmd_nameでrubyプログラムが実行出来るようにエイリアスを設定
$ echo alias cmd_name="ruby Rubyプログラムへの絶対パス" >> ~/.bash_profile
# 環境変数の反映 
source ~/.bash_profile

コマンド実行

スクリプトファイルで同一フォルダ内にあるRubyプログラムへのエイリアスを貼ってみました。

# 現在のパスを取得
SCRIPT_DIR=$(cd $(dirname $0) && pwd)
# homeでrubyプログラムが実行出来るようにエイリアスを設定
echo alias homehome="'ruby ${SCRIPT_DIR}/HomeRuby.rb'" >> ~/.bash_profile
# 環境変数の反映 
source ~/.bash_profile

実行例

こんな感じで指定したコマンドでスクリプトが実行出来ました!  

f:id:madogiwa0124:20171009190555g:plain

ionicでWebサイトへのリンクを貼る。

ionicでWebサイトへのリンクを貼る方法をメモφ(..)

↓こんな感じ  f:id:madogiwa0124:20171002223836p:plain

手順

.htmlファイルにリンクを置く

.htmlファイル内に通常のWebアプリケーションと同様に<a>...</a>を配置します。
配置したリンクには(click)でクリックイベントを定義し、.tsで定義したopenWebSite()メソッドを呼び出します。

<a href="#" (click)="openWebSite(page.url)">{{page.title}}</a>

 

.tsでWebサイトを開く処理を実装する。

.ts内にメソッドを定義し、window.open()メソッドに引数としてURLを渡します。
urlと合わせて_system及びlocation=yesを引数として渡していますが、_systemはシステムのブラウザでリンクを開くことを表し、location=yesはアドレスバーの有無を意味します。

export class PageIndexPage {
  /* 省略 */
  openWebSite(url) {
    window.open(url, '_system', 'location=yes');
    return false;
  }
  
}

以上のやり方でWebサイトへのリンクを貼ることが出来ました・ω・

参考

window.open - Apache Cordova

www.thepolyglotdeveloper.com

RubyonRails:kaminariを使ってページャーを簡単に実装する

f:id:madogiwa0124:20170729104257p:plain

開発中のサービス「いつもの更新、いつでも確認 | Moook」でページャーを実装する際に使用したgemkaminariの使い方をメモφ(..)

github.com

使い方

gemのインストール

kaminariを使うには、gemファイルに追加しbundle installを実行します。

Gemfile

gem 'kaminari'

実装

ページャーを作るために必要な箇所はControllerViewのみです・ω・ 処理の概要を説明すると下記のような感じです。

Source 実装内容
Controller リクエストパラメーターから渡されたページ番号を使って、検索結果取得範囲を制御する。
View ページャーを生成し、設置する

具体的なプログラムも下記に記載しておきますφ(..)

Controller

  def index
    @pages = Page.favorited_pages(current_user).page(params[:page]).per(9)
  end

取得結果に.page(params[:page])及び.per(1ページ辺りの件数)追記することで、ページ番号を指定した検索結果の制御が行えます。
検索結果の制御は、引数のページ番号とクエリメソッドのlimitoffsetを使って実現されていますφ(..)
offsetlimitの詳細は、下記記事にまとめたので知りたい人がいれば見てみてください。

madogiwa0124.hatenablog.com

View

ページャーの設置を行う前に、ページャーのviewを生成します。
下記コマンドを実行すると、app/views/kaminari配下にページャーのviewファイルが作成されます。

$ rails g kaminari:views default

その後、Controllerで取得したインスタンス変数をpagenateに引数として渡してあげれば、ページャーが生成されます。

<%= paginate(@pages) %>

また、bootstrapをページャーに反映させるのも下記からファイルを取得してapp/views/kaminari配下のファイルを差し替えてあげれば簡単に出来ます!

github.com

↓こんな感じ

f:id:madogiwa0124:20170927214342p:plain

ローカライズ

先程の画像では、ページャーの日本語化が行われていました。
これは、kaminariページャーの表示をconfig/locales/ja.ymlに追記することで設定できます。 これをやらないと翻訳を失敗した際に上手く表示されません・・・。
※私が導入した際もtruncateが翻訳に失敗し、Truncateと表示されてしまいました(´・ω・`)

ja.yml

  views:
    pagination:
      first: "最初"
      last: "最後"
      previous: "前"
      next: "次"
      truncate: "..."

applicaiton.rbconfig.i18n.default_locale=:jaとなっていることが前提です。

おわりに

kaminariを使えば、簡単にページャーを設定することが出来ます!
ページャーを用いることで、取得レコード数が制限され表示のパフォーマンスも良くなると思いますので、皆さんも自分が作っているRailsアプリケーションに導入してみてはいかがでしょうか?ヽ(´エ`)ノ

RubyonRails:Rails5で使えるデータ検索関連のメソッドをまとめてみた

f:id:madogiwa0124:20170729104257p:plain

現在、Railsブロンズ試験を受験してみようと思い、RubyonRails5アプリケーションプログラミングという本で勉強中なので、頭の整理も兼ねて学んだことをまとめてみるφ(..)

Ruby on Rails 5アプリケーションプログラミング

Ruby on Rails 5アプリケーションプログラミング

今回はモデルの検索について主要なメソッドをまとめてみました・ω・

モデルの検索処理まとめ

主キーによる検索:findメソッド

findメソッドは、主キーによるレコードの検索を行います。
取得結果は主キー指定の場合はモデルのインスタンス、複数の主キーを指定した場合は、モデルのインスタンスの配列が返却されます。

# 主キーによる検索
Model.find(1)
#=> SELECT  "models".* FROM "models" WHERE "models"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]

# 複数の主キーによる検索
Model.find([1, 2, 3])
#=> LECT "models".* FROM "models" WHERE "models"."id" IN (1, 2, 3)

任意キーによる検索:find_byメソッド

find_byメソッドは、任意の項目をキーとして検索を行います。
取得結果として検索条件に合致した最初の一件を返却します。
また複数の検索キーが引数に設定された場合は、複数の検索キー(AND条件)で結果を取得します。

# タイトルをキーとして検索
Model.find_by(title: "hoge")
#=> SELECT  "models".* FROM "models" WHERE "models"."title" = ? LIMIT ?  [["title", "hoge"], ["LIMIT", 1]]

# タイトルと内容をキーとして検索
Model.find_by(title: "hoge").find_by(content: "fuga")
#=> SELECT  "models".* FROM "models" WHERE "models"."title" = ? AND "models"."content" = ? LIMIT ?  [["title", "hoge"], ["content", "fuga"], ["LIMIT", 1]]

基本的な条件式を設定する:whereメソッド

whereメソッドは、引数に条件を設定し、与えられた条件に合致するレコードを返却します。
find_byメソッドと一見似ていますが、whereメソッドは、条件に合致する全てのレコードを返却します。
また、プレースホルダ?を使い任意の値を条件式に埋め込むことが出来ます。
※取得結果が1件だったとしてもActiveRecord::Relationで返却されるため注意が必要です。

madogiwa0124.hatenablog.com

# タイトルがhogeかつ本文がfugaのレコードを検索
# hashで複数条件を与えた場合はfind_byメソッドと同様にAND条件となる。
Model.where(title: "hoge", content: "fuga")
#=> SELECT  "models".* FROM "models" WHERE "models"."title" = ? AND "models"."content" = ? LIMIT ?  [["title", "hoge"], ["content", "fuga"], ["LIMIT", 11]]

# 金額が1000以上のレコードを検索
Model.where('price >= ?', 1000)
#=> SLECT  "models".* FROM "models" WHERE (price >= 1000) LIMIT ?  [["LIMIT", 11]]

条件に合致しないレコードを検索する:notメソッド

notメソッドを使うことで、whereメソッドで指定した条件に合致しないレコードを取得することが出来ます。

# タイトルがhogeじゃないレコードを検索
Model.where.not(title: "hoge")
#=> SELECT  "models".* FROM "models" WHERE "models"."title" != ? LIMIT ?  [["title", "hoge"], ["LIMIT", 11]]

OR条件で複数条件を設定する:orメソッド

orメソッドは与えられた条件式をOR条件(または)として加えることが出来ます。
ただし、加えられるのは同一モデルに対するwhereメソッドのみです。

# タイトルがhogeまたは本文がfugaのレコードを検索
Model.where(title: "hoge").or(Model.where(content: "fuga"))
#=> SELECT  "models".* FROM "models" WHERE ("models"."title" = ? OR "models"."content" = ?) LIMIT ?  [["title", "hoge"], ["content", "fuga"], ["LIMIT", 11]]

取得結果を並び変える:orderメソッド

orderメソッドに項目とソート順を与えることで取得結果の並び替えることが出来ます。
項目とソート順は複数与え、複数項目での並び替えを行うことも可能です。

# タイトルの昇順で並び変える
Model.order(title: :asc)
#=> SELECT  "models".* FROM "models" ORDER BY "models"."title" ASC LIMIT ?  [["LIMIT", 11]]

# タイトルの降順で並び変える
Model.order(title: :desc)
#=> SELECT  "models".* FROM "models" ORDER BY "models"."title" DESC LIMIT ?  [["LIMIT", 11]]

# 価格の降順、タイトルの昇順で並び変える
Model.order(price: :desc, title: :asc)
# => LECT  "models".* FROM "models" ORDER BY "models"."price" DESC, "models"."title" ASC LIMIT ?  [["LIMIT", 11]]

取得する項目を指定する:selectメソッド

selectメソッドを用いることで特定の項目のみを取得することが出来ます。
引数を複数与えることで、複数の項目を指定することも可能です。

# 全てのモデルのタイトルを取得する
Model.select(:title)
#=> SELECT  "models"."title" FROM "models" LIMIT ?  [["LIMIT", 11]]

# 全てのモデルのタイトルと価格を取得する
Model.select(:title, :price)
#=> SELECT  "models"."title", "models"."price" FROM "models" LIMIT ?  [["LIMIT", 11]]

重複したレコードを削除する:distinctメソッド

distinctメソッドを使うことで取得結果から重複したレコードを削除することが出来ます。

# モデルに設定されているジャンルの一覧を重複なしで取得
Model.select(:genre).distinct
#=> SELECT  DISTINCT "models"."genre" FROM "models" LIMIT ?  [["LIMIT", 11]]

レコードの取得件数を制御する:limitメソッド・offsetメソッド

limitメソッドを使用することで最大取得件数を制限することが出来ます。
また、offsetメソッドを使用することで、取得開始位置を指定することが出来ます。

# モデルを最大3件取得する
Model.limit(3)
# => SELECT  "models".* FROM "models" LIMIT ?  [["LIMIT", 3]]

# モデルを10件目から10件取得する
# offsetを指定する際は先頭行が0となるため注意
Model.offset(10).limit(10)
# => SELECT  "models".* FROM "models" LIMIT ? OFFSET ?  [["LIMIT", 10], ["OFFSET", 10]]

データの集計を行う:groupメソッド

groupメソッドを使用することで特定のキーで結果をグルーピングし、データの集計を行うことが出来ます。

# ジャンル別の最大価格を取得する
Model.select('genre, MAX(price) AS max_price').group(:genre)
# => SELECT genre, MAX(price) as max_price FROM "models" GROUP BY "models"."genre"

集計後の結果に検索条件を設定する:havingメソッド

havingメソッドは、集計後の結果に対して条件を設定し絞込を行うことが出来ます。

# ジャンル別の最大価格が10000以上のものだけを取得する
Model.select('genre, MAX(price) AS max_price').group(:genre).having('MAX(price) >= ?', 10000)
# => SELECT  genre, MAX(price) as max_price FROM "models" GROUP BY "models"."genre" HAVING (MAX(price) >= 10000) LIMIT ?  [["LIMIT", 11]]

特定項目の平均値・最小値・最大値・合計値を取得する:averageメソッド・minimumメソッド・maximumメソッド・sumメソッド

平均・最小・最大・合計といった集計でよく使いそうなものは、メソッドとして定義されています。
これらのメソッドはwhereメソッドに続けて記述することによって、検索結果に適用することも出来ます。

# 価格の平均値を取得
Model.average(:price)
# => SELECT AVG("models"."price") FROM "models"

# 価格の最小値を取得
Model.minimum(:price)
# => SELECT MIN("models"."price") FROM "models"

# 価格の最大値を取得
Model.maximum(:price)
# => SELECT MAX("models"."price") FROM "models"

# 価格の合計値を取得
Model.sum(:price)
# => SELECT SUM("models"."price") FROM "models"

# 特定ジャンルの平均価格を取得
Model.where(genre: "hoge").average(:price)
# => SELECT AVG("models"."price") FROM "models" WHERE "models"."genre" = ?  [["genre", "hoge"]]

生のSQLを使って検索を行う:find_by_sqlメソッド

どうしても生のSQLで検索を行いたい場合は、find_by_sqlメソッドを使用します。
SQLの構文はDBMSに依存するためDBMS変更時に不具合を誘発する可能性があるため注意してください。

# 特定ジャンルのレコードを取得
Model.find_by_sql(['SELECT * FROM models WHERE genre = ?', 'hoge'])
# => SELECT * FROM models WHERE genre = 'hoge'

以上です!
また何かあれば追記しようと思いますφ(..)

Ruby on Rails:インスタンス変数等をjavascriptに受け渡す方法

はじめに

Railsで取得したデータを使ってChart.jsでグラフ描画する等、Railsで扱っている変数をjsに受け渡す方法をメモφ(..)

↓イメージはこんな感じ f:id:madogiwa0124:20170918142442p:plain

手順

概要

  1. 取得データをJSONに変換し、HTML要素のdata属性に設定(viewに埋め込む)
  2. jsで設定した要素のdata属性の値を取得

RailsでViewに埋め込んだJSONjavascript側でパースして受け取って、使用するイメージです(/・ω・)/

ソースコード

hoge.html.erb

<div id="tag_info" data-json="<%= current_user.favorite_tags_info.to_json %>" ></div>

hoge.js

tags = JSON.parse(document.getElementById('tag_info').dataset.json);

おまけ

gonというGemを使っても出来るらしいφ(..)

github.com

qiita.com

参考

qiita.com

Ruby on Rails:文字列の一部だけエスケープさせずにHTMLとして認識させる方法

はじめに

掲示板のアプリケーション等、特定の文字部分(>>3等)を<a></a>として認識させる方法をメモφ(..)

↓イメージはこういう感じ f:id:madogiwa0124:20170916104509p:plain

やりかた

今回は>>数字を返信用の文字列として扱い、<a></a>でページ内リンクを貼るケースを想定してますφ(..)

  1. 文字列全体をhメソッドを使ってエスケープ
  2. エスケープされた文字列の返信用文字列&gt;&gt;>>に置換
  3. >>数値部を抽出し、リンク用のHTMLを生成し本文に埋め込む
  4. 出力側のViewでhtml_safeで出力

実際のソースコード

hoge_helper.rb

  def format_comment(content)
    # 返信用の文字列を定義
    reply = { char: '>>', escaped: '&gt;&gt;' }
    # コメント本文のHTMLをエスケープ後、返信用の文字列のみをHTMLとして再定義
    content = h(content).gsub(reply[:escaped], reply[:char])
    # 返信先リンク部の取得
    content_arry = content.split(" ")
    target = content_arry.select{ |c| c.include?(reply[:char]) }
    target.each do |t|
      # 返信先リンクHTMLの生成
      to = t.match(/#{reply[:char]}\d+/).to_s
      link_html = link_to to, "#comment_#{to.gsub(reply[:char], '')}"
      # 本文の返信部を返信先リンクHTMLで置換
      content = content.gsub(to, link_html)
    end
    content
  end

index.html.erb

<p><%= format_comment(comment.content).html_safe %></p>

以上

参考

www.rubylife.jp

qiita.com

Ruby:複数の区切り文字で文字列を分割する方法(String.split)

はじめに

英語の文章を".“、”!“、”?“等の複数の区切り文字で分割する方法を調べたのでメモφ(..)

複数の区切り文字で分割する方法

区切り文字を統一後、分割する

String.splitを呼び出す前に、区切り文字を置換し統一してあげればOK!(/・ω・)/
今回のケースでは、?!.に置換後にString.splitを呼び出しています。

str = "I have a pen. I have an apple. I have a pen? I have an apple!"
key = "pen"
str = str.gsub("!",".").gsub("?",".")
p str.split(".")
# result : ["I have a pen", " I have an apple", " I have a pen", " I have an apple"]

正規表現を引数に渡す

String.split正規表現を引数として渡してあげればOK!(/・ω・)/
今回のケースでは/\.|\?|!/という正規表現を与えて、.?!で分割されるようにしました。
.?は、正規表現予約語のため、エスケープしています。

str = "I have a pen. I have an apple. I have a pen? I have an apple!"
key = "pen"
p str.split(/\.|\?|!/)
# result : ["I have a pen", " I have an apple", " I have a pen", " I have an apple"]

おまけ

区切り文字で文章を分割後、再度区切り文字を付与する書き方を載せてみましたφ(..)

str = "I have a pen. I have an apple. I have a pen? I have an apple!"
key = "pen"
spliter = /\.|\?|!/
# 区切り文字を出現順に保存
split_chars = str.split("").select{ |s| s.match(spliter) }
# 区切り文字で文章を分割後、区切り文字を再度付与
str_array = str.split(spliter).zip(split_chars).map{|s| s.join }
# 結果出力
p str_array
# result : ["I have a pen.", " I have an apple.", " I have a pen?", " I have an apple!"]

以上

参考

qiita.com

qiita.com