Skip to content

Useful Methods

Ryuji EGUCHI edited this page Dec 11, 2019 · 40 revisions

ActiveRecord

  • merge
class Catalog < ApplicationRecord
  has_many :channels, through: :channel_catalogs
end

class Channel < ApplicationRecord
  has_many :catalogs, through: :channel_catalogs
end

channel = Channel.last
channel.catalogs = Catalog.first(2)

# レコードがある時は、同じ挙動。
Channel.find_by(id: 17).catalogs.pluck(:id)
=> [1, 2]

Catalog.joins(:channels).merge(Channel.where(id: 17)).pluck(:id)
=> [1, 2]

# レコードが無い時に、挙動が変わる。nilの時にNoMethodErrorになるか、[]が返るか。
Channel.find_by(id: 100).catalogs.pluck(:id)
=> NoMethodError: undefined method `catalogs' for nil:NilClass

Channel.find_by(id: 100)&.catalogs&.pluck(:id)
=> nil

Catalog.joins(:channels).merge(Channel.where(id: 100)).pluck(:id)
=> []


# 期待動作する時のSQL
> Catalog.joins(:channels).merge(Channel.where(id: 17)).to_sql
=> "SELECT `catalogs`.* FROM `catalogs` INNER JOIN `channel_catalogs` ON `channel_catalogs`.`catalog_id` = `catalogs`.`id` AND (`channel_catalogs`.`request_status` = 20 OR `channel_catalogs`.`request_status` IS NULL) INNER JOIN `channels` ON `channels`.`id` = `channel_catalogs`.`channel_id` WHERE `channels`.`id` = 17"

# 期待動作しない時のSQL
> Channel.joins(:fairs).merge(Fair.where(id: 17)).to_sql
=> "SELECT `channels`.* FROM `channels` INNER JOIN `channel_fairs` ON `channel_fairs`.`channel_id` = `channels`.`id` INNER JOIN `channels` `fairs_channels` ON `fairs_channels`.`id` = `channel_fairs`.`fair_id` AND `fairs_channels`.`type` IN ('Fair') WHERE `channels`.`type` IN ('Fair') AND `channels`.`id` = 17"

Useful Methods

There're lots of useful methods that are enhanced by ActiveSupport. You should check the following site, too.

http://guides.rubyonrails.org/active_support_core_extensions.html

  • &

It's same as try!

  • try

  • nil?

  • empty?

  • blank?

  • present?

  • presence

  • yield

  • yield_self (Ruby 2.5)

  • then (Ruby 2.6) alias of yield_self (discussion)

  • block_given?

  • each

  • each_with_index

  • map

    Get used to the following syntax (e.g.): %w[a b c].map(&:upcase)

    Use map when you want to get an array. Otherwise, use each. Differentiate them.

  • each_with_object (Rubocop suggests using each_with_object instead of reduce / inject )

  def self.providers
    {
      email: {
        formal: 'Email',
        id: 'email'
      },
      facebook: {
        formal: 'Facebook',
        id: 'facebook.com'
      }
    }.with_indifferent_access
  end

> ExternalAccount.providers.reduce({}) { |h, (k, v)| h[v[:id]] = k; h }
=> {"email"=>"email", "facebook.com"=>"facebook"}

> ExternalAccount.providers.each_with_object({}) { |(k, v), h | h[v[:id]] = k }
=> {"email"=>"email", "facebook.com"=>"facebook"}
User.exists?(email: 'test@example.com')
  User Exists (2.5ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2  [["email", "test@example.com"], ["LIMIT", 1]]
=> true

User.where(email: 'test@example.com').exists?
  User Exists (0.5ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2  [["email", "test@example.com"], ["LIMIT", 1]]
=> true
  • any?
  • all?
['foo', 'bar'].all?(&:blank?)
=> false

['foo', ''].all?(&:blank?)
=> false

['', ''].all?(&:blank?)
=> true

[nil, ''].all?(&:blank?)
=> true
  • pluck

  • find_each

  • find_in_batches

  • first (this doesn't work when id is uuid)

  • last (the same as above)

  • include?

[1, 2, 3].include?(3)
=> true

(0...10).include?(3)
=> true

(0...10).include?(10)
=> false
  • in?
(3).in?([1,2,3])
=> true

(3).in?(0...10)
=> true

(10).in?(0...10)
=> false
  • values_at

  • fetch_values

  • slice

  • except

  • merge

  • select

  • reject

  • dig

  • match

  • to_param

  • to_query

  • start_with?

  • end_with?

  • symbolize_keys (deep_symbolize_keys)

  • stringify_keys (deep_stringify_keys)

  • send (public_send)

  • define_method

  • tap

  • attributes

user.attributes = { name: 'myname', email: 'myname@example.com' }
  • assign_attributes

  • delegate

  • html_safe

  • squish

  • inquiry

  • strip_heredoc

  • *

[*1..5]
=> [1, 2, 3, 4, 5]
a, *b = [1, 2 ,3]
=> [1, 2, 3]

b
=> [2, 3]
  • rjust

The following methods written here.

  • any?
  • blank?
  • build
  • create, create!
  • delete_all
  • destroy_all
  • empty?
  • explain
  • find_or_create_by, find_or_create_by!
Job.find(1000)
=> ActiveRecord::RecordNotFound: Couldn't find Job with 'id'=1000

job = Job.find_or_create_by(id: 1000) do |j|
  j.id_token = 'new_id_token'
end

job.new_record?
=> true

job.id_token
=> "new_id_token"
  • find_or_initialize_by
  • new
  • reload
  • size
  • to_sql
  • update_all

Useful Expressions

  • redirect_to post_url(@post) and return

https://api.rubyonrails.org/classes/ActionController/Redirecting.html

  • ActiveRecord で オブジェクト同士を==で比較した場合、id を比較している

https://qiita.com/YumaInaura/items/f8b946127f6ec888bbaf


providers = {
  facebook: {
    formal: 'Facebook',
    id: 'facebook.com'
  }
}.with_indifferent_access

> providers[:facebook]
=> {
    "formal" => "Facebook",
        "id" => "facebook.com"
}

> providers['facebook']
=> {
    "formal" => "Facebook",
        "id" => "facebook.com"
}
Clone this wiki locally