# :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/