範囲オブジェクト
範囲を表す時は..
または...
を使用する。
対象とする範囲が異なるため使い分ける。
n以上m以下
n以上m以下を指定する場合は..
を使用する。
irb(main):001:0> numbers = 1..5 => 1..5 irb(main):002:0> numbers.include?(1) => true irb(main):003:0> numbers.include?(5) => true
n以上m未満
n以上m未満を指定する場合は...
を使用する。
irb(main):001:0> numbers = 1...5 => 1...5 irb(main):002:0> numbers.include?(1) => true irb(main):003:0> numbers.include?(5) => false
ブロックの色々な書き方
mapメソッドを使い、ブロックの書き方を何種類か記録。
do~end
['a', 'b', 'c'].map do |s| s.upcase end => ["A", "B", "C"]
{ }
['a', 'b', 'c'].map { |s| s.upcase } => ["A", "B", "C"]
(&: ~ )
['a', 'b', 'c'].map(&:upcase) => ["A", "B", "C"]
配列の削除について
A = [1, 2, 3, 4, 1, 2]
という配列があった時に、delete
とdelete_at
を使用した場合の挙動の違いは下記のようになる。
delete
irb(main):001:0> A = [1, 2, 3, 4, 1, 2] => [1, 2, 3, 4, 1, 2] irb(main):002:0> A.delete(2) => 2 irb(main):003:0> A => [1, 3, 4, 1]
delete
は配列に存在するnの要素を削除する。
delete_at
irb(main):001:0> A = [1, 2, 3, 4, 1, 2] => [1, 2, 3, 4, 1, 2] irb(main):002:0> A.delete_at(2) => 3 irb(main):003:0> A => [1, 2, 4, 1, 2]
delete_at
は配列のn番目の要素を削除する。
where句で「_」を検索する方法
ユーザーの検索でSQL文を使い、_(アンダースコア)から始まるユーザーネームを検索しようとした際に、少し困ったので書いておきます。
なんで困ったの?
まずスコープを作って検索の共通化をしました。
class User < ApplicationRecord scope :search_user, ->(name) { where('name like?', "#{name}%") } end
こんな感じのスコープで、任意の場所で検索をかけます。
@users.search_user('_')
と記述したところ、結果は全検索となりました。
欲しい結果はアンダースコアから始まるユーザーです。
原因を考えていたところ、そういえばSQLにはワイルドカードなんてのがあったなと思い出し調べてみました。
ワイルドカード
LIKE句で使えるワイルドカードは2種類あります。
%……0文字以上の任意の文字列
_…任意の1文字
なるほど。ワイルドカードで検索をしてしまったようです。
@users.search_user('_')
の意味するところは、任意の1文字を何もない文字に指定したので、結果的に全検索になっていました。
解決策
アンダースコアから始まる名前を検索するにはエスケープ文字を使ってあげれば良いです。
ワイルドカードである「_」の前に、バックスラッシュを書いてあげれば正しく検索できます。
@users.search_user('\_')
これで欲しい結果を得ることができました。
参考
http://www.sql-reference.com/select/like.html
https://rooter.jp/programming/ruby/rails_use_where_or_sanitize_sql_methods_to_avoid_sql_injection/
https://itsakura.com/sql-select-like
blongs_toの外部キーがnilでもDBへ保存できるようになるオプション
著者(author)と書籍(book)の1対多の関係があった場合、モデルは次のようになります。
class Author < ApplicationRecord has_many :books end
class Book < ApplicationRecord belongs_to :author end
Bookは次のカラムを持っています。
name:string author_id:integer
belongs_to
Bookを登録する場合、author_idがnilだとバリデーションで弾かれます。
これはbelongs_toオプションを設定することで、自動的に外部キーがpresence: true
となるからです。
デフォルトで設定してくれるのは助かりますが、困ることもあります。
例えば、書籍の著者が分からない、なんてケースもあるかと思います。
optional: true
そういう時はoptional: trueオプションを付けることで、外部キーがnilでも保存ができるようになります。
class Book < ApplicationRecord belongs_to :author, optional: true end
これでauthor_idがnilでも保存ができるようになりました。
impressionistを使ってPV数を計測する
制作中のアプリにPV数をカウントする機能が欲しかったので調べてみたところ、impressionistというgemが良さそうだったので導入してみました。
前提
導入
いつものようにGemfileへgemを記述しinstallします。
gem 'impressionist'
$ bundle install
これで導入できた…と思ったんですが、後になってエラーが起こりました。
どうやらimpressionistの最新版にはバグがあるようなので、安定版を使います。
参考に記載のある記事を元に次のように記述します。
gem 'impressionist', git: 'git://github.com/charlotte-ruby/impressionist.git', ref: '46a582ff8cd3496da64f174b30b91f9d97e86643'
$ bundle install
これでOKです。
次にテーブルを作成します。
$ rails g impressionist
このコマンドでマイグレーションファイルが作られます。
一応中身を確認してみると、
def self.up create_table :impressions, :force => true do |t| t.string :impressionable_type t.integer :impressionable_id t.integer :user_id t.string :controller_name t.string :action_name t.string :view_name t.string :request_hash t.string :ip_address t.string :session_hash t.text :message t.text :referrer t.text :params t.timestamps end add_index :impressions, [:impressionable_type, :message, :impressionable_id], :name => "impressionable_type_message_index", :unique => false, :length => {:message => 255 } add_index :impressions, [:impressionable_type, :impressionable_id, :request_hash], :name => "poly_request_index", :unique => false add_index :impressions, [:impressionable_type, :impressionable_id, :ip_address], :name => "poly_ip_index", :unique => false add_index :impressions, [:impressionable_type, :impressionable_id, :session_hash], :name => "poly_session_index", :unique => false add_index :impressions, [:controller_name,:action_name,:request_hash], :name => "controlleraction_request_index", :unique => false add_index :impressions, [:controller_name,:action_name,:ip_address], :name => "controlleraction_ip_index", :unique => false add_index :impressions, [:controller_name,:action_name,:session_hash], :name => "controlleraction_session_index", :unique => false add_index :impressions, [:impressionable_type, :impressionable_id, :params], :name => "poly_params_request_index", :unique => false, :length => {:params => 255 } add_index :impressions, :user_id end def self.down drop_table :impressions end
この様になってるかと思います。
そのままmigrateします。
$ rails db:migrate
PV数を計測したいページのテーブルにカラムを追加します。
今回はUsersのshowページに付けることにしてみます。
まずはmigrationファイルを作成します。
$ railg g migration AddImpressionsCountToUsers impressions_count:integer
作成したmigrationファイルにdefaultの値を追記します。
class AddImpressionsCountToUsers < ActiveRecord::Migration[5.2] def change # default: 0 初期値を0とする add_column :users, :impressions_count, :integer, default: 0 end end
再びmigrateします。
rails db:migrate
一度サーバーを再起動してimpressionistのメソッドを使えるようにしておきます。
コントローラの設定
Userの詳細ページを閲覧した際にPVを計測したいので、showアクションに記述していきます。
同一の閲覧者がページをリロードし3回見た時PVのカウントを3とすると正確性が落ちるので、session_hashを使用して1回だけカウントされるようにします。
def show impressionist(@user, nil, unique: [:session_hash]) @user = User.find(params[:id]) end
モデルの設定
counter_cacheオプションを付けて記述します。
class User < ActiveRecord::Base is_impressionable counter_cache: true end
ビューで表示する
これでPV数計測の準備が整いました。 実際にshowページで見てみましょう。
= @user.impressions_count
先ほど追加したカラムを使い表示すると、「1」という数字が出てくるはずです。
これは自分がアクセスした数が表示されていて、PV数の計測が成功していることがわかります。
以上で実装ができました。アプリを実際にデプロイしたら、ユニークユーザーがアクセスしてくれる度にPV数が1ずつ増えていきます。
参考
https://github.com/charlotte-ruby/impressionist https://remonote.jp/rails-impressionist-ranking https://qiita.com/yimajo/items/995584ede90be1a873ce
high_voltageを使用して簡単に静的ページを作成する
静的なページを作成する時にそれぞれcontrollerを作るか検討していたら、high_voltageというgemを見つけました。
controllerやroutesを設定しなくともapp/view/pages
以下のファイルを表示できるようになるというものです。
前提
導入
まずはgemをinstallします。
gem 'high_voltage'
bundle install
次に、pages
ディレクトリを作成します。
mkdir app/view/pages
これでhigh_voltageを使う準備ができました。
簡単ですね。
使用方法
試しに利用規約のページを作ってみます。
app/view/pages
にterms.html.slim
というファイルを作成します。
touch app/view/pages/terms.html.slim
サーバーを立ち上げ、http://localhost:3000/pages/terms
へアクセスすると、空のページが表示されます。
先ほどのファイルに記述をして再度アクセスしたら表示が確認出来るかと思います。
パス
ページのパスは、page_path('*')
となります。
今回はtermsなのでpage_path('terms')
と指定してあげればリンクが作れます。
= link_to '利用規約', page_path('terms')
こんな感じで使うことができます。
URLのpagesを表示しないようにする
high_voltageで生成したページにはpages
というURLが含まれてしまいますが、設定で消すことができます。
config/initializers
にhigh_voltage.rb
という設定ファイルを作成します。
そこへ次のように記述をします。
HighVoltage.configure do |config| config.route_drawer = HighVoltage::RouteDrawers::Root end
一度サーバーを再起動したら、URLが変更されています。
http://localhost:3000/pages/terms
は使えなくなり、http://localhost:3000/terms
にアクセスすることで表示されます。
パスは変わらずpage_path('terms')を使います。