---
# System prepended metadata

title: Ruby Quick Note
tags: [note]

---

# :gem: Ruby Quick Note

> As usual, this is a quick, unorganized, messy note.

:::spoiler Click to open Table of Content
[TOC]
:::

## :ballot_box_with_check: TODO:

- [ ] what exactly is "Symbol"
- [ ] rails async io ?
- [ ] how ruby mange "block"
- [ ] meta-programming: do it pre-compile like C? or after AST or ???
- [ ] how method evaluation and reference (how to passing lambda around)
  - > hint: sth called `proc` object. `lambda` is a `proc` object with special attributes
  - > hint^2: block can be encapsulate in `proc`

## :chicken: Common mistakes

:::warning
### :bug: `validate` and `validates` are different :exclamation: 
`validate` points to a method that contains **custom** validation logic
`validates` applies to **pre-built** validators
:::

:::warning
### :bug: Plural in Rails

be careful of model's plural...

> I run into some oopsie doopsie error because of this.
> I'm so stupid :(

```ruby
class User < ApplicationRecord
  has_many :user_roles
  has_many :roles, through :user_roles # <- has **many** **roles**
end

class UserRole < ApplicationRecord
  belongs_to :user
  belongs_to :role # <- belongs to **A** role
end
```

```shell
# each raw reference to A user, A role
$ rails g migration CreateUserRoles user:references role:references
```

:::info
:pencil: 
And Yes, even irregular plural noun like 'people' and 'child' do this
`ActiveSupport::Inflector` will handle these English special cases

for example:

```ruby
class Person < ApplicationRecord
  ...

class Role < ApplicationRecord
  has_many :person_roles
  has_many :people, through: :person_roles
```

> starts to feel a little bit hilarious at this point...

:::

:::warning
### ERB: `<%= %>` and `<% %>` are different

- `<% %>` embedded ruby code
- `<%= %>` embedded ruby AND return/write value to the content

#### Haml

- `- if xxx` evaluate ruby code
- `= link_to xxx` return the value of the ruby code
:::

:::warning
### Gem pg cannot found `libpq-fe.h`

if installed `libpq` via `brew`, we needs to add the libpq to PATH

```zsh
# ~/.zshrc or ~/.zprofile
export PATH="/opt/homebrew/opt/libpq/bin:$PATH"
```
:) easy task
:::

# Notes: 

## functional collection processing

```ruby
# These are equivalent:

users.map { |user| user.confirmed? }

users.map(&:confirmed?)

user.map do |user|
  user.confirmed?
end

# also can be view as different way of handling "block"
```

`.map` and `.collect` are the same
> why ruby why :face_palm: 

- `.each` only iterate the item
- `.map` will also return the result as array
- `.map!` will modify the object to result

### chain the operation in rails

```ruby
# from all user select whom is activated but not admin then get an array of their email
User.all.select(&:active?).reject(&:admin?).map(&:email)
```

## Gems

:::info
### Sidekiq

#### Naming

`work` is the old term. `Job` is the new term.
`Sidekiq::Work` -> `Sidekiq::Job`

#### Active_job

Rails has a default buildin job queue frame work called Active_job. But we could set config to override the default active job to `sidekiq` (for more functionality?)
:::

:::info
### Devise

https://github.com/heartcombo/devise/wiki/How-To:-Upgrade-to-Devise-2.0-migration-schema-style#after
:::

:::info
### Factory_bot

- factory can have child and inherits from parent

```ruby
factory :user do
  name { 'name' }
  factory :admin do
    admin {true}
  end
end

create :admin
```

```ruby
factory :user do
  name {'name'}
  trait :admin do
    admin {true}
  end
end

create :user, traits: [:admin]
```
:::

:::info
### cancancan

How it works:

`can(action, subject, *conditions, *block)` will trigger `add_rules`

Each class will associate with multiple rules.

> Note: cancan will handle the inheritance relationship
> e.g.: 
> ```ruby
> can :show, Animal
> can? :show, Cat # -> true
> ```

when calling `can?` it will:

```
- for every related rules
  - evaluate code blocks if has blocks
  - evaluate condition if has condition
  - return true if passing in `Class` object (no evaluation needed)
- if no matching rules -> return false
```

#### controller integration

`load_and_authorize_resource` add `before_action`: `can #method, @resource`
it will try to auto-match the action_name with method_name:

:::

## DB

- quick-reminder
  - migrate: setup table schema (and change)
  - seed: init default data

## controller

instance variable in `.erb`'s(_view_) instance refer to the controller

> Rails renders the view in context of the conroller instance

erb can also access some variable from helper function?

:::info
#### :book: How controller and rendering process works 

Gems like `devise` and `cancancan` will mixin their helper function to `ActionController`,
and then before _rails_ do the rendering it will do require everything needed from `ActionController`


hence, we cloud access to all the helper function and controller instance variables in the `view.erb` files 

> note: _rails_ will init a instance for every request call.

> note: rails use `Zeitwerk` to implement dependency injection so that ActionController would able to access all the "beans" it needed

> ==TODO==: I feel something wrong here... I needs to go more investigation
:::


## Meta programming 

### example

`devise/controllers/helpers.rb`

```ruby
def self.define_helpers(mapping) #:nodoc:
mapping = mapping.name

class_eval <<-METHODS, __FILE__, __LINE__ + 1
  def #{mapping}_signed_in?
    !!current_#{mapping}
  end

# create `customer_signed_in?` method when use `Customer` as resource
# create `user_signed_in?` method when use `User` as resource
```

> reminds me of C, the good old `#define`

# RUBY :gem: :gem: :gem:

:::info
Object:

top level methods belongs to `main` object
:::

## Cool vid

- [rubyconf dont' @ me](https://www.youtube.com/watch?v=R0oxlyVUpDw)
- [rubyconf phaser](https://www.youtube.com/watch?v=n3h2uPDZ2LY)

## something deeper 

![image](https://hackmd.io/_uploads/Bykr39Gokx.png)

![圖片](https://hackmd.io/_uploads/BJqYy7Eskg.png)

:::info
## Ruby Object

### Struct

```graphviz
digraph {
 node [shape="record"]
 g [ label="{\<Ruby Object Struct\> | flags | klass | *iv_tbl }"]
}
```

> **klass** means class. using klass to avoid conflict with the keyword `class`
> **iv** stands for instance variable

Ruby will store first few variable directly inside of Ruby Object. After the forth instance variable been added to the object, it will crate a separated table to store the all the iv.

```graphviz
digraph {
 node [shape="record"]
 rankdir=LR;
 
 g [ label="\<Ruby Object Struct\> | flags | klass | foo | bar | <iv> *iv_tbl"]
  tbl [ label=" <top> 123 | 'string'"]

 g:iv -> tbl:top
}
```


[:page_facing_up: **ruby doc**](https://ruby-hacking-guide.github.io/object.html)

![image](https://hackmd.io/_uploads/HJYb0m3jJx.png)


### caching

ruby use Object Shape to cache the instance variable index.

:::


### Fun Facts

#### No Boolean Class

```ruby
> true.class
=> TrueClass
> TrueClass.superclass
=> Object

> false.class
=> FalseClass
> FalseClass.superclass
=> Object
```

`TrueClass` and `FalseClass` are direct child of `Object`, **NO** BooleanClass.

> https://www.rubytapas.com/2019/01/08/boolean/